Hi, and welcome to the Julia community!
I’m not sure I completely understand what you want to achieve (i.e. why this is easier than just writing
macro foo(a::Integer, b, c)
println(a + b + c)
end
directly, or just creating a function), so perhaps a more complicated example would be useful. But for this case I guess
macro macwo(header::Expr, body::Expr)
esc(quote
macro $(header.args[1])($(header.args[2:end]...))
$body
end
end)
end
works:
julia> @macwo foo(a::Integer, b, c) begin
println(a + b + c)
end
@foo (macro with 1 method)
julia> @foo(1, 2, 3)
6
The idea here is that we want to output essentially the same macro (expression) as I typed at the start of my post
julia> using MacroTools
julia> @macroexpand @macwo foo(a::Integer, b, c) begin
println(a + b + c)
end
quote
#= REPL[1]:3 =#
macro foo(a::Integer, b, c)
#= REPL[1]:3 =#
#= REPL[1]:4 =#
begin
#= REPL[5]:2 =#
println(a + b + c)
end
end
end
(Without the escaping esc we would have Main.foo, Main.Integer and Main.println.) Now, to write our macro macwo it is useful to take a look at the input we are getting:
julia> macro show_args(header, body)
dump(header)
dump(body)
end
@show_args (macro with 1 method)
julia> @show_args foo(a::Integer, b, c) begin
println(a + b + c)
end
Expr
head: Symbol call
args: Array{Any}((4,))
1: Symbol foo
2: Expr
head: Symbol ::
args: Array{Any}((2,))
1: Symbol a
2: Symbol Integer
3: Symbol b
4: Symbol c
Expr
head: Symbol block
args: Array{Any}((2,))
1: LineNumberNode
line: Int64 2
file: Symbol REPL[11]
2: Expr
head: Symbol call
args: Array{Any}((2,))
1: Symbol println
2: Expr
head: Symbol call
args: Array{Any}((4,))
1: Symbol +
2: Symbol a
3: Symbol b
4: Symbol c
In this way we can see that our method name foo can be found as header.args[1], while the argument list is present in header.args[2:end], which we splat (and interpolate) to get three arguments instead of a single length-3 array.
You could also add additional checks, depending on how robust you want your macro to be. For example, we expect header.head === :call. Currently,
@macwo foo[a::Integer, b, c] begin
println(a + b + c)
end
would behave identically, even though here header.head === :ref.
julia> macro macwo(header::Expr, body::Expr)
@assert header.head === :call
esc(quote
macro $(header.args[1])($(header.args[2:end]...))
$body
end
end)
end
@macwo (macro with 1 method)
julia> @macwo foo(a::Integer, b, c) begin
println(a + b + c)
end
@foo (macro with 1 method)
julia> @macwo foo[a::Integer, b, c] begin
println(a + b + c)
end
ERROR: LoadError: AssertionError: header.head === :call
(...)
Edit: An alternative to inspecting the expression tree, is to use MacroTools.jl’s @capture, which can be easier to read:
macro macwo(header::Expr, body::Expr)
@capture(header, f_(a__))
esc(quote
macro $f($(a...))
$body
end
end)
end
By the way, I see that the automatic translation thinks you wrote the original message in Japanese, and that it ‘translated’ “receives” to “takes”. This might be a relevant issue for Testing automatic translations to English.