@@ -18,10 +18,7 @@ def initialize
1818
1919 def initialize ( context )
2020 @context = context
21- @exp_line_no = @line_no = 1
22- @indent = 0
23- @continue = false
24- @line = ""
21+ @line_no = 1
2522 @prompt = nil
2623 end
2724
@@ -42,6 +39,11 @@ def self.compile_with_errors_suppressed(code, line_no: 1)
4239 result
4340 end
4441
42+ def single_line_command? ( code )
43+ command = code . split ( /\s / , 2 ) . first
44+ @context . symbol_alias? ( command ) || @context . transform_args? ( command )
45+ end
46+
4547 # io functions
4648 def set_input ( &block )
4749 @input = block
@@ -65,14 +67,9 @@ def configure_io(io)
6567 end
6668 else
6769 # Accept any single-line input for symbol aliases or commands that transform args
68- command = code . split ( /\s / , 2 ) . first
69- if @context . symbol_alias? ( command ) || @context . transform_args? ( command )
70- next true
71- end
70+ next true if single_line_command? ( code )
7271
73- code . gsub! ( /\s *\z / , '' ) . concat ( "\n " )
74- tokens = self . class . ripper_lex_without_warning ( code , context : @context )
75- ltype , indent , continue , code_block_open = check_state ( code , tokens )
72+ ltype , indent , continue , code_block_open = check_code_state ( code )
7673 if ltype or indent > 0 or continue or code_block_open
7774 false
7875 else
@@ -210,67 +207,56 @@ def check_state(code, tokens)
210207 [ ltype , indent , continue , code_block_open ]
211208 end
212209
213- def prompt
214- if @prompt
215- @prompt . call ( @ltype , @indent , @continue , @line_no )
216- end
210+ def check_code_state ( code )
211+ check_target_code = code . gsub ( / \s * \z / , '' ) . concat ( " \n " )
212+ tokens = self . class . ripper_lex_without_warning ( check_target_code , context : @context )
213+ check_state ( check_target_code , tokens )
217214 end
218215
219- def initialize_input
220- @ltype = nil
221- @indent = 0
222- @continue = false
223- @line = ""
224- @exp_line_no = @line_no
225- @code_block_open = false
216+ def save_prompt_to_context_io ( ltype , indent , continue , line_num_offset )
217+ # Implicitly saves prompt string to `@context.io.prompt`. This will be used in the next `@input.call`.
218+ @prompt . call ( ltype , indent , continue , @line_no + line_num_offset )
226219 end
227220
228- def each_top_level_statement
229- initialize_input
230- catch ( :TERM_INPUT ) do
231- loop do
232- begin
233- prompt
234- unless l = lex
235- throw :TERM_INPUT if @line == ''
236- else
237- @line_no += l . count ( "\n " )
238- if l == "\n "
239- @exp_line_no += 1
240- next
241- end
242- @line . concat l
243- if @code_block_open or @ltype or @continue or @indent > 0
244- next
245- end
246- end
247- if @line != "\n "
248- @line . force_encoding ( @io . encoding )
249- yield @line , @exp_line_no
250- end
251- raise TerminateLineInput if @io . eof?
252- @line = ''
253- @exp_line_no = @line_no
254-
255- @indent = 0
256- rescue TerminateLineInput
257- initialize_input
258- prompt
259- end
221+ def readmultiline
222+ save_prompt_to_context_io ( nil , 0 , false , 0 )
223+
224+ # multiline
225+ return @input . call if @io . respond_to? ( :check_termination )
226+
227+ # nomultiline
228+ code = ''
229+ line_offset = 0
230+ loop do
231+ line = @input . call
232+ unless line
233+ return code . empty? ? nil : code
260234 end
235+
236+ code << line
237+ # Accept any single-line input for symbol aliases or commands that transform args
238+ return code if single_line_command? ( code )
239+
240+ ltype , indent , continue , code_block_open = check_code_state ( code )
241+ return code unless ltype or indent > 0 or continue or code_block_open
242+
243+ line_offset += 1
244+ save_prompt_to_context_io ( ltype , indent , continue , line_offset )
261245 end
262246 end
263247
264- def lex
265- line = @input . call
266- if @io . respond_to? ( :check_termination )
267- return line # multiline
248+ def each_top_level_statement
249+ loop do
250+ code = readmultiline
251+ break unless code
252+
253+ if code != "\n "
254+ code . force_encoding ( @io . encoding )
255+ yield code , @line_no
256+ end
257+ @line_no += code . count ( "\n " )
258+ rescue TerminateLineInput
268259 end
269- code = @line + ( line . nil? ? '' : line )
270- code . gsub! ( /\s *\z / , '' ) . concat ( "\n " )
271- @tokens = self . class . ripper_lex_without_warning ( code , context : @context )
272- @ltype , @indent , @continue , @code_block_open = check_state ( code , @tokens )
273- line
274260 end
275261
276262 def process_continue ( tokens )
0 commit comments