Swap two variables using macros:
var a = 1 var b = 2 swap(a, b) echo a, b # Output: 2 1
Hint:
Use a
temp
variable inside the quoted code.Use backticks to plug in the identifiers.
When you're using quote do:, you're not printing code as a string - you're generating an AST (code structure).
So you don't want to convert to strings using astToStr
. Instead, inject the expression itself directly, as an AST node.
Notice the difference:
Outside ofquote do
, expr
(even with backticks) gets a NimNode
.
Inside of quote_do
, expr_a
injects the runtime value of the variable/expression.
Two different results below:
echo typeof(expr)
echo typeof(`expr`) # Same as above
quote do:
echo typeof(`expr`)
Why typeof(astToStr(...))
doesn't work:
astToStr
is a macro-time function - it only works during macro expansion, not at runtime.
Inside of quote_do
, astToStr()
turns the compile-time AST node into a string representation at compile time.
When you call typeof(astToStr(...))
, it gets evaluated after quote do is compiled.
When you're inside quote do
, the backticks surrounding an identifier (e.g. expr_a
) mean:
> "Inject the code represented by the NimNode expr_a into this spot."
But with something like echo typeof(a)
it might output int
, because:
By the time this code is actually run, you've already generated and compiled it.
At that point, you're not printing the type of the AST - you're printing the runtime type of the variable a
(which is int
).
Your insight: with macro, code (AST/NimNode) and runtime values (typed values like int, string, etc.) differ.
Nim doesn't evaluate expr_a
at macro time - it just splices it into the generated code, like a template.
After macro expansion, it's just normal Nim code (using that identifier or expression).
Only then is it typed (like int
) - hence the typeof(...)
giving int
(because now it's just typeof(a)
).
How do you see Nim's generated code during the compile stage, before the runtime stage then? A few ways in Nim to see the AST dump at compile time:
repr(...)
- This prints the raw AST of the generated code:
let body = quote do:
...
echo repr(body)
macro.dumpTree
/ dumpAst
expandMacros
import macros
macro swap_variables(expr_a: untyped, expr_b: untyped): untyped =
echo typeof(`expr_a`)
echo typeof(expr_a) # Same as above
echo "as string: ", astToStr(expr_a)
result = quote do: # Simulate the dumpTree below
let tmp = `expr_a`
`expr_a` = `expr_b`
`expr_b` = tmp
echo typeof(`expr_a`), " ", typeof(astToStr(`expr_a`))
# echo treeRepr(result)
# echo repr(result)
var a = 1
var b = 2
echo a, " ", b
# dumpTree:
# let tmp = a;
# a = b
# b = tmp
swap_variables(a, b)
echo a, " ", b