Reputation: 400
I would have thought this would work:
macro meta_meta(x,y)
:(macro $x(arg) :($($y) + $arg) end)
end
The expected behavior is that calling @meta_meta(f,2)
should be equivalent to macro f(arg) :(2 + $arg) end
In other words:
julia> @meta_meta(f,2)
julia> @f(3)
5
Instead I get:
ERROR: syntax: invalid macro definition
I'm at a bit of a loss for how to proceed. I see that the expression tree for this macro is different from the one I get if I manually generate @f and examine its expression tree, and I've tried several iterations of @meta_meta, but I cannot figure out how to change my definition to get it working.
Upvotes: 5
Views: 731
Reputation: 12051
Macro hygiene is a little finnicky when dealing with a quote inside a quote. Often I find the only way is to refuse macro hygiene entirely, and use gensym
liberally to simulate it.
However in your reduced example, it's straightforward to just turn the inner quote into an Expr
:
julia> macro meta_meta(x, y)
:(macro $(esc(x))(arg) Expr(:call, :+, $(esc(y)), esc(arg)) end)
end
@meta_meta (macro with 1 method)
julia> @meta_meta f 2
@f (macro with 1 method)
julia> @f 3
5
If things get more complicated, the approach I mentioned above involves turning off macro hygiene with esc
. This means that we have to do the hygiene ourself, hence the gensym
:
julia> macro meta_meta(x, y)
arg = gensym()
esc(:(macro $x($arg) :($$y + $$arg) end))
end
@meta_meta (macro with 1 method)
julia> @meta_meta f 2
@f (macro with 1 method)
julia> @f 3
5
Upvotes: 6