Re: How to call a macro from a template with a constructed identifier argument?
> Interesting, I guess this works because quote doesn't touch the passed in > backticked identifier and this is then returned intact to the template? Yes. The different meanings of backtick-quoting ("make an identifier" in the template, "evaluate in local scope and put here" in the quote block) can be pretty confusing: import macros macro defthing(name: untyped): untyped = # used this instead of parseStmt result = quote do: let `name` = 1000 echo "generated code: " & result.repr template calldefthing(name: untyped): untyped = # defthing name # argument is an identifier defthing `name Extra` # argument is not an identifier, I'd like to evaluate the `name Extra` before the macro is called calldefthing x echo $xExtra
Re: How to call a macro from a template with a constructed identifier argument?
In a quote do block, quoted identifier are interpolated with the normal Nim syntax. You actually have to use the normal Nim syntax, which wasn't really evident in my own example because echo exist in both. Basically quote do is equivalent to template + getAST: import macros macro defthing(): untyped = # macro level let interpol = 123 # 2. Extra stuff in macro v2" result = newStmtList() result.add quote do: # "Runtime level" echo "yet more thing to do in macro with normal Nim syntax" let a = 456 + `interpol` echo a proc foo(x: int): bool = x mod 2 == 0 echo foo(a) echo foo(`interpol`) defthing()
Re: How to call a macro from a template with a constructed identifier argument?
Thanks for the suggestions. @mratsim I had no idea you could put a template inside a macro and get its evaluated AST. Cool! This will be very useful. @Lando Interesting, I guess this works because quote doesn't touch the passed in backticked identifier and this is then returned intact to the template? Maybe I should treat identifiers-like NimNodes as more of a black box in the future to allow this sort of thing.
Re: How to call a macro from a template with a constructed identifier argument?
@mratsim: The code needs two changes to work: import macros macro defthing(name: untyped): untyped = # used this instead of parseStmt result = quote do: let `name` = 1000 # Now things get really weird: added a dummy argument and things work as intended.. template calldefthing(name, t: untyped) = defthing `name Extra` calldefthing(x, y) echo $xExtra
Re: How to call a macro from a template with a constructed identifier argument?
Normally to do identifier construction of variable you need to use `{.inject.}` However untyped macro will capture everything and you will have to deal with the inject pragma in your macro. Instead forget about the template and do identifier construction directly in it. import macros static: echo "Target macro: " dumpASTgen(): let xExtra = 1000 static: echo "#" macro defthing(name: untyped): untyped = echo name.treerepr result = newStmtList() result.add nnkLetSection.newTree( nnkIdentDefs.newTree( newIdentNode($name & "Extra"), newEmptyNode(), newLit(1000) ) ) defthing awesome echo "xExtra is: " & $awesomeExtra Now building on your example, if you want to match normal Nim syntax and macro calls. Here are 3 ways to do that from within macros and templates: import macros macro defthing(name: untyped): untyped = echo name.treerepr result = newStmtList() result.add nnkLetSection.newTree( nnkIdentDefs.newTree( newIdentNode($name & "Extra"), newEmptyNode(), newLit(1000) ) ) # 1. Extra stuff in macro v1 template extraThing(): untyped = echo "wow extra from template with normal Nim syntax" result.add getAST(extraThing()) # 2. Extra stuff in macro v2" result.add quote do: echo "yet more thing to do in macro with normal Nim syntax" template yetyetAnother(name: untyped): untyped = # 3. Extra stuff in template defthing(name) echo xExtra * 1337 yetyetAnother(x)
Re: How to call a macro from a template with a constructed identifier argument?
Yes, that compiles, but the macro produces the code let x = 1000 instead of the code let xExtra = 1000 I'm trying to get the identifier to be constructed before passing it into the macro, but I'm not sure if that's possible.
Re: How to call a macro from a template with a constructed identifier argument?
This works for me on 0.18 and devel import macros import strutils macro defthing(name: untyped): untyped = return parseStmt("let $1 = 1000".format(ident($name))) template calldefthing(name: untyped): untyped = # defthing name # argument is an identifier defthing `name Extra` # argument is not an identifier, I'd like to evaluate the `name Extra` before the macro is called calldefthing x
How to call a macro from a template with a constructed identifier argument?
I have a macro that creates a type and associated functions, and I'm calling that from a template. I want to use identifier construction to append a suffix to the template parameter, but the whole backticked AST (instead of the constructed identifier) gets passed in to the macro. Is there some way to generate an identifier before the macro is evaluated? I've included a simplified example below. macro defthing(name: untyped): untyped = return parseStmt("let $1 = 1000".format($name.ident)) template calldefthing(name: untyped): untyped {.dirty.} = defthing name # argument is an identifier defthing `name Extra` # argument is not an identifier, I'd like to evaluate the `name Extra` before the macro is called calldefthing x