Skip to content

Commit a6f2d15

Browse files
authored
Improve error message for missing closing tokens (#397)
When a missing closing token like `)`, `]` or `}` is encountered we want the "Expected `)`" error to point to a location one past the last valid token, not to the trailing error tokens. For example from #349 here's a poor error message from the existing code: ERROR: ParseError: # Error @ REPL[53]:15:5 ylims!(p, (0, last(ylims(p))) xlabel!(p, "Contig length cutoff (kbp)") # └─────────────────────────────────────┘ ── Expected `)` After this change, the error location instead points to the end of the last valid line: ERROR: ParseError: # Error @ REPL[53]:15:5 ylims!(p, (0, last(ylims(p))) # └── Expected `)`
1 parent acb609d commit a6f2d15

File tree

3 files changed

+16
-11
lines changed

3 files changed

+16
-11
lines changed

src/parser.jl

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -141,15 +141,20 @@ end
141141
#
142142
# Crude recovery heuristic: bump any tokens which aren't block or bracket
143143
# closing tokens.
144-
function bump_closing_token(ps, closing_kind)
144+
function bump_closing_token(ps, closing_kind, alternative_closer_hint=nothing)
145145
# todo: Refactor with recover() ?
146-
bump_trivia(ps)
147146
if peek(ps) == closing_kind
147+
bump_trivia(ps)
148148
bump(ps, TRIVIA_FLAG)
149149
return
150150
end
151+
errmsg = "Expected `$(untokenize(closing_kind))`"
152+
if !isnothing(alternative_closer_hint)
153+
errmsg *= alternative_closer_hint
154+
end
151155
# We didn't find the closing token. Read ahead in the stream
152156
mark = position(ps)
157+
emit_diagnostic(ps, mark, mark, error=errmsg)
153158
while true
154159
k = peek(ps)
155160
if is_closing_token(ps, k) && !(k in KSet", ;")
@@ -158,8 +163,7 @@ function bump_closing_token(ps, closing_kind)
158163
bump(ps)
159164
end
160165
# mark as trivia => ignore in AST.
161-
emit(ps, mark, K"error", TRIVIA_FLAG,
162-
error="Expected `$(untokenize(closing_kind))`")
166+
emit(ps, mark, K"error", TRIVIA_FLAG)
163167
if peek(ps) == closing_kind
164168
bump(ps, TRIVIA_FLAG)
165169
end
@@ -3101,7 +3105,6 @@ function parse_brackets(after_parse::Function,
31013105
had_splat = false
31023106
param_start = nothing
31033107
while true
3104-
bump_trivia(ps)
31053108
k = peek(ps)
31063109
if k == closing_kind
31073110
break
@@ -3127,7 +3130,6 @@ function parse_brackets(after_parse::Function,
31273130
end
31283131
t = peek_token(ps, skip_newlines=true)
31293132
k = kind(t)
3130-
bump_trivia(ps)
31313133
if k == K","
31323134
had_commas = true
31333135
bump(ps, TRIVIA_FLAG)
@@ -3156,7 +3158,7 @@ function parse_brackets(after_parse::Function,
31563158
end
31573159
end
31583160
release_positions(ps.stream, params_positions)
3159-
bump_closing_token(ps, closing_kind)
3161+
bump_closing_token(ps, closing_kind, " or `,`")
31603162
return opts
31613163
end
31623164

test/diagnostics.jl

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -64,14 +64,17 @@ end
6464
Diagnostic(16, 16, :error, "missing condition in `elseif`")
6565

6666
@test diagnostic("f(x::V) where {V) = x", allow_multiple=true) == [
67-
Diagnostic(17, 16, :error, "Expected `}`")
67+
Diagnostic(17, 16, :error, "Expected `}` or `,`")
6868
Diagnostic(17, 21, :error, "extra tokens after end of expression")
6969
]
7070
@test diagnostic("[1)", allow_multiple=true) == [
71-
Diagnostic(3, 2, :error, "Expected `]`")
71+
Diagnostic(3, 2, :error, "Expected `]` or `,`")
7272
Diagnostic(3, 3, :error, "extra tokens after end of expression")
7373
]
74-
74+
@test diagnostic("f(x, y #=hi=#\ng(z)") == Diagnostic(7, 6, :error, "Expected `)` or `,`")
75+
@test diagnostic("(x, y \nz") == Diagnostic(6, 5, :error, "Expected `)` or `,`")
76+
@test diagnostic("function f(x, y \nz end") == Diagnostic(16, 15, :error, "Expected `)` or `,`")
77+
7578
@test diagnostic("sin. (1)") ==
7679
Diagnostic(5, 5, :error, "whitespace is not allowed here")
7780
@test diagnostic("x [i]") ==

test/hooks.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ end
5252
@test err.source.first_line == 1
5353
@test err.diagnostics[1].first_byte == 6
5454
@test err.diagnostics[1].last_byte == 5
55-
@test err.diagnostics[1].message == "Expected `}`"
55+
@test err.diagnostics[1].message == "Expected `}` or `,`"
5656
end
5757

5858
@testset "toplevel errors" begin

0 commit comments

Comments
 (0)