From e7669ab1c12c8fbb3a9ddc32a3108b3bf62ce99a Mon Sep 17 00:00:00 2001 From: Claire Foster Date: Sun, 13 Aug 2023 07:26:35 +1000 Subject: [PATCH] Only show the first parse error 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. --- src/parser_api.jl | 8 +++++++- test/parser_api.jl | 46 +++++++++++++++++++++++++++++++++++++--------- 2 files changed, 44 insertions(+), 10 deletions(-) diff --git a/src/parser_api.jl b/src/parser_api.jl index 6eca864d..51548a99 100644 --- a/src/parser_api.jl +++ b/src/parser_api.jl @@ -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 """ diff --git a/test/parser_api.jl b/test/parser_api.jl index 4ceb8b58..9e05dee1 100644 --- a/test/parser_api.jl +++ b/test/parser_api.jl @@ -117,7 +117,7 @@ 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 @@ -125,20 +125,48 @@ end 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