Skip to content

Commit 63e30a1

Browse files
committed
Be more defensive in the parser translator lexer
Generally I have been good about safely accessing the tokens but failed to properly guard against no tokens in places where it could theoretically happen through invalid syntax. I added a test case for one occurance, other changes are theoretical only.
1 parent fd7a417 commit 63e30a1

2 files changed

Lines changed: 30 additions & 14 deletions

File tree

lib/prism/translation/parser/lexer.rb

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -275,7 +275,7 @@ def to_a
275275
when :tCOMMENT
276276
if token.type == :EMBDOC_BEGIN
277277

278-
while !((next_token = lexed[index][0]) && next_token.type == :EMBDOC_END) && (index < length - 1)
278+
while !((next_token, _ = lexed[index]) && next_token.type == :EMBDOC_END) && (index < length - 1)
279279
value += next_token.value
280280
index += 1
281281
end
@@ -287,8 +287,8 @@ def to_a
287287
is_at_eol = value.chomp!.nil?
288288
location = range(token.location.start_offset, token.location.end_offset + (is_at_eol ? 0 : -1))
289289

290-
prev_token = lexed[index - 2][0] if index - 2 >= 0
291-
next_token = lexed[index][0]
290+
prev_token, _ = lexed[index - 2] if index - 2 >= 0
291+
next_token, _ = lexed[index]
292292

293293
is_inline_comment = prev_token&.location&.start_line == token.location.start_line
294294
if is_inline_comment && !is_at_eol && !COMMENT_CONTINUATION_TYPES.include?(next_token&.type)
@@ -307,7 +307,7 @@ def to_a
307307
end
308308
end
309309
when :tNL
310-
next_token = next_token = lexed[index][0]
310+
next_token, _ = lexed[index]
311311
# Newlines after comments are emitted out of order.
312312
if next_token&.type == :COMMENT
313313
comment_newline_location = location
@@ -344,8 +344,8 @@ def to_a
344344
location = range(token.location.start_offset, token.location.start_offset + percent_array_leading_whitespace(value))
345345
value = nil
346346
when :tSTRING_BEG
347-
next_token = lexed[index][0]
348-
next_next_token = lexed[index + 1][0]
347+
next_token, _ = lexed[index]
348+
next_next_token, _ = lexed[index + 1]
349349
basic_quotes = value == '"' || value == "'"
350350

351351
if basic_quotes && next_token&.type == :STRING_END
@@ -413,7 +413,7 @@ def to_a
413413
while token.type == :STRING_CONTENT
414414
current_length += token.value.bytesize
415415
# Heredoc interpolation can have multiple STRING_CONTENT nodes on the same line.
416-
is_first_token_on_line = lexed[index - 1] && token.location.start_line != lexed[index - 2][0].location&.start_line
416+
is_first_token_on_line = lexed[index - 1] && token.location.start_line != lexed[index - 2]&.first&.location&.start_line
417417
# The parser gem only removes indentation when the heredoc is not nested
418418
not_nested = heredoc_stack.size == 1
419419
if is_percent_array
@@ -427,7 +427,7 @@ def to_a
427427
tokens << [:tSTRING_CONTENT, [current_string, range(start_offset, start_offset + current_length)]]
428428
break
429429
end
430-
token = lexed[index][0]
430+
token, _ = lexed[index]
431431
index += 1
432432
end
433433
else
@@ -482,7 +482,7 @@ def to_a
482482
end
483483

484484
if percent_array?(quote_stack.pop)
485-
prev_token = lexed[index - 2][0] if index - 2 >= 0
485+
prev_token, _ = lexed[index - 2] if index - 2 >= 0
486486
empty = %i[PERCENT_LOWER_I PERCENT_LOWER_W PERCENT_UPPER_I PERCENT_UPPER_W].include?(prev_token&.type)
487487
ends_with_whitespace = prev_token&.type == :WORDS_SEP
488488
# parser always emits a space token after content in a percent array, even if no actual whitespace is present.
@@ -491,7 +491,7 @@ def to_a
491491
end
492492
end
493493
when :tSYMBEG
494-
if (next_token = lexed[index][0]) && next_token.type != :STRING_CONTENT && next_token.type != :EMBEXPR_BEGIN && next_token.type != :EMBVAR && next_token.type != :STRING_END
494+
if (next_token, _ = lexed[index]) && next_token.type != :STRING_CONTENT && next_token.type != :EMBEXPR_BEGIN && next_token.type != :EMBVAR && next_token.type != :STRING_END
495495
next_location = token.location.join(next_token.location)
496496
type = :tSYMBOL
497497
value = next_token.value
@@ -506,13 +506,13 @@ def to_a
506506
type = :tIDENTIFIER
507507
end
508508
when :tXSTRING_BEG
509-
if (next_token = lexed[index][0]) && !%i[STRING_CONTENT STRING_END EMBEXPR_BEGIN].include?(next_token.type)
509+
if (next_token, _ = lexed[index]) && !%i[STRING_CONTENT STRING_END EMBEXPR_BEGIN].include?(next_token.type)
510510
# self.`()
511511
type = :tBACK_REF2
512512
end
513513
quote_stack.push(value)
514514
when :tSYMBOLS_BEG, :tQSYMBOLS_BEG, :tWORDS_BEG, :tQWORDS_BEG
515-
if (next_token = lexed[index][0]) && next_token.type == :WORDS_SEP
515+
if (next_token, _ = lexed[index]) && next_token.type == :WORDS_SEP
516516
index += 1
517517
end
518518

@@ -588,9 +588,9 @@ def calculate_heredoc_whitespace(heredoc_token_index)
588588
previous_line = -1
589589
result = Float::MAX
590590

591-
while (lexed[next_token_index] && next_token = lexed[next_token_index][0])
591+
while (next_token, _ = lexed[next_token_index])
592592
next_token_index += 1
593-
next_next_token = lexed[next_token_index] && lexed[next_token_index][0]
593+
next_next_token, _ = lexed[next_token_index]
594594
first_token_on_line = next_token.location.start_column == 0
595595

596596
# String content inside nested heredocs and interpolation is ignored

test/prism/ruby/parser_test.rb

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,22 @@ def test_current_parser_for_current_ruby
173173
end
174174
end
175175

176+
def test_invalid_syntax
177+
code = <<~RUBY
178+
foo do
179+
case bar
180+
when
181+
end
182+
end
183+
RUBY
184+
buffer = Parser::Source::Buffer.new("(string)")
185+
buffer.source = code
186+
187+
parser = Prism::Translation::Parser33.new
188+
parser.diagnostics.all_errors_are_fatal = true
189+
assert_raise(Parser::SyntaxError) { parser.tokenize(buffer) }
190+
end
191+
176192
def test_it_block_parameter_syntax
177193
it_fixture_path = Pathname(__dir__).join("../../../test/prism/fixtures/it.txt")
178194

0 commit comments

Comments
 (0)