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?
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.
1 Like
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
Thanks! It looks like rmlines
removes only one level of LineNumberNode
s; 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.
1 Like
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
Okay, I didnt test that, I will fix it later today since that’s a bug for me.
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
1 Like
I realize this is solved but for sport I figured I’ll write my own solution of linefilter!
also using recursion, only tested in 1.7.1, maybe someone stumbling across this thread years later will find it useful:
Code:
macro unquote(expr::Expr)
function aux!(args::Vector{Any}) ::Nothing
to_delete = Vector{Integer}()
for (i, x) in enumerate(args)
if x isa LineNumberNode
push!(to_delete, i)
elseif x isa Expr
aux!(x.args)
end
end
n_deleted = 0;
for i in to_delete
deleteat!(args, i - n_deleted)
n_deleted += 1
end
end
aux!(expr.args)
return Expr(expr.head, :($(expr.args...)))
end
Usage:
julia> quoted = quote module m end; struct s end; i = 1; end
quote
#= REPL[15]:1 =#
module m
#= REPL[15]:1 =#
#= REPL[15]:1 =#
end
#= REPL[15]:1 =#
struct s
#= REPL[15]:1 =#
end
#= REPL[15]:1 =#
i = 1
end
julia> unquoted = @unquote quote module m end; struct s end; i = 1; end
quote
module m
end
struct s
end
i = 1
end
It is part of jluna and can be used freely