Reputation: 15336
How can I make macro that works when used as pragma to also work if used as plain call?
Please note that it has to be untyped
as for some reason I can't use typed
macro.
import macros
proc fn_signature(fn: NimNode): string =
let fn_impl = case fn.kind
of nnk_ident: fn.get_impl
of nnk_proc_def: fn
else: return "invalid usage"
fn_impl.tree_repr()
macro fn_signature_macro(fn: untyped) =
echo fn.fn_signature
proc a: string {.fn_signature_macro.} = ""
fn_signature_macro a
Error:
stack trace: (most recent call last)
/usercode/in.nim(12, 10) fn_signature_macro
/usercode/in.nim(5, 22) fn_signature
/usercode/in.nim(15, 20) template/generic instantiation of `fn_signature_macro` from here
/usercode/in.nim(5, 22) Error: node is not a symbol
Upvotes: 0
Views: 428
Reputation: 1598
Since you asked for how to do this with an untyped
macro, and making no claims of whether this is good design or not:
import macros
{.experimental: "dynamicBindSym".}
proc fn_signature(fn: NimNode): string =
let fn_impl = case fn.kind
of nnk_ident: fn.bindSym.getImpl()
of nnk_proc_def: fn
else: return "invalid usage"
fn_impl.tree_repr()
macro fn_signature_macro(fn: untyped) =
echo fn.fn_signature
proc a: string {.fn_signature_macro.}
proc b:int
fn_signature_macro b
since the second call to fn_signature_macro
is just the un-looked-up identifier b
, we need to look it up with bindSym
. Look at the docs for more information, bindSym allows you to specify whether the resulting symbol is open or closed, and here I've had to use an experimental feature for this to work.
Also, it's not necessary for the procs to have bodies for the macro to rewrite them
Upvotes: 1
Reputation: 495
It works fine, your error is calling getImpl
on a nnkIdent
. You cannot look at the implementation of a identifier since it's not looked up. You may want something like the following.
import macros
proc fn_signature(fn: NimNode): string =
let fn_impl = case fn.kind
of nnk_ident: fn.get_impl
of nnk_proc_def: fn
else: return "invalid usage"
fn_impl.tree_repr()
macro fn_signature_macro(fn: typed): untyped =
case fn.kind:
of nnkProcDef:
result = fn
else: discard
echo fn.fn_signature
proc a: string {.fn_signature_macro.} = ""
fn_signature_macro a
Upvotes: 1