I'm using the nim programming language and am doing some metaprogramming.
I want to write a DSL of some sorts that enables generating procs. For that I want to pass some nim-code into a macro (e.g. a proc definition) and eventually generate the proc from that.
Now I know you can capture nim-code inside of a macro with syntax such as this:
macro generateMapper(body: untyped): untyped =
echo body.repr
generateMapper():
proc useThisToGenerateAProc(source: A, target: B)
Which puts proc useThisToGenerateAProc(source: A, target: B)
into body, but echo'ing body.repr doesn't show anything.
How can I see what NimNodes are actually inside body or other NimNodes in general etc.?
You'll want to use these procs from std/macros
(in order of most verbose representation to least):
These will print you a representation at compile-time of the NimNode and everything it contains. AstGenRepr of those 3 is the one that is closest to the code you'd actually write inside a macro where you deal with the Nodes yourself.
An example with astGenRepr
:
macro generateMapper(body: untyped): untyped =
echo body.astGenRepr
generateMapper():
proc myMapProc(source: A, target: B): string
This prints (With comments from myself):
nnkStmtList.newTree( # The general "box" representing the entire line of code
nnkProcDef.newTree( # The general "box" representing the entire proc definition
newIdentNode("myMapProc"), # The name of the proc
newEmptyNode(),
newEmptyNode(),
nnkFormalParams.newTree( # The general "box" representing all parameters of this proc
newIdentNode("string"), # The return type, in this case string. Can be newEmptyNode() in case of no return type
nnkIdentDefs.newTree( # The general "box" representing the first parameter
newIdentNode("source"),# Name of the first parameter
newIdentNode("A"), # Type of the first parameter
newEmptyNode()
),
nnkIdentDefs.newTree( # The general "box" representing the second parameter
newIdentNode("target"),# Name of the second parameter
newIdentNode("B"), # Type of the second parameter
newEmptyNode()
)
),
newEmptyNode(),
newEmptyNode(),
newEmptyNode()
)
)
Compared to that the more compact treeRepr
:
StmtList
ProcDef
Ident "myMapProc"
Empty
Empty
FormalParams
Ident "string"
IdentDefs
Ident "source"
Ident "A"
Empty
IdentDefs
Ident "target"
Ident "B"
Empty
Empty
Empty
Empty
And the even more compact lisprepr
:
(StmtList (ProcDef (Ident "myMapProc") (Empty) (Empty) (FormalParams (Ident "string") (IdentDefs (Ident "source") (Ident "A") (Empty)) (IdentDefs (Ident "target") (Ident "B") (Empty))) (Empty) (Empty) (Empty)))