Skip to content

Commit

Permalink
Only show the first parse error (#344)
Browse files Browse the repository at this point in the history
Parser recovery commonly results in several errors which refer to much
the same location in the broken source file and are not useful to the
user.

Currently the most useful error is the first one, so this PR trims down
error printing to only show that one.
  • Loading branch information
c42f committed Aug 13, 2023
1 parent 94bad1a commit df84e02
Show file tree
Hide file tree
Showing 2 changed files with 44 additions and 10 deletions.
8 changes: 7 additions & 1 deletion src/parser_api.jl
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,13 @@ end

function Base.showerror(io::IO, err::ParseError)
println(io, "ParseError:")
show_diagnostics(io, err.diagnostics, err.source)
# Only show the first parse error for now - later errors are often
# misleading due to the way recovery works
i = findfirst(is_error, err.diagnostics)
if isnothing(i)
i = lastindex(err.diagnostics)
end
show_diagnostics(io, err.diagnostics[1:i], err.source)
end

"""
Expand Down
46 changes: 37 additions & 9 deletions test/parser_api.jl
Original file line number Diff line number Diff line change
Expand Up @@ -117,28 +117,56 @@ end

@testset "ParseError printing" begin
try
JuliaSyntax.parsestmt(JuliaSyntax.SyntaxNode, "a -- b -- c", filename="somefile.jl")
parsestmt(SyntaxNode, "a -- b -- c", filename="somefile.jl")
@assert false "error should be thrown"
catch exc
@test exc isa JuliaSyntax.ParseError
@test sprint(showerror, exc) == """
ParseError:
# Error @ somefile.jl:1:3
a -- b -- c
# └┘ ── invalid operator
# Error @ somefile.jl:1:8
a -- b -- c
# └┘ ── invalid operator"""
# └┘ ── invalid operator"""
@test occursin("Stacktrace:\n", sprint(showerror, exc, catch_backtrace()))
file_url = JuliaSyntax._file_url("somefile.jl")
@test sprint(showerror, exc, context=:color=>true) == """
ParseError:
\e[90m# Error @ \e[0;0m\e]8;;$file_url#1:3\e\\\e[90msomefile.jl:1:3\e[0;0m\e]8;;\e\\
a \e[48;2;120;70;70m--\e[0;0m b -- c
\e[90m# └┘ ── \e[0;0m\e[91minvalid operator\e[0;0m
\e[90m# Error @ \e[0;0m\e]8;;$file_url#1:8\e\\\e[90msomefile.jl:1:8\e[0;0m\e]8;;\e\\
a -- b \e[48;2;120;70;70m--\e[0;0m c
\e[90m# └┘ ── \e[0;0m\e[91minvalid operator\e[0;0m"""
\e[90m# └┘ ── \e[0;0m\e[91minvalid operator\e[0;0m"""
end

try
# Test that warnings are printed first followed by only the first error
parsestmt(SyntaxNode, """
@(a)
x -- y
z -- y""", filename="somefile.jl")
@assert false "error should be thrown"
catch exc
@test exc isa JuliaSyntax.ParseError
@test sprint(showerror, exc) == """
ParseError:
# Warning @ somefile.jl:1:2
@(a)
#└─┘ ── parenthesizing macro names is unnecessary
# Error @ somefile.jl:2:1
@(a)
x
╙ ── unexpected text after parsing statement"""
end

try
# Test that initial warnings are always printed
parsestmt(SyntaxNode, """
@(a)""", filename="somefile.jl")
@assert false "error should be thrown"
catch exc
@test exc isa JuliaSyntax.ParseError
@test sprint(showerror, exc) == """
ParseError:
# Warning @ somefile.jl:1:2
@(a)
#└─┘ ── parenthesizing macro names is unnecessary"""
end
end

Expand Down

0 comments on commit df84e02

Please sign in to comment.