String interpolation
Asked Answered
L

3

5

In scala, you easily include the content of a variable inside a string, like this:

val nm = "Arrr"
println(s"my name is , $nm")

Is this possible in nim, and in that case, how?

Linalinacre answered 17/4, 2015 at 16:39 Comment(0)
B
7

The strfmt module features some experimental string interpolation:

import strfmt
let nm = "Arrr"
echo interp"my name is $nm"
Berliner answered 17/4, 2015 at 16:50 Comment(2)
Awesome, this really should be included in the standard library.Ravine
I agree with bluenote10. Thanks def-Linalinacre
I
4

Adding your own string interpolation is not particularly had, since the standard library already provides most of the necessary pieces:

import macros, parseutils, sequtils

macro i(text: string{lit}): expr =
  var nodes: seq[PNimrodNode] = @[]
  # Parse string literal into "stuff".
  for k, v in text.strVal.interpolatedFragments:
    if k == ikStr or k == ikDollar:
      nodes.add(newLit(v))
    else:
      nodes.add(parseExpr("$(" & v & ")"))
  # Fold individual nodes into a statement list.
  result = newNimNode(nnkStmtList).add(
    foldr(nodes, a.infix("&", b)))

const
  multiplier = 3
  message = i"$multiplier times 2.5 is ${multiplier * 2.5}"

echo message
# --> 3 times 2.5 is 7.5

proc blurb(a: int): string =
  result = i"param a ($a) is not a constant"

when isMainModule:
  for f in 1..10:
    echo f.blurb
Ithaca answered 17/4, 2015 at 18:32 Comment(5)
That's a good custom solution. Could it work without variables initialized on compile time?Linalinacre
One should mention that interpolatedFragments will break on something like "${a & "}" & b}, since it only counts braces. strfmt currently also suffers from this, but there should be a way to solve it by making interpolatedFragments a compileTime iterator, allowing to use parseExpr to properly parse an expression.Ravine
@Linalinacre why wouldn't it? The macro doesn't do anything to variables, it only transforms the literals to break them up into concatenations. Added some "runtime" lines to example.Ithaca
@Ravine interpolatedFragments is very simple and wasn't intended for nested braces. Nothing stops you from implementing a brace escaping mechanism inside the parsing loop and making it on par to say an SQL parser like github.com/Araq/Nim/blob/devel/lib/pure/parsesql.nim. But at this point I'd say you are abusing string interpolation for little benefit.Ithaca
@GrzegorzAdamHankiewicz: What I'm trying to say is that since the macro is expanded at compile time, the full power of the compiler is available anyways, and it would make sense to use its expression parser (if possible!) instead of parsing it manually. Imho it is not an abuse to allow any possible language statement, just like you can in Scala. The problem with the limitations is not that they are overly restrictive, but that people will not know them and they will lose time to find out why they get strange compilation errors.Ravine
Y
0

The strformat module is now considered the go-to way to do it:

import strformat
let nm = "Arrr"
echo fmt"my name is , {nm}"
Ymir answered 19/3, 2021 at 9:56 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.