Hey, I'm trying to implement a macro to reduce some cumbersome boilerplate code. However, I can't seem to get newProc to work. Here's the stripped down macro code:
import std/macros
macro mkCaster(caster: proc) =
expectKind(caster, nnkLambda)
echo "lambda: " & caster.repr()
result = newProc(newIdentNode("newCaster"), params=toSeq(caster.params), body=caster.body)
echo "cosntr: " & result.repr()
return result
mkCaster(proc (v: bool): int = return int(v)) # expression 'result = int(v)' has no type (or is ambiguous)
mkCaster(proc (v: bool): int = int(v)) # 'result' is of type <int> which cannot be captured as it would violate memory safety...consider using a <ref int> which can be captured.
assert newCaster(true) == 1
As you can see I'm basically attempting to pull in the lambda and after doing some manipulations (omitted here) I'm trying to generate a new procedure with a name. The problem is the compiler doesn't seem to like it. I've even tried replicating the AST 1:1 based on what the generated code would be for the newly generated function but the one of the same two issues appear that I cannot seem to get rid of.
The representation that's printed to terminal
lambda: proc (v: bool): int = return int(v)
cosntr: proc newCaster(v: bool): int =
return int(v)
and
lambda: proc (v: bool): int = result = int(v)
cosntr: proc newCaster(v: bool): int =
result = int(v)
respectively. So the generated code is correct in both cases I just can't get it passed the compiler. Help would be appreciated.Replacing proc with untyped will fix it.
macro mkCaster(caster: untyped)
It seems that all the symbols were bound to somewhere before passed into the macro, as a side effect of using typed parameter. The compile thus thought you were capturing outter variables.For ratchet on what that does:
It tells nim to not really try to make sense of whatever code gets put into the mkCaster macro. So you are allowed to have entirely invalid stuff in there, you just need to create NimNodes that contains valid code as the macro output (which you do).
By using proc (or by extension: typed), you force nim to do some level of syntax parsing on the input and if your input violates that it throws errors.
It makes your example to work. But you'll also lose the ability of getting the type information from the input, by using an untyped parameter.
Another way is to take a typed parameter and make a recursive copy of it, replacing every node of the kind of nnkSym with that of nnkIdent. But I don't know if this will work.