gcv
January 6, 2022, 5:28am
1
I’m having trouble with macros taking multiple parameters. Specifically, I’m writing a macro which needs to take @__DIR__
and an expression as its arguments. Here’s a simplified example:
macro tm1(dir, action)
:(begin
println("tm1 dir: ", $dir)
$action
end)
end
The following invocation fails:
@tm1 @__DIR__ begin
3 + 3
end
The error is:
ERROR: LoadError: LoadError: MethodError: no method matching var"@tm1"(::LineNumberNode, ::Module, ::Expr)
Closest candidates are:
var"@tm1"(::LineNumberNode, ::Module, ::Any, ::Any) at /path/to/file.jl
But if I invoke the macro with an explicit string instead of @__DIR__
, it works:
@tm1 "/tmp" begin
3 + 3
end
All right, maybe macros don’t like taking another macro as an argument?
macro tm2(dir)
:(begin
println("tm2 dir: ", $dir)
end)
end
@tm2 @__DIR__
Which works fine! So a macro with one parameter can take another macro as an argument, but with two (or more?) it breaks? WTF?
Julia version 1.6.2.
jzr
January 6, 2022, 5:31am
2
@__DIR__
needs to be in parentheses.
1 Like
rdeits
January 6, 2022, 2:14pm
3
The problem is that when you write:
@a @b x
the parser treats that as calling macro @b
with argument x
, then calling macro @a
with just one argument.
You can see that by using dump
to look at the syntax tree:
julia> dump(:(@a @b x))
Expr
head: Symbol macrocall
args: Array{Any}((3,))
1: Symbol @a
2: LineNumberNode
line: Int64 1
file: Symbol REPL[5]
3: Expr
head: Symbol macrocall
args: Array{Any}((3,))
1: Symbol @b
2: LineNumberNode
line: Int64 1
file: Symbol REPL[5]
3: Symbol x
or just by constructing the expression and letting julia add some parentheses to disambiguate:
julia> :(@a @b x)
:(#= REPL[6]:1 =# @a #= REPL[6]:1 =# @b(x))
And you can fix this by adding the parentheses that you actually want instead:
julia> @tm1(@__DIR__(), begin
3 + 3
end)
tm1 dir: /home/user
6
In this case, it’s also sufficient to just add parens on the call to @__DIR__
to avoid it trying to grab the whole begin
block as an argument:
julia> @tm1 @__DIR__() begin
3 + 3
end
tm1 dir: /home/user
6
2 Likes