Expr malforming in Julia v 0.7


Hi fellows

This is what happens

julia> Expr(:macrocall,Symbol("@m"),:(:x),:y)
:(@m y)

I was expecting
:(@m :x y)

Is this a bug?


dump shows that macro calls are actually parsed with an extra first argument which holds the current line number:

julia> dump(:(@foo x))
  head: Symbol macrocall
  args: Array{Any}((3,))
    1: Symbol @foo
    2: LineNumberNode
      line: Int64 1
      file: Symbol REPL[1]
    3: Symbol x
  typ: Any

so it looks like your :x is taking the place of that LineNumberNode. I’m not sure what the recommended practice is for constructing :macrocall expressions manually, but it looks like you can provide that argument yourself:

julia> Expr(:macrocall, Symbol("@m"), LineNumberNode(0), :x, :y)
:(#= line 0 =# @m x y)

or let Julia do the parsing for you:

julia> :(@m $(:x) $(:y))
:(#= REPL[11]:1 =# @m x y)


You need to use Meta.quot:

julia> :(@m $(Meta.quot(:x)) y)
:(@m :x y)

julia> Expr(:macrocall, Symbol("@m"), Meta.quot(:x), :y)
:(@m :x y)



This is not the issue. (the first reply already answered it)


Ah, I see I was on 0.6.x, this breaking change is confusing because it is undocumented, just barely mentioned in NEWS, the only example is misleading, since it doesn’t need to be a LineNumberNode and one con not dispatch a macro on that:

All macros receive an extra argument __source__::LineNumberNode which describes the parser location in the source file for the @ of the macro call. It can be accessed as a normal argument variable in the body of the macro. This is implemented by inserting an extra leading argument into the Expr(:macrocall, :@name, LineNumberNode(...), args...) surface syntax. (#21746)

This well formed ekpression, looks nasty :open_mouth: IMHO

julia> macro m(x, y) :($x, $y) end
@m (macro with 1 method)

julia> y = 5

julia> Expr(:macrocall, Symbol("@m"), rand(10), :(:x), :y)
:(@m :x y)

julia> eval(ans)
(:x, 5)

What I meant was that redits would still need to use quot or wrap in :(...) in order to return the desired output, also wouldn’t @__LINE__ be a better suggestion then (in this case it simply returns an int)?

We need to pass the line number node (or just anything) explicitly when constructing the expression manually yet it is inserted automatically when parsed? The metaprogramming API is getting real messy for my brain :frowning:

julia> Expr(:macrocall, Symbol("@m"), @__LINE__, :(:x), :y)
:(@m :x y)

julia> dump(ans)
  head: Symbol macrocall
  args: Array{Any}((4,))
    1: Symbol @m
    2: Int64 1
    3: QuoteNode
      value: Symbol x
    4: Symbol y
  typ: Any