Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Show leaf Kinds when printing syntax trees #489

Merged
merged 1 commit into from
Aug 9, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 28 additions & 19 deletions src/syntax_tree.jl
Original file line number Diff line number Diff line change
Expand Up @@ -139,61 +139,70 @@ function leaf_string(ex)
end

function _show_syntax_node(io, current_filename, node::AbstractSyntaxNode,
indent, show_byte_offsets)
fname = filename(node)
indent, show_location, show_kind)
line, col = source_location(node)
posstr = "$(lpad(line, 4)):$(rpad(col,3))│"
if show_byte_offsets
posstr *= "$(lpad(first_byte(node),6)):$(rpad(last_byte(node),6))│"
if show_location
fname = filename(node)
# Add filename if it's changed from the previous node
if fname != current_filename[]
println(io, indent, " -file- │ ", repr(fname))
current_filename[] = fname
end
posstr = "$(lpad(line, 4)):$(rpad(col,3))│$(lpad(first_byte(node),6)):$(rpad(last_byte(node),6))│"
else
posstr = ""
end
val = node.val
nodestr = is_leaf(node) ? leaf_string(node) : "[$(untokenize(head(node)))]"
treestr = string(indent, nodestr)
# Add filename if it's changed from the previous node
if fname != current_filename[]
#println(io, "# ", fname)
treestr = string(rpad(treestr, 40), "│$fname")
current_filename[] = fname
if show_kind && is_leaf(node)
treestr = rpad(treestr, 40)*" :: "*string(kind(node))
end
println(io, posstr, treestr)
if !is_leaf(node)
new_indent = indent*" "
for n in children(node)
_show_syntax_node(io, current_filename, n, new_indent, show_byte_offsets)
_show_syntax_node(io, current_filename, n, new_indent, show_location, show_kind)
end
end
end

function _show_syntax_node_sexpr(io, node::AbstractSyntaxNode)
function _show_syntax_node_sexpr(io, node::AbstractSyntaxNode, show_kind)
if is_leaf(node)
if is_error(node)
print(io, "(", untokenize(head(node)), ")")
else
print(io, leaf_string(node))
if show_kind
print(io, "::", kind(node))
end
end
else
print(io, "(", untokenize(head(node)))
first = true
for n in children(node)
print(io, ' ')
_show_syntax_node_sexpr(io, n)
_show_syntax_node_sexpr(io, n, show_kind)
first = false
end
print(io, ')')
end
end

function Base.show(io::IO, ::MIME"text/plain", node::AbstractSyntaxNode; show_byte_offsets=false)
println(io, "line:col│$(show_byte_offsets ? " byte_range │" : "") tree │ file_name")
_show_syntax_node(io, Ref(""), node, "", show_byte_offsets)
function Base.show(io::IO, ::MIME"text/plain", node::AbstractSyntaxNode; show_location=false, show_kind=true)
println(io, "SyntaxNode:")
if show_location
println(io, "line:col│ byte_range │ tree")
end
_show_syntax_node(io, Ref(""), node, "", show_location, show_kind)
end

function Base.show(io::IO, ::MIME"text/x.sexpression", node::AbstractSyntaxNode)
_show_syntax_node_sexpr(io, node)
function Base.show(io::IO, ::MIME"text/x.sexpression", node::AbstractSyntaxNode; show_kind=false)
_show_syntax_node_sexpr(io, node, show_kind)
end

function Base.show(io::IO, node::AbstractSyntaxNode)
_show_syntax_node_sexpr(io, node)
_show_syntax_node_sexpr(io, node, false)
end

function Base.push!(node::SN, child::SN) where SN<:AbstractSyntaxNode
Expand Down
64 changes: 39 additions & 25 deletions test/syntax_tree.jl
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,9 @@
# as `lastindex(t, 2)` isn't well defined

@test sprint(show, t) == "(call-i (call-i a * b) + c)"
str = sprint(show, MIME("text/plain"), t)
# These tests are deliberately quite relaxed to avoid being too specific about display style
@test occursin("line:col", str)
@test occursin("call-i", str)
@test sprint(io->show(io, MIME("text/x.sexpression"), t, show_kind=true)) ==
"(call-i (call-i a::Identifier *::* b::Identifier) +::+ c::Identifier)"

@test sprint(highlight, child(t, 1, 3)) == "a*b + c\n# ╙"
@test sprint(highlight, t.source, t.raw, 1, 3) == "a*b + c\n# ╙"

Expand Down Expand Up @@ -69,30 +68,45 @@ end
@testset "SyntaxNode pretty printing" begin
t = parsestmt(SyntaxNode, "f(a*b,\n c)", filename="foo.jl")
@test sprint(show, MIME("text/plain"), t) == """
line:col│ tree │ file_name
1:1 │[call] │foo.jl
1:1 │ f
1:3 │ [call-i]
1:3 │ a
1:4 │ *
1:5 │ b
2:3 │ c
SyntaxNode:
[call]
f :: Identifier
[call-i]
a :: Identifier
* :: *
b :: Identifier
c :: Identifier
"""
@test sprint(io->show(io, MIME("text/plain"), t, show_byte_offsets=true)) == """
line:col│ byte_range │ tree │ file_name
1:1 │ 1:11 │[call] │foo.jl
1:1 │ 1:1 │ f

@test sprint(io->show(io, MIME("text/plain"), t, show_location=true)) == """
SyntaxNode:
line:col│ byte_range │ tree
-file- │ "foo.jl"
1:1 │ 1:11 │[call]
1:1 │ 1:1 │ f :: Identifier
1:3 │ 3:5 │ [call-i]
1:3 │ 3:3 │ a
1:4 │ 4:4 │ *
1:5 │ 5:5 │ b
2:3 │ 10:10 │ c
1:3 │ 3:3 │ a :: Identifier
1:4 │ 4:4 │ * :: *
1:5 │ 5:5 │ b :: Identifier
2:3 │ 10:10 │ c :: Identifier
"""

t,_ = parsestmt(SyntaxNode, "begin a end\nbegin b end", 13)
@test sprint(show, MIME("text/plain"), t) == """
line:col│ tree │ file_name
1:1 │[block]
1:7 │ b
@test sprint(io->show(io, MIME("text/plain"), t, show_kind=false)) == """
SyntaxNode:
[call]
f
[call-i]
a
*
b
c
"""

t,_ = parsestmt(SyntaxNode, "begin a end\nbegin b end", 13, first_line=100)
@test sprint(io->show(io, MIME("text/plain"), t, show_location=true)) == """
SyntaxNode:
line:col│ byte_range │ tree
100:1 │ 13:23 │[block]
100:7 │ 19:19 │ b :: Identifier
"""
end
Loading