@@ -82,25 +82,33 @@ def assert_row_indenting(lines, row)
8282 end
8383
8484 def assert_indent_level ( lines , expected , local_variables : [ ] )
85- indent_level , _code_block_open = check_state ( lines , local_variables : local_variables )
85+ indent_level , _continue , _code_block_open = check_state ( lines , local_variables : local_variables )
8686 error_message = "Calculated the wrong number of indent level for:\n #{ lines . join ( "\n " ) } "
8787 assert_equal ( expected , indent_level , error_message )
8888 end
8989
90+ def assert_should_continue ( lines , expected , local_variables : [ ] )
91+ _indent_level , continue , _code_block_open = check_state ( lines , local_variables : local_variables )
92+ error_message = "Wrong result of should_continue for:\n #{ lines . join ( "\n " ) } "
93+ assert_equal ( expected , continue , error_message )
94+ end
95+
9096 def assert_code_block_open ( lines , expected , local_variables : [ ] )
91- _indent_level , code_block_open = check_state ( lines , local_variables : local_variables )
97+ _indent_level , _continue , code_block_open = check_state ( lines , local_variables : local_variables )
9298 error_message = "Wrong result of code_block_open for:\n #{ lines . join ( "\n " ) } "
9399 assert_equal ( expected , code_block_open , error_message )
94100 end
95101
96102 def check_state ( lines , local_variables : [ ] )
97103 context = build_context ( local_variables )
98- tokens = RubyLex . ripper_lex_without_warning ( lines . join ( "\n " ) , context : context )
104+ code = lines . join ( "\n " )
105+ tokens = RubyLex . ripper_lex_without_warning ( code , context : context )
99106 opens = IRB ::NestingParser . open_tokens ( tokens )
100107 ruby_lex = RubyLex . new ( context )
101108 indent_level = ruby_lex . calc_indent_level ( opens )
102- code_block_open = !opens . empty? || ruby_lex . process_continue ( tokens )
103- [ indent_level , code_block_open ]
109+ continue = ruby_lex . should_continue? ( tokens )
110+ terminated = ruby_lex . code_terminated? ( code , tokens , opens )
111+ [ indent_level , continue , !terminated ]
104112 end
105113
106114 def test_interpolate_token_with_heredoc_and_unclosed_embexpr
@@ -235,7 +243,7 @@ def test_symbols
235243 def test_endless_range_at_end_of_line
236244 input_with_prompt = [
237245 PromptRow . new ( '001:0: :> ' , %q(a = 3..) ) ,
238- PromptRow . new ( '002:0: :* ' , %q() ) ,
246+ PromptRow . new ( '002:0: :> ' , %q() ) ,
239247 ]
240248
241249 lines = input_with_prompt . map ( &:content )
@@ -256,7 +264,7 @@ def test_heredoc_with_embexpr
256264 PromptRow . new ( '009:0:]:* ' , %q(B) ) ,
257265 PromptRow . new ( '010:0:]:* ' , %q(}) ) ,
258266 PromptRow . new ( '011:0: :> ' , %q(]) ) ,
259- PromptRow . new ( '012:0: :* ' , %q() ) ,
267+ PromptRow . new ( '012:0: :> ' , %q() ) ,
260268 ]
261269
262270 lines = input_with_prompt . map ( &:content )
@@ -285,9 +293,9 @@ def test_heredoc_prompt_with_quotes
285293 def test_backtick_method
286294 input_with_prompt = [
287295 PromptRow . new ( '001:0: :> ' , %q(self.`(arg)) ) ,
288- PromptRow . new ( '002:0: :* ' , %q() ) ,
296+ PromptRow . new ( '002:0: :> ' , %q() ) ,
289297 PromptRow . new ( '003:0: :> ' , %q(def `(); end) ) ,
290- PromptRow . new ( '004:0: :* ' , %q() ) ,
298+ PromptRow . new ( '004:0: :> ' , %q() ) ,
291299 ]
292300
293301 lines = input_with_prompt . map ( &:content )
@@ -777,6 +785,36 @@ def test_dynamic_prompt_with_blank_line
777785 assert_dynamic_prompt ( lines , expected_prompt_list )
778786 end
779787
788+ def test_should_continue
789+ assert_should_continue ( [ 'a' ] , false )
790+ assert_should_continue ( [ '/a/' ] , false )
791+ assert_should_continue ( [ 'a;' ] , false )
792+ assert_should_continue ( [ '<<A' , 'A' ] , false )
793+ assert_should_continue ( [ 'a...' ] , false )
794+ assert_should_continue ( [ 'a\\' , '' ] , true )
795+ assert_should_continue ( [ 'a.' ] , true )
796+ assert_should_continue ( [ 'a+' ] , true )
797+ assert_should_continue ( [ 'a; #comment' , '' , '=begin' , 'embdoc' , '=end' , '' ] , false )
798+ assert_should_continue ( [ 'a+ #comment' , '' , '=begin' , 'embdoc' , '=end' , '' ] , true )
799+ end
800+
801+ def test_code_block_open_with_should_continue
802+ # syntax ok
803+ assert_code_block_open ( [ 'a' ] , false ) # continue: false
804+ assert_code_block_open ( [ 'a\\' , '' ] , true ) # continue: true
805+
806+ # recoverable syntax error code is not terminated
807+ assert_code_block_open ( [ 'a+' , '' ] , true )
808+
809+ # unrecoverable syntax error code is terminated
810+ assert_code_block_open ( [ '.; a+' , '' ] , false )
811+
812+ # other syntax error that failed to determine if it is recoverable or not
813+ assert_code_block_open ( [ '@; a' ] , false )
814+ assert_code_block_open ( [ '@; a+' ] , true )
815+ assert_code_block_open ( [ '@; (a' ] , true )
816+ end
817+
780818 def test_broken_percent_literal
781819 tokens = RubyLex . ripper_lex_without_warning ( '%wwww' )
782820 pos_to_index = { }
0 commit comments