Skip to content

Commit 14c204e

Browse files
authored
show multiple parse errors if exist (#687)
> multisyntaxerrors.jl ```julia function f(W,X,Y) s = 0 for i = 1:10 s += g(W[i]*f(X[end-1] + Y[end÷2+]), W[i+1]*f(X[end-2] + Y[end÷2]) +, W[i+2]*f(X[end-3] + Y[end÷2-3])) end return s end ``` ```julia julia> report_file("../JETLS/multisyntaxerrors.jl") [...] ═════ 2 toplevel errors found ═════ ┌ @ multisyntaxerrors.jl:4 │ # Error @ multisyntaxerrors.jl:4:42 │ for i = 1:10 │ s += g(W[i]*f(X[end-1] + Y[end÷2+]), │ # ╙ ── unexpected `]` └────────────────────── ┌ @ multisyntaxerrors.jl:5 │ # Error @ multisyntaxerrors.jl:5:47 │ s += g(W[i]*f(X[end-1] + Y[end÷2+]), │ W[i+1]*f(X[end-2] + Y[end÷2]) +, │ # ╙ ── unexpected `,` └────────────────────── ```
1 parent 2d5a3cc commit 14c204e

File tree

3 files changed

+40
-21
lines changed

3 files changed

+40
-21
lines changed

src/toplevel/virtualprocess.jl

Lines changed: 17 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -21,18 +21,19 @@ function Base.getproperty(er::ToplevelErrorReport, sym::Symbol)
2121
end
2222
end
2323

24-
struct SyntaxErrorReport <: ToplevelErrorReport
25-
err::JuliaSyntax.ParseError
24+
struct ParseErrorReport <: ToplevelErrorReport
25+
diagnostic::JuliaSyntax.Diagnostic
26+
source::JuliaSyntax.SourceFile
2627
file::String
2728
line::Int
28-
function SyntaxErrorReport(err::JuliaSyntax.ParseError)
29-
lnn = JuliaSyntax.source_location(LineNumberNode, err.source,
30-
JuliaSyntax.first_byte(first(err.diagnostics)))
31-
return new(err, String(lnn.file::Symbol), lnn.line)
29+
function ParseErrorReport(diagnostic::JuliaSyntax.Diagnostic, source::JuliaSyntax.SourceFile)
30+
line = JuliaSyntax.source_line(source, JuliaSyntax.first_byte(diagnostic))
31+
return new(diagnostic, source, source.filename::String, line)
3232
end
3333
end
3434
# don't show stacktrace for syntax errors
35-
print_report(io::IO, report::SyntaxErrorReport) = showerror(io, report.err)
35+
print_report(io::IO, report::ParseErrorReport) =
36+
JuliaSyntax.show_diagnostic(io, report.diagnostic, report.source)
3637

3738
# TODO Use JuliaLowering.jl here
3839
struct LoweringErrorReport <: ToplevelErrorReport
@@ -586,19 +587,17 @@ function _virtual_process!(res::VirtualProcessResult,
586587
end
587588

588589
s = String(s)::String
589-
parsed = try
590-
JuliaSyntax.parseall(Expr, s; filename)
591-
catch err
592-
err isa JuliaSyntax.ParseError || rethrow(err)
593-
err
594-
end
595-
596-
if parsed isa JuliaSyntax.ParseError
597-
# if there's any syntax error, try to identify all the syntax error location
598-
push!(res.toplevel_error_reports, SyntaxErrorReport(parsed))
599-
else
590+
stream = JuliaSyntax.ParseStream(s)
591+
JuliaSyntax.parse!(stream; rule=:all)
592+
if isempty(stream.diagnostics)
593+
parsed = JuliaSyntax.build_tree(Expr, stream; filename)
600594
@assert isexpr(parsed, :toplevel)
601595
_virtual_process!(res, parsed, filename, analyzer, config, context, pkg_mod_depth)
596+
else
597+
source = JuliaSyntax.SourceFile(stream; filename)
598+
for diagnostic in stream.diagnostics
599+
push!(res.toplevel_error_reports, ParseErrorReport(diagnostic, source))
600+
end
602601
end
603602

604603
with_toplevel_logger(config) do @nospecialize(io)

test/toplevel/test_virtualprocess.jl

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,27 @@ include("../setup.jl")
1313

1414
res = report_text(s)
1515
report = only(res.res.toplevel_error_reports)
16-
@test report isa SyntaxErrorReport
16+
@test report isa ParseErrorReport
1717
@test report.line == 5
1818
end
19+
20+
# report multiple syntax errors if exist
21+
let s = """
22+
function f(W,X,Y)
23+
s = 0
24+
for i = 1:10
25+
s += g(W[i]*f(X[end-1] + Y[end÷2+]),
26+
W[i+1]*f(X[end-2] + Y[end÷2]) +,
27+
W[i+2]*f(X[end-3] + Y[end÷2-3]))
28+
end
29+
return s
30+
end
31+
""" |> strip
32+
33+
res = report_text(s)
34+
@test length(res.res.toplevel_error_reports) == 2
35+
@test all(r -> r isa ParseErrorReport, res.res.toplevel_error_reports)
36+
end
1937
end
2038

2139
@testset "virtualize module context" begin

test/ui/test_print.jl

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,17 +19,19 @@ end
1919
res = report_text(src, @__FILE__)
2020
print_reports(io, res.res.toplevel_error_reports)
2121
let s = String(take!(io))
22-
@test occursin("1 toplevel error found", s)
22+
@test occursin("2 toplevel errors found", s)
2323
@test occursin(Regex("@ $(@__FILE__):\\d"), s)
2424
@test occursin("invalid identifier", s)
25+
@test occursin("Expected `end`", s)
2526
end
2627

2728
res = report_text(src, "foo")
2829
print_reports(io, res.res.toplevel_error_reports)
2930
let s = String(take!(io))
30-
@test occursin("1 toplevel error found", s)
31+
@test occursin("2 toplevel errors found", s)
3132
@test occursin(r"@ foo:\d", s)
3233
@test occursin("invalid identifier", s)
34+
@test occursin("Expected `end`", s)
3335
end
3436
end
3537
end

0 commit comments

Comments
 (0)