Args... in macros

I have a macro: @m1 which takes args... as argument as in:

macro m1(args...)
...
end

I wanted to create e new macro @m2 which calls @m1 with an extra parameter.
That is, I want @m2(a[1:3] = 3, key = :b) to be equivalent to @m1(a[1:3] = 3, key = :b, MyType())

The best I could do was:

macro m2(args..)
    return :(@m1($(args...), MyType()))
end

But as expected I have problem with scoping (I need to use esc…).
Unfortunately, things like:

macro m2(args..)
    return :(@m1($(esc(args)...), MyType()))
end

fail…

It look so close to the final solution, but it fails…
Any ideas?

Make a function m1_fn:

macro  m1(args...)
  return m1_fn(args...)
end
m1_fn(args...) = ...

then call that from m2.

2 Likes

Thanks!
Unfortunately, m1 belongs to another package, so that would not be a nice solution…

Ok, then Base.marcoexpand(@__MODULE__, @m1($(args...)) to get the AST and take it from there.

2 Likes

Isn’t this just an issue with your use of esc on a tuple without broadcasting?

This seems to work fine (even if @m1 is in another module):

module A
export @m1
macro m1(args...)
    quote
        println($(esc.(args)...))
    end
end
end # module A

macro m2(args...)
    quote
        @m1($(esc.(args)...), 4)
    end
end
julia> using .A

julia> @macroexpand @m1 1 2 3
quote
    #= REPL[1]:5 =#
    (Main.A.println)(1, 2, 3)
end

julia> @macroexpand @m2 1 2 3
quote
    #= REPL[2]:3 =#
    begin
        #= REPL[1]:5 =#
        (Main.A.println)(1, 2, 3, 4)
    end
end

and it seems behave correctly from an hygiene point of view:

julia> let x = 3
           @macroexpand @m2 1 2 x
       end
quote
    #= REPL[2]:3 =#
    begin
        #= REPL[1]:5 =#
        (Main.A.println)(1, 2, x, 4)
    end
end

julia> let x = 3
           @m2 1 2 x
       end
1234

It is currently nearly impossible to correctly handle hygiene with macros that call other macros. See macro hygine escape stripped late for macros calling macros · Issue #23221 · JuliaLang/julia · GitHub.

4 Likes

I was concluding something like that… Many thanks for the link!