Skip to content

Commit

Permalink
show multiple parse errors if exist (#687)
Browse files Browse the repository at this point in the history
> 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 `,`
└──────────────────────
```
  • Loading branch information
aviatesk authored Feb 4, 2025
1 parent 2d5a3cc commit 14c204e
Show file tree
Hide file tree
Showing 3 changed files with 40 additions and 21 deletions.
35 changes: 17 additions & 18 deletions src/toplevel/virtualprocess.jl
Original file line number Diff line number Diff line change
Expand Up @@ -21,18 +21,19 @@ function Base.getproperty(er::ToplevelErrorReport, sym::Symbol)
end
end

struct SyntaxErrorReport <: ToplevelErrorReport
err::JuliaSyntax.ParseError
struct ParseErrorReport <: ToplevelErrorReport
diagnostic::JuliaSyntax.Diagnostic
source::JuliaSyntax.SourceFile
file::String
line::Int
function SyntaxErrorReport(err::JuliaSyntax.ParseError)
lnn = JuliaSyntax.source_location(LineNumberNode, err.source,
JuliaSyntax.first_byte(first(err.diagnostics)))
return new(err, String(lnn.file::Symbol), lnn.line)
function ParseErrorReport(diagnostic::JuliaSyntax.Diagnostic, source::JuliaSyntax.SourceFile)
line = JuliaSyntax.source_line(source, JuliaSyntax.first_byte(diagnostic))
return new(diagnostic, source, source.filename::String, line)
end
end
# don't show stacktrace for syntax errors
print_report(io::IO, report::SyntaxErrorReport) = showerror(io, report.err)
print_report(io::IO, report::ParseErrorReport) =
JuliaSyntax.show_diagnostic(io, report.diagnostic, report.source)

# TODO Use JuliaLowering.jl here
struct LoweringErrorReport <: ToplevelErrorReport
Expand Down Expand Up @@ -586,19 +587,17 @@ function _virtual_process!(res::VirtualProcessResult,
end

s = String(s)::String
parsed = try
JuliaSyntax.parseall(Expr, s; filename)
catch err
err isa JuliaSyntax.ParseError || rethrow(err)
err
end

if parsed isa JuliaSyntax.ParseError
# if there's any syntax error, try to identify all the syntax error location
push!(res.toplevel_error_reports, SyntaxErrorReport(parsed))
else
stream = JuliaSyntax.ParseStream(s)
JuliaSyntax.parse!(stream; rule=:all)
if isempty(stream.diagnostics)
parsed = JuliaSyntax.build_tree(Expr, stream; filename)
@assert isexpr(parsed, :toplevel)
_virtual_process!(res, parsed, filename, analyzer, config, context, pkg_mod_depth)
else
source = JuliaSyntax.SourceFile(stream; filename)
for diagnostic in stream.diagnostics
push!(res.toplevel_error_reports, ParseErrorReport(diagnostic, source))
end
end

with_toplevel_logger(config) do @nospecialize(io)
Expand Down
20 changes: 19 additions & 1 deletion test/toplevel/test_virtualprocess.jl
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,27 @@ include("../setup.jl")

res = report_text(s)
report = only(res.res.toplevel_error_reports)
@test report isa SyntaxErrorReport
@test report isa ParseErrorReport
@test report.line == 5
end

# report multiple syntax errors if exist
let s = """
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
""" |> strip

res = report_text(s)
@test length(res.res.toplevel_error_reports) == 2
@test all(r -> r isa ParseErrorReport, res.res.toplevel_error_reports)
end
end

@testset "virtualize module context" begin
Expand Down
6 changes: 4 additions & 2 deletions test/ui/test_print.jl
Original file line number Diff line number Diff line change
Expand Up @@ -19,17 +19,19 @@ end
res = report_text(src, @__FILE__)
print_reports(io, res.res.toplevel_error_reports)
let s = String(take!(io))
@test occursin("1 toplevel error found", s)
@test occursin("2 toplevel errors found", s)
@test occursin(Regex("@ $(@__FILE__):\\d"), s)
@test occursin("invalid identifier", s)
@test occursin("Expected `end`", s)
end

res = report_text(src, "foo")
print_reports(io, res.res.toplevel_error_reports)
let s = String(take!(io))
@test occursin("1 toplevel error found", s)
@test occursin("2 toplevel errors found", s)
@test occursin(r"@ foo:\d", s)
@test occursin("invalid identifier", s)
@test occursin("Expected `end`", s)
end
end
end
Expand Down

0 comments on commit 14c204e

Please sign in to comment.