Skip to content

Commit 92eac55

Browse files
authored
Merge pull request #225 from JuliaLang/c42f/emit-diagnostic-cleanup
Clean up emit_diagnostic stream position handling
2 parents a78aa6e + 9c26a47 commit 92eac55

File tree

10 files changed

+119
-87
lines changed

10 files changed

+119
-87
lines changed

src/diagnostics.jl

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ end
3939

4040
first_byte(d::Diagnostic) = d.first_byte
4141
last_byte(d::Diagnostic) = d.last_byte
42-
is_error(d::Diagnostic) = d.level == :error
42+
is_error(d::Diagnostic) = d.level === :error
4343
Base.range(d::Diagnostic) = first_byte(d):last_byte(d)
4444

4545
# Make relative path into a file URL
@@ -54,9 +54,9 @@ function _file_url(filename)
5454
end
5555

5656
function show_diagnostic(io::IO, diagnostic::Diagnostic, source::SourceFile)
57-
color,prefix = diagnostic.level == :error ? (:light_red, "Error") :
58-
diagnostic.level == :warning ? (:light_yellow, "Warning") :
59-
diagnostic.level == :note ? (:light_blue, "Note") :
57+
color,prefix = diagnostic.level === :error ? (:light_red, "Error") :
58+
diagnostic.level === :warning ? (:light_yellow, "Warning") :
59+
diagnostic.level === :note ? (:light_blue, "Note") :
6060
(:normal, "Info")
6161
line, col = source_location(source, first_byte(diagnostic))
6262
linecol = "$line:$col"
@@ -92,8 +92,8 @@ function show_diagnostics(io::IO, diagnostics::AbstractVector{Diagnostic}, text:
9292
end
9393

9494
function emit_diagnostic(diagnostics::AbstractVector{Diagnostic},
95-
fbyte::Integer, lbyte::Integer; kws...)
96-
push!(diagnostics, Diagnostic(fbyte, lbyte; kws...))
95+
byterange::AbstractUnitRange; kws...)
96+
push!(diagnostics, Diagnostic(first(byterange), last(byterange); kws...))
9797
end
9898

9999
function any_error(diagnostics::AbstractVector{Diagnostic})

src/expr.jl

Lines changed: 14 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ function _to_expr(node::SyntaxNode; iteration_spec=false, need_linenodes=true,
7676
headsym = !isnothing(headstr) ? Symbol(headstr) :
7777
error("Can't untokenize head of kind $(nodekind)")
7878
end
79-
if headsym == :string || headsym == :cmdstring
79+
if headsym === :string || headsym === :cmdstring
8080
# Julia string literals may be interspersed with trivia in two situations:
8181
# 1. Triple quoted string indentation is trivia
8282
# 2. An \ before newline removes the newline and any following indentation
@@ -100,7 +100,7 @@ function _to_expr(node::SyntaxNode; iteration_spec=false, need_linenodes=true,
100100
end
101101
else
102102
e = _to_expr(node_args[i])
103-
if e isa String && headsym == :string
103+
if e isa String && headsym === :string
104104
# Wrap interpolated literal strings in (string) so we can
105105
# distinguish them from the surrounding text (issue #38501)
106106
# Ie, "$("str")" vs "str"
@@ -124,22 +124,22 @@ function _to_expr(node::SyntaxNode; iteration_spec=false, need_linenodes=true,
124124
end
125125

126126
# Convert children
127-
insert_linenums = (headsym == :block || headsym == :toplevel) && need_linenodes
127+
insert_linenums = (headsym === :block || headsym === :toplevel) && need_linenodes
128128
args = Vector{Any}(undef, length(node_args)*(insert_linenums ? 2 : 1))
129-
if headsym == :for && length(node_args) == 2
129+
if headsym === :for && length(node_args) == 2
130130
# No line numbers in for loop iteration spec
131131
args[1] = _to_expr(node_args[1], iteration_spec=true, need_linenodes=false)
132132
args[2] = _to_expr(node_args[2])
133-
elseif headsym == :let && length(node_args) == 2
133+
elseif headsym === :let && length(node_args) == 2
134134
# No line numbers in let statement binding list
135135
args[1] = _to_expr(node_args[1], need_linenodes=false)
136136
args[2] = _to_expr(node_args[2])
137137
else
138138
eq_to_kw_in_call =
139-
((headsym == :call || headsym == :dotcall) && is_prefix_call(node)) ||
140-
headsym == :ref
141-
eq_to_kw_all = headsym == :parameters && !map_kw_in_params
142-
in_vcbr = headsym == :vect || headsym == :curly || headsym == :braces || headsym == :ref
139+
((headsym === :call || headsym === :dotcall) && is_prefix_call(node)) ||
140+
headsym === :ref
141+
eq_to_kw_all = headsym === :parameters && !map_kw_in_params
142+
in_vcbr = headsym === :vect || headsym === :curly || headsym === :braces || headsym === :ref
143143
if insert_linenums && isempty(node_args)
144144
push!(args, source_location(LineNumberNode, node.source, node.position))
145145
else
@@ -150,8 +150,7 @@ function _to_expr(node::SyntaxNode; iteration_spec=false, need_linenodes=true,
150150
end
151151
eq_to_kw = eq_to_kw_in_call && i > 1 || eq_to_kw_all
152152
args[insert_linenums ? 2*i : i] =
153-
_to_expr(n, eq_to_kw=eq_to_kw,
154-
map_kw_in_params=in_vcbr)
153+
_to_expr(n, eq_to_kw=eq_to_kw, map_kw_in_params=in_vcbr)
155154
end
156155
if nodekind == K"block" && has_flags(node, PARENS_FLAG)
157156
popfirst!(args)
@@ -204,7 +203,7 @@ function _to_expr(node::SyntaxNode; iteration_spec=false, need_linenodes=true,
204203
end
205204
elseif headsym === :where
206205
reorder_parameters!(args, 2)
207-
elseif headsym == :parens
206+
elseif headsym === :parens
208207
# parens are used for grouping and don't appear in the Expr AST
209208
return only(args)
210209
elseif headsym in (:try, :try_finally_catch)
@@ -252,15 +251,15 @@ function _to_expr(node::SyntaxNode; iteration_spec=false, need_linenodes=true,
252251
pushfirst!(args, numeric_flags(flags(node)))
253252
elseif headsym === :typed_ncat
254253
insert!(args, 2, numeric_flags(flags(node)))
255-
# elseif headsym == :string && length(args) == 1 && version <= (1,5)
254+
# elseif headsym === :string && length(args) == 1 && version <= (1,5)
256255
# Strip string from interpolations in 1.5 and lower to preserve
257256
# "hi$("ho")" ==> (string "hi" "ho")
258257
elseif headsym === :(=) && !is_decorated(node)
259258
if is_eventually_call(args[1]) && !iteration_spec && !Meta.isexpr(args[2], :block)
260259
# Add block for short form function locations
261260
args[2] = Expr(:block, loc, args[2])
262261
end
263-
elseif headsym == :elseif
262+
elseif headsym === :elseif
264263
# Block for conditional's source location
265264
args[1] = Expr(:block, loc, args[1])
266265
elseif headsym === :(->)
@@ -290,7 +289,7 @@ function _to_expr(node::SyntaxNode; iteration_spec=false, need_linenodes=true,
290289
elseif headsym === :module
291290
pushfirst!(args, !has_flags(node, BARE_MODULE_FLAG))
292291
pushfirst!(args[3].args, loc)
293-
elseif headsym == :inert || (headsym == :quote && length(args) == 1 &&
292+
elseif headsym === :inert || (headsym === :quote && length(args) == 1 &&
294293
!(a1 = only(args); a1 isa Expr || a1 isa QuoteNode ||
295294
a1 isa Bool # <- compat hack, Julia 1.4+
296295
))

src/hooks.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -288,7 +288,7 @@ function _fl_parse_hook(code, filename, lineno, offset, options)
288288
ex = Expr(:toplevel, ex)
289289
end
290290
return ex, sizeof(code)
291-
elseif options === :statement || options == :atom
291+
elseif options === :statement || options === :atom
292292
ex, pos = Meta.parse(code, offset+1, greedy=options==:statement, raise=false)
293293
return ex, pos-1
294294
else

src/kinds.jl

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1133,6 +1133,10 @@ function is_radical_op(x)
11331133
kind(x) in (K"", K"", K"")
11341134
end
11351135

1136+
"""
1137+
Return true if `x` has whitespace or comment kind
1138+
"""
11361139
function is_whitespace(x)
1137-
kind(x) in (K"Whitespace", K"NewlineWs")
1140+
k = kind(x)
1141+
return k == K"Whitespace" || k == K"NewlineWs" || k == K"Comment"
11381142
end

src/literal_parsing.jl

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -261,7 +261,7 @@ function unescape_julia_string(io::IO, str::AbstractString,
261261
u = m == 4 ? 'u' : 'U'
262262
msg = (m == 2) ? "invalid hex escape sequence" :
263263
"invalid unicode escape sequence"
264-
emit_diagnostic(diagnostics, escstart, i, error=msg)
264+
emit_diagnostic(diagnostics, escstart:i, error=msg)
265265
had_error = true
266266
else
267267
if m == 2 # \x escape sequence
@@ -279,7 +279,7 @@ function unescape_julia_string(io::IO, str::AbstractString,
279279
i += 1
280280
end
281281
if n > 255
282-
emit_diagnostic(diagnostics, escstart, i,
282+
emit_diagnostic(diagnostics, escstart:i,
283283
error="invalid octal escape sequence")
284284
had_error = true
285285
else
@@ -303,7 +303,7 @@ function unescape_julia_string(io::IO, str::AbstractString,
303303
c == '`' ? '`' :
304304
nothing
305305
if isnothing(u)
306-
emit_diagnostic(diagnostics, escstart, i,
306+
emit_diagnostic(diagnostics, escstart:i,
307307
error="invalid escape sequence")
308308
had_error = true
309309
else

src/parse_stream.jl

Lines changed: 31 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -359,7 +359,7 @@ function _buffer_lookahead_tokens(lexer, lookahead)
359359
while true
360360
raw = Tokenize.next_token(lexer)
361361
k = kind(raw)
362-
was_whitespace = k in (K"Whitespace", K"Comment", K"NewlineWs")
362+
was_whitespace = is_whitespace(k)
363363
had_whitespace |= was_whitespace
364364
f = EMPTY_FLAGS
365365
raw.dotop && (f |= DOTOP_FLAG)
@@ -622,7 +622,7 @@ function _bump_until_n(stream::ParseStream, n::Integer, flags, remap_kind=K"None
622622
break
623623
end
624624
f = flags | (@__MODULE__).flags(tok)
625-
is_trivia = k (K"Whitespace", K"Comment", K"NewlineWs")
625+
is_trivia = is_whitespace(k)
626626
is_trivia && (f |= TRIVIA_FLAG)
627627
outk = (is_trivia || remap_kind == K"None") ? k : remap_kind
628628
h = SyntaxHead(outk, f)
@@ -686,7 +686,7 @@ function bump_invisible(stream::ParseStream, kind, flags=EMPTY_FLAGS;
686686
h = SyntaxHead(kind, flags)
687687
push!(stream.tokens, SyntaxToken(h, (@__MODULE__).kind(h), false, b))
688688
if !isnothing(error)
689-
emit_diagnostic(stream, b, b-1, error=error)
689+
emit_diagnostic(stream, b:b-1, error=error)
690690
end
691691
stream.peek_count = 0
692692
return position(stream)
@@ -797,12 +797,6 @@ function Base.position(stream::ParseStream)
797797
ParseStreamPosition(lastindex(stream.tokens), lastindex(stream.ranges))
798798
end
799799

800-
# Get position of next item to be emitted into the output stream
801-
# TODO: Figure out how to remove this? It's only used with emit_diagnostic
802-
function next_position(stream::ParseStream)
803-
ParseStreamPosition(lastindex(stream.tokens)+1, lastindex(stream.ranges)+1)
804-
end
805-
806800
"""
807801
emit(stream, mark, kind, flags = EMPTY_FLAGS; error=nothing)
808802
@@ -819,14 +813,14 @@ function emit(stream::ParseStream, mark::ParseStreamPosition, kind::Kind,
819813
# nested.
820814
fbyte = token_first_byte(stream, first_token)
821815
lbyte = token_last_byte(stream, lastindex(stream.tokens))
822-
emit_diagnostic(stream, fbyte, lbyte, error=error)
816+
emit_diagnostic(stream, fbyte:lbyte, error=error)
823817
end
824818
push!(stream.ranges, range)
825819
return position(stream)
826820
end
827821

828-
function emit_diagnostic(stream::ParseStream, fbyte::Integer, lbyte::Integer; kws...)
829-
emit_diagnostic(stream.diagnostics, fbyte, lbyte; kws...)
822+
function emit_diagnostic(stream::ParseStream, byterange::AbstractUnitRange; kws...)
823+
emit_diagnostic(stream.diagnostics, byterange; kws...)
830824
return nothing
831825
end
832826

@@ -849,20 +843,30 @@ function emit_diagnostic(stream::ParseStream; whitespace=false, kws...)
849843
end
850844
fbyte = lookahead_token_first_byte(stream, begin_tok_i)
851845
lbyte = lookahead_token_last_byte(stream, end_tok_i)
852-
emit_diagnostic(stream, fbyte, lbyte; kws...)
846+
emit_diagnostic(stream, fbyte:lbyte; kws...)
853847
return nothing
854848
end
855849

856-
function emit_diagnostic(stream::ParseStream, mark::ParseStreamPosition; kws...)
857-
emit_diagnostic(stream, token_first_byte(stream, mark.token_index),
858-
_next_byte(stream) - 1; kws...)
850+
function emit_diagnostic(stream::ParseStream, mark::ParseStreamPosition; trim_whitespace=true, kws...)
851+
i = mark.token_index
852+
j = lastindex(stream.tokens)
853+
if trim_whitespace
854+
while i < j && is_whitespace(stream.tokens[j])
855+
j -= 1
856+
end
857+
while i+1 < j && is_whitespace(stream.tokens[i+1])
858+
i += 1
859+
end
860+
end
861+
byterange = stream.tokens[i].next_byte:stream.tokens[j].next_byte-1
862+
emit_diagnostic(stream, byterange; kws...)
859863
end
860864

861865
function emit_diagnostic(stream::ParseStream, mark::ParseStreamPosition,
862866
end_mark::ParseStreamPosition; kws...)
863-
fbyte = token_first_byte(stream, mark.token_index)
864-
lbyte = token_first_byte(stream, end_mark.token_index) - 1
865-
emit_diagnostic(stream, fbyte, lbyte; kws...)
867+
fbyte = stream.tokens[mark.token_index].next_byte
868+
lbyte = stream.tokens[end_mark.token_index].next_byte-1
869+
emit_diagnostic(stream, fbyte:lbyte; kws...)
866870
end
867871

868872
#-------------------------------------------------------------------------------
@@ -890,19 +894,19 @@ function validate_tokens(stream::ParseStream)
890894
# jl_strtod_c can return "underflow" even for valid cases such
891895
# as `5e-324` where the source is an exact representation of
892896
# `x`. So only warn when underflowing to zero.
893-
underflow0 = code == :underflow && x == 0
897+
underflow0 = code === :underflow && x == 0
894898
else
895899
x, code = parse_float_literal(Float32, text, fbyte, nbyte)
896-
underflow0 = code == :underflow && x == 0
900+
underflow0 = code === :underflow && x == 0
897901
end
898-
if code == :ok
902+
if code === :ok
899903
# pass
900-
elseif code == :overflow
901-
emit_diagnostic(stream, fbyte, lbyte,
904+
elseif code === :overflow
905+
emit_diagnostic(stream, fbyte:lbyte,
902906
error="overflow in floating point literal")
903907
error_kind = K"ErrorNumericOverflow"
904908
elseif underflow0
905-
emit_diagnostic(stream, fbyte, lbyte,
909+
emit_diagnostic(stream, fbyte:lbyte,
906910
warning="underflow to zero in floating point literal")
907911
end
908912
elseif k == K"Char"
@@ -917,7 +921,7 @@ function validate_tokens(stream::ParseStream)
917921
read(charbuf, Char)
918922
if !eof(charbuf)
919923
error_kind = K"ErrorOverLongCharacter"
920-
emit_diagnostic(stream, fbyte, lbyte,
924+
emit_diagnostic(stream, fbyte:lbyte,
921925
error="character literal contains multiple characters")
922926
end
923927
end
@@ -929,7 +933,7 @@ function validate_tokens(stream::ParseStream)
929933
end
930934
elseif is_error(k) && k != K"error"
931935
# Emit messages for non-generic token errors
932-
emit_diagnostic(stream, fbyte, lbyte,
936+
emit_diagnostic(stream, fbyte:lbyte,
933937
error=_token_error_descriptions[k])
934938
end
935939
if error_kind != K"None"

0 commit comments

Comments
 (0)