From 344e6c915f41d99df024c7e90403baca0d5213a5 Mon Sep 17 00:00:00 2001 From: tomoya ishida Date: Tue, 18 Oct 2022 14:30:29 +0900 Subject: [PATCH] [ruby/irb] Fix code terminated check with heredoc and backtick (https://github.com/ruby/irb/pull/390) * Fix backtick method def method call handled as backtick open * Fix handling heredoc in check_string_literal * Sort result of lexer.parse by pos in ruby<2.7. It's not sorted when the given code includes heredoc. * Update lib/irb/ruby-lex.rb Co-authored-by: Stan Lo * Update lib/irb/ruby-lex.rb Co-authored-by: Stan Lo * Add check_string_literal test for heredoc code that does not end with newline https://github.com/ruby/irb/commit/44bc712460 Co-authored-by: Stan Lo --- lib/irb/ruby-lex.rb | 22 ++++++++++++++------ test/irb/test_ruby_lex.rb | 42 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 58 insertions(+), 6 deletions(-) diff --git a/lib/irb/ruby-lex.rb b/lib/irb/ruby-lex.rb index 8f629331db..cb6d669a72 100644 --- a/lib/irb/ruby-lex.rb +++ b/lib/irb/ruby-lex.rb @@ -162,7 +162,7 @@ class RubyLex end end else - lexer.parse.reject { |it| it.pos.first == 0 } + lexer.parse.reject { |it| it.pos.first == 0 }.sort_by(&:pos) end end ensure @@ -706,6 +706,7 @@ class RubyLex i = 0 start_token = [] end_type = [] + pending_heredocs = [] while i < tokens.size t = tokens[i] case t.event @@ -729,18 +730,27 @@ class RubyLex end end when :on_backtick - start_token << t - end_type << :on_tstring_end + if t.state.allbits?(Ripper::EXPR_BEG) + start_token << t + end_type << :on_tstring_end + end when :on_qwords_beg, :on_words_beg, :on_qsymbols_beg, :on_symbols_beg start_token << t end_type << :on_tstring_end when :on_heredoc_beg - start_token << t - end_type << :on_heredoc_end + pending_heredocs << t + end + + if pending_heredocs.any? && t.tok.include?("\n") + pending_heredocs.reverse_each do |t| + start_token << t + end_type << :on_heredoc_end + end + pending_heredocs = [] end i += 1 end - start_token.last.nil? ? nil : start_token.last + pending_heredocs.first || start_token.last end def process_literal_type(tokens = @tokens) diff --git a/test/irb/test_ruby_lex.rb b/test/irb/test_ruby_lex.rb index 2c94a36a5d..beda53fc89 100644 --- a/test/irb/test_ruby_lex.rb +++ b/test/irb/test_ruby_lex.rb @@ -170,6 +170,40 @@ module TestIRB assert_dynamic_prompt(lines, expected_prompt_list) end + def test_heredoc_with_embexpr + input_with_prompt = [ + PromptRow.new('001:0:":* ', %q(< ', %q(])), + PromptRow.new('012:0: :* ', %q()), + ] + + lines = input_with_prompt.map(&:content) + expected_prompt_list = input_with_prompt.map(&:prompt) + assert_dynamic_prompt(lines, expected_prompt_list) + end + + def test_backtick_method + input_with_prompt = [ + PromptRow.new('001:0: :> ', %q(self.`(arg))), + PromptRow.new('002:0: :* ', %q()), + PromptRow.new('003:0: :> ', %q(def `(); end)), + PromptRow.new('004:0: :* ', %q()), + ] + + lines = input_with_prompt.map(&:content) + expected_prompt_list = input_with_prompt.map(&:prompt) + assert_dynamic_prompt(lines, expected_prompt_list) + end + def test_incomplete_coding_magic_comment input_with_correct_indents = [ Row.new(%q(#coding:u), nil, 0), @@ -632,5 +666,13 @@ module TestIRB assert_empty(error_tokens, 'Error tokens must be ignored if there is corresponding non-error token') end end + + def test_unterminated_heredoc_string_literal + ['<