I have macro (fillVar in the example) that creates code that fills variable with value calculated from NimNode. And another macro (printVar in the example) that needs the variable to get filled.
This example prints v, but I need test to be printed and I can't modify fillVar macro. Can it be done?
import macros
macro fillVar(id: expr, v: expr): stmt =
let vlit = ($v).newStrLitNode
result = quote do:
`id` = `vlit`
macro printVar(v: expr): stmt =
var x: string
fillVar x, v
let xlit = newStrLitNode(x)
result = quote do:
echo `xlit`
printVar test
I've modified the code you wrote to print what you want, but it would help more to understand what you are trying to accomplish with this code.
Edit: I just realized you said you can't modify fillVar. Why can't you modify it?
import macros
macro fillVar(id: expr, v: expr): stmt =
let vlit = v
result = quote do:
`id` = `vlit`
macro printVar(v: expr): stmt =
var x: string
fillVar x, $v.toStrLit
let xlit = newStrLitNode(x)
result = quote do:
echo `xlit`
printVar test
Ok, here is more realistic example. I can't pass the original AST to the macro genSignature called from jclass macro. I know, that I can generate code that will call it. But I need signature as a string value inside jclass macro
import macros
proc jniSig(t: typedesc[string]): string = "Ljava/lang/String;"
# This macro generates JNI signatures
macro genSignature(id, n: expr): stmt =
result = quote do:
`id` = `n`.jniSig
# I can get the signature in ordinary code
var sig: string
genSignature sig, string
# I can use it in unit tests
assert sig == "Ljava/lang/String;"
# And this macro must use ``genSignature``
macro jclass(head, body: expr): stmt =
for procDef in body:
var sig: string
# *** I can't use genSignature in the macro code like that
genSignature sig, procDef
So it seems like the problem is that you're trying to use macros like actual code. However, macros can only generate ASTs. I've expanded upon your example to hopefully do what you want based on what you've said. I've included references to some tools like getAst and treeRepr that I used while creating my unit testing library, einheit. If you have questions, or something isn't clear in what I wrote, please let me know :)
import macros
proc jniSig(t: typedesc[string]): string = "Ljava/lang/String;"
# Another method just to test
proc jniSig(t: typedesc[int]): string = "Ljava/lang/Integer;"
# This macro generates JNI signatures
macro genSignature(id, n: expr): stmt =
result = quote do:
`id` = `n`.jniSig
# I can get the signature in ordinary code
var sig: string
genSignature sig, string
# I can use it in unit tests
assert sig == "Ljava/lang/String;"
# And this macro must use ``genSignature``
macro jclass(head, body: expr): stmt =
# Since macros can only work with AST, you'll
# need to build a statement list to hold the
# calls to genSignature
var stmtList = newStmtList()
# This template is so that we can use
# runtime code.
template genSig(tdesc) =
var sig: string
genSignature(sig, tdesc)
echo sig
# Do more code in here
for procDef in body:
echo procDef.treeRepr
# prints:
#
# ProcDef
# Ident !"doThings" -> 0
# Empty -> 1
# Empty -> 2
# FormalParams -> 3
# Ident !"string" < - We want this, I assume, which is at index [3][0]
# Empty
# Empty
# Empty
let returnType = procDef[3][0]
let ast = getAst(genSig(returnType))
stmtList.add(ast)
return stmtList
jclass MyClass:
proc doThings(): string
proc doThings2(): int
# prints:
#
# Ljava/lang/String;
# Ljava/lang/Integer;