Removing LineNumberNodes when displaying expressions with macros


#1

I’m trying to define a function to filter LineNumberNodes from an expression to pretty-print it without annotations:

filterLNN(x) = deepcopy(x)

function filterLNN(e::Expr)
    Expr(e.head, filterLNN.(filter(x->!isa(x, LineNumberNode), e.args))...)
end
julia> quote
         let acc = 1
           for i in 1:3
             acc += i
           end
           acc
         end
       end |> filterLNN

quote
    let acc = 1
        for i = 1:3
            acc += i
        end
        acc
    end
end

So far, so good, but my problem is that macro calls in the expression aren’t displayed anymore:

julia> quote
         let acc = 1
           @simd for i in 1:3
             acc += i
           end
           acc
         end
       end |> filterLNN

quote
    let acc = 1
        @simd
        acc
    end
end

I can display macro calls again if I leave at least their “accompanying” LineNumberNode in the expression:

function filterLNN(e::Expr)
    if e.head == :macrocall
        Expr(e.head, e.args[1:2]..., filterLNN.(filter(x->!isa(x, LineNumberNode), e.args[3:end]))...)
    else
        Expr(e.head, filterLNN.(filter(x->!isa(x, LineNumberNode), e.args))...)
    end
end
julia> quote
         let acc = 1
           @simd for i in 1:3
             acc += i
           end
           acc
         end
       end |> filterLNN

quote
    let acc = 1
        #= REPL[26]:3 =# @simd for i = 1:3
                acc += i
            end
        acc
    end
end

Is this expected behavior? Or should I look for a bug in the implementation of display for macro calls?


#2

There is MacroTools.rmlines which doesn’t actually seem to work on your quote. My hack was here simply to regex the string version… but surely there is a nicer way.


#3

You can also use my tool SyntaxTree.linefilter! from SyntaxTree.jl for that

julia> using SyntaxTree

julia> quote
           x = 1
           y = x+2
       end
quote
    #= REPL[2]:2 =#
    x = 1
    #= REPL[2]:3 =#
    y = x + 2
end

julia> linefilter!(ans)
quote
    x = 1
    y = x + 2
end

The linefilter! method is faster than MacroTools because it is recursively mutating


#4

Thanks! It looks like rmlines removes only one level of LineNumberNodes; striplines is recursive. Both these seem to handle macro calls like in my implementation, but at least it’s an improvement to use an already written implementation instead of having to write mine.

Thanks. I’ll consider doing that too if I don’t find a nicer way.


#5

Thanks, but this function does not seem to handle macro calls in any special way, and therefore produces the same output as my first attempt above:

julia> quote
           let acc = 1
               @simd for i in 1:3
                   acc += i
               end
               acc
           end
       end |> SyntaxTree.linefilter

quote
    let acc = 1
        @simd
        acc
    end
end

#6

Okay, I didnt test that, I will fix it later today since that’s a bug for me.


#7

It is fixed in the master branch now, it can handle it correctly

julia> quote
           let acc = 1
               @simd for i in 1:3
                   acc += i
               end
               acc
           end
       end |> SyntaxTree.linefilter!

quote
    let acc = 1
        @simd for i = 1:3
                acc += i
            end
        acc
    end
end

The problem is that :macrocall expressions now require a LineNumberNode or something to fill its place, so the solution is to simply put nothing in its place

This bug fix will be tagged as an updated release today