I am trying to use nnkDotExpr in a macro and am getting an error. Specifically I am trying to write a macro which will write a procedure that returns a specific field. I have tried three approaches all of which seem to fail and I am not sure why.
This is the code I have.
import macros
type
Test_Type = object of RootObj
Name_HIDDEN: string
macro Name_MacroA*(vType: untyped): untyped =
var tName = nnkDotExpr(ident("self"), ident("Name_HIDDEN"))
quote do:
proc Name*(self: var `vType`): string =
return `tName`
macro Name_MacroB*(vType: untyped): untyped =
var tName = newNimNode(nnkDotExpr)
tName.add(ident("self"))
tName.add(ident("Name_HIDDEN"))
quote do:
proc Name*(self: var `vType`): string =
return `tName`
macro Name_MacroC*(vType: untyped): untyped =
var tName = nnkDotExpr.newTree(ident("self"), ident("Name_HIDDEN"))
quote do:
proc Name*(self: var `vType`): string =
return `tName`
Name_MacroB(Test_Type)
var tTest: Test_Type
tTest.Name_HIDDEN = "Hello"
echo tTest.Name
When I use Name_MacroA I am get the error:
Error: attempting to call routine: 'nnkDotExpr'
found 'nnkDotExpr' [enumField declared in /usr/local/Cellar/nim/2.0.0_1/nim/lib/core/macros.nim(45, 5)]
Name_MacroA is an attempt to match the code from the nnkDotExpr reference in Nim Macros.
When I use Name_MacroB or Name_MacroC I get the error:
template/generic instantiation of `Name_MacroB` from here test4.nim(17, 20) Error: undeclared identifier: 'self'
candidates (edit distance, scope distance); see '--spellSuggest':
(2, 4): 'del'
(2, 4): 'ref'
(2, 4): 'send'
Name_MacroB is an attempt to match the code from Nim Macros
Name_MacroC is an attempt to match code from Nim Macros
The first issue is that you are trying to call nnkDotExpr
when its an enum. For NimNodeKind's like nnkDotExpr
you need to use newTree.
The second issue is that quote do
is generating a unique symbol for the self
parameter so you need to make it use your own ident like so
# Create your own ident
let selfIdent = ident"self"
# Can use genSym if you think there might be conflicts
# let selfIdent = genSym(nskParam, "self")
tName.add(selfIdent)
tName.add(ident("Name_HIDDEN"))
quote do:
# Now it uses your symbol here instead of making a new one
proc Name*(`selfIdent`: var `vType`): string =
return `tName`
Also there is newDotExpr which makes creating dot expressions simplier