I'm trying to expand a template and write the resulting code into a nim file. I've tried this approach, inspired by expandMacros:
import macros
template test(msg: string, body: untyped): typed =
body
proc testproc(s: string) =
echo s & ": " & $rows
testproc(msg)
macro wrapper(body: typed): untyped =
template inner(x: untyped): untyped = x
let
ast = getAst(inner(body))
code = $toStrLit(ast)
writeFile("result.nim", code)
static:
wrapper():
test("string"):
let rows = 9
This sort of works: the file result.nim contains recognizable nim code, but it is not properly indented and has weird features:
let rows = 9
proc testproc(s150024: string) =
echo [&(s150024, ": ", $ rows)]
testproc("string")
Needless to say it does not compile.
I've looked into the code of c2nim and it takes a different approach, importing compiler modules and using renderModule. I've tried that too but I can't make it work. It seems that renderModule expects a PNode and getAst returns a NimNode, but I don't understand the details.
ast = getAst(inner(body))
code = $toStrLit(ast)
is replaceable by:
code = body.repr
Other than that, it seems to be a bug as body.repr.parseStmt should be an identity and here it's not (parse error due to invalid indentation).
Thanks for the hint, the macro becomes simpler and better:
macro expandToFile(filepath: string, body: typed): untyped =
result = body # optional
writeFile($filepath, repr(body))
Maybe a similar mod could be applied to the source of expandMacros but I'm not sure of all the implications.
Trying again with a devel compiler instead of 0.17.2 gets rid of the indentation bug:
let rows = 9
proc testproc(s143025: string) =
echo [&(s143025, ": ", $rows)]
testproc("string")
Name mangling is not very convenient but I guess that it can't be avoided. There remains the broken echo syntax, should I file a bug against this?I think so. I tried it with both typed and untyped macro arguments. What's funny, it works as expected for untyped ones:
macro sth(code: untyped): untyped =
echo code.repr
sth:
let s = 5
echo s
But not for typed:
macro sth(code: typed): untyped =
echo code.repr
sth:
let s = 5
echo s
I think there is a more serious bug involved here...