How do you factor out some duplicated code that lies inside a macro? I've tried to put it in a proc that takes and returns a PNimrodNode, but it failed with: Error: cannot generate code for 'newNimNode'.
proc castToInt (e: PNimrodNode): PNimrodNode =
let c = newNimNode (nnkCast)
c.add (ident ("int"))
c.add (e)
result = c
Thanks!template castToInt(e: expr): expr = int(e)
template forever(body: stmt): stmt = while true: body
Thank you Araq, it did the trick.
zahary, I wasn't aware of this template thingy. Very handy. It worked for the forever statement but not for the castToInt expression where it failed with:
Error: conversion from PNimrodNode to int is invalid
stinger, the castToInt template will work as a replacement for a similar macro.
If you just want to produce that piece of AST and use it within a more complicated macro, then you have several options all coming from the macros module:
macro foo(e: expr): stmt =
var n = getAst(castToInt(e)) # `n` here will be PNimrodNode
...
macro foo(e: expr): stmt =
var n = quote(int(`e`))
...
template castToInt(e: expr): expr = cast[int](e)
As a type conversion is not the same as a type cast.
I've tried that too but no success either. Here's a small sample, I must do something wrong.
import macros
type
TMyEnum = enum
A, B
TMyEnumSet = set[TMyEnum]
proc castToInt (e: PNimrodNode): PNimrodNode {.compileTime.} =
let c = newNimNode (nnkCast)
c.add (ident ("int"))
c.add (e)
result = c
template castToInt2 (e: expr): expr =
cast[int](e)
macro foo (e: expr): stmt =
let s = newNimNode (nnkStmtList)
s.add (newCall (!"echo", castToInt2 (e)))
result = s
foo ({A, B})
I think my psychic powers were greater than Araq's and I figured a little bit better what you are trying to do :)
In this particular case, you have to use getAst to obtain the AST tree that will be produced by the template:
s.add (newCall (!"echo", getAst(castToInt2(e))))
If you don't use getAst here, Nimrod will try to expand the template when the macro is compiled (as opposed to when it's executed). The code will effectively become:
s.add (newCall (!"echo", cast[int](e)))
and it should be obvious why this is not what you want.