the macroexpand in the code below lead to an Error. UndefVarError: i not defined
Ther error is clear, but how can I solve it? Or how can I put the “i” from the for loop in the right environment?
macro dlamdba(body...)
quote
#println(length($(body)))
(msg) ->
begin
for i = 1:2
println((i))
if msg == $(body[i].args[1])
println(msg)
$(esc(body[i].args[2]))()
end
end
end
end
end
@macroexpand @dlamdba [:inc,() -> count = count +1] [:dec,() -> count = count -1]
i only exists in the quote as a symbol, it’s not a variable until after the macro returns. Executing body[i].args[1] before interpolation into the quote doesn’t work because there’s no i variable.
I think the fundamental issue is you’re trying to write a for loop that changes subexpressions per iteration. That’s not something Julia code can do, so macros can’t transform code into that. You only have so many arguments for @dlambda, so you could just execute them all in sequence, like a fully unrolled loop. You can’t really write that in a quote, but you can mutate the Expr that the quote instantiates. Write out the unrolled loop and examine the Expr structure with dump to get an idea of how to mutate towards that.
While @Benny’s answer is of course true, I think a potentially more helpful answer is that you need to do the loop over i inside the macro, rather than leaving it as quoted code.
i.e. something like
macro dlamdba(body...)
f_body = Expr(:block)
for i ∈ 1:2
ex = quote
println($i)
if msg == $(esc(body[i].args[1]))
println(msg)
$(esc(body[i].args[2]))()
end
end
push!(f_body.args, ex)
end
:(msg -> $f_body)
end