In your if blocks, when you write
$(esc(body[1]))[2] = $(esc(body[1]))[2] + 1
this is macroexpanded to
([:inc count])[2] = ([:inc, count])[2] + 1
which is a setindex! expression on an array, not a lexical rebinding.
I would instead write this as
macro counter_macro(body...)
quote
println("macro")
(msg) ->
begin
if $(body[1].args[1]) == msg
println("test inc")
$(esc(body[1].args[2])) = $(esc(body[1].args[2])) + 1
end
if $(body[2].args[1]) == msg
println("test dec")
$(esc(body[2].args[2])) = $(esc(body[1].args[2])) - 1
end
$(esc(body[2].args[2]))
end
end
end
(Well, actually I also wouldn’t use a variable argument list since you clearly only actually support two arguments, and have a pre-defined expectation for what sort of structure you want those arguments to have, but I guess that’s another topic)
With the above changes, I get
julia> c = let count = 0
@counter_macro [:inc count] [:dec count]
end
macro
#10 (generic function with 1 method)
julia> c(:inc)
test inc
1
julia> c(:inc)
test inc
2
julia> c(:dec)
test dec
1
julia> c(:dec)
test dec
0