I am working on a macro and I am having an issue with it (I think it must be something silly).
My macro:
macro init*(args: varargs[typed]) =
var body = nnkStmtList.newTree()
var comp: ModelInstanceRef
var names:seq[string]
for arg in args:
names &= arg.strVal
var id = newIdentNode(arg.strVal)
# int case
if arg.getType.typeKind == ntyInt:
let argVal = arg.getImpl[2].intVal.int
body.add quote do:
`id` = `argVal`
comp.integerAddr.add( addr(`id`) )
result = quote do:
proc setStartValues*(comp: ModelInstanceRef) =
`body`
The way in which I use it:
var counter*:int = 1
init(counter)
The generated code looks like:
var counter: int = 1
proc setStartValues(comp`gensym3: ModelInstanceRef) {.exportc, dynlib.} =
counter = 1
add(comp.integerAddr, addr(counter))
but I want it to generate:
var counter: int = 1
proc setStartValues(comp: ModelInstanceRef) {.exportc, dynlib.} = # <<< look at: comp
counter = 1
add(comp.integerAddr, addr(counter))
I tried as well:
macro init*(args: varargs[typed]) =
var body = nnkStmtList.newTree()
var comp: ModelInstanceRef
var names:seq[string]
for arg in args:
names &= arg.strVal
var id = newIdentNode(arg.strVal)
# int case
if arg.getType.typeKind == ntyInt:
let argVal = arg.getImpl[2].intVal.int
body.add quote do:
`id` = `argVal`
comp.integerAddr.add( addr(`id`) )
var id = newIdentNode("comp")
result = quote do:
proc setStartValues*(`id`: ModelInstanceRef) =
`body`
This seems to create the proper code, but it complains about: Error: illegal capture 'comp' because 'setStartValues' has the calling convention: <cdecl>
Any idea?
Try using std/genasts.
import std/genasts # add this import
macro init*(args: varargs[typed]) =
var body = nnkStmtList.newTree()
var comp: ModelInstanceRef
var names:seq[string]
for arg in args:
names &= arg.strVal
var id = newIdentNode(arg.strVal)
# int case
if arg.getType.typeKind == ntyInt:
let argVal = arg.getImpl[2].intVal.int
body.add quote do:
`id` = `argVal`
comp.integerAddr.add( addr(`id`) )
# adjust the result like so
let compIdent = ident("comp")
result = genAst(compIdnt, body):
proc setStartValues*(compIdent: ModelInstanceRef) =
body
The following seems to work as intended:
macro init*(args: varargs[typed]) =
result = nnkStmtList.newTree()
# 1. Function name
var newFunc = nnkProcDef.newTree()
newFunc.add( nnkPostfix.newTree(
newIdentNode("*"),
newIdentNode("setStartValues")
),
newEmptyNode(),
newEmptyNode()
)
# 2. Function arguments
var formalParams = nnkFormalParams.newTree()
formalParams.add newEmptyNode()
formalParams.add nnkIdentDefs.newTree(
newIdentNode("comp"),
newIdentNode("ModelInstanceRef"),
newEmptyNode()
)
newFunc.add( formalParams, newEmptyNode(), newEmptyNode() )
# 3. Function body
var funcBody = nnkStmtList.newTree()
#funcBody.add quote do:
# echo "hola"
#newFunc.add funcBody
funcBody.add newEmptyNode()
funcBody.add newEmptyNode()
var body = nnkStmtList.newTree()
for arg in args:
#names &= arg.strVal
let id = newIdentNode(arg.strVal)
# 3.1 Assignment
body.add nnkAsgn.newTree(
#newIdentNode("counter"),
id,
#newLit(1)
newLit(argVal)
)
if arg.getType.typeKind == ntyInt:
let argVal = arg.getImpl[2].intVal.int
# 3.2 Add adress
body.add nnkCall.newTree(
nnkDotExpr.newTree(
nnkDotExpr.newTree(
newIdentNode("comp"),
newIdentNode("integerAddr")
),
newIdentNode("add")
),
nnkCall.newTree(
newIdentNode("addr"),
id
#newIdentNode("counter")
)
)
newFunc.add body
result.add newFunc
Try using {.inject.}.
result = quote do:
proc setStartValues*(comp {.inject.}: ModelInstanceRef) =
`body`