Hi. I’m having trouble defining a macro which manipulates expressions containing $
’s. It’s best illustrated by example:
Is it possible to define a macro @newrule
such that
for op ∈ (+, -)
@newrule $op(a, 0) => a
end
expands to a function call newrule(::Expr)
for op ∈ (+, -)
newrule(:($op(a, 0) => a))
end
where op
is in the local scope? So at run-time this is should be equivalent to:
newrule(:(a + 0 => a))
newrule(:(a - 0 => a))
It seems like this should certainly be possible, since the macro performs a purely syntactical transformation at parse-time—but here’s my trouble:
If we do
using MacroTools: postwalk
macro newrule(expr)
escaped = postwalk(expr) do node
if node isa Expr && node.head == :$
esc(node.args[1])
else
node
end
end
escaped
end
then the macro call @newrule $op(a, 0) => a
will return and evaluate the expression :( a + 0 => a )
, which errors since a
is undefined. But we want the macro to return an expression which evaluates to the expression, so that the run-time value is the expression :( a + 0 => a )
. If I do
...
end
QuoteNode(escaped)
end
then the macro call results in a run-time expression, but the interpolation is quoted also, so that the run-time value is :(($(Expr(:escape, :op)))(a, 0))
.
Thanks for your help!