diff options
author | tomoya ishida <tomoyapenguin@gmail.com> | 2023-05-19 22:48:03 +0900 |
---|---|---|
committer | git <svn-admin@ruby-lang.org> | 2023-05-19 13:48:08 +0000 |
commit | e8c9f727e8a9f0fe9fb1a6d61a60b8c8b479a87b (patch) | |
tree | 8c8d4c9dfd7851f0bbd0da62ad2beb9fdf2b801b /lib/irb | |
parent | 875adad948d48d13539075fff526fa5ecb5eba18 (diff) |
[ruby/irb] Simplify each_top_level_statement
(https://github.com/ruby/irb/pull/576)
* Simplify each_top_level_statement, reduce instance vars
* Update lib/irb/ruby-lex.rb
Co-authored-by: Stan Lo <stan001212@gmail.com>
* Remove unused ltype from TestRubyLex#check_state response
* Remove unnecessary const path of TerminateLineInput
* Combine duplicated code state check into method
---------
https://github.com/ruby/irb/commit/172453cec4
Co-authored-by: Stan Lo <stan001212@gmail.com>
Diffstat (limited to 'lib/irb')
-rw-r--r-- | lib/irb/ruby-lex.rb | 112 |
1 files changed, 49 insertions, 63 deletions
diff --git a/lib/irb/ruby-lex.rb b/lib/irb/ruby-lex.rb index ac734072df..e29d52e47c 100644 --- a/lib/irb/ruby-lex.rb +++ b/lib/irb/ruby-lex.rb @@ -18,10 +18,7 @@ class RubyLex def initialize(context) @context = context - @exp_line_no = @line_no = 1 - @indent = 0 - @continue = false - @line = "" + @line_no = 1 @prompt = nil end @@ -42,6 +39,11 @@ class RubyLex result end + def single_line_command?(code) + command = code.split(/\s/, 2).first + @context.symbol_alias?(command) || @context.transform_args?(command) + end + # io functions def set_input(&block) @input = block @@ -65,14 +67,9 @@ class RubyLex end else # Accept any single-line input for symbol aliases or commands that transform args - command = code.split(/\s/, 2).first - if @context.symbol_alias?(command) || @context.transform_args?(command) - next true - end + next true if single_line_command?(code) - code.gsub!(/\s*\z/, '').concat("\n") - tokens = self.class.ripper_lex_without_warning(code, context: @context) - ltype, indent, continue, code_block_open = check_state(code, tokens) + ltype, indent, continue, code_block_open = check_code_state(code) if ltype or indent > 0 or continue or code_block_open false else @@ -210,67 +207,56 @@ class RubyLex [ltype, indent, continue, code_block_open] end - def prompt - if @prompt - @prompt.call(@ltype, @indent, @continue, @line_no) - end + def check_code_state(code) + check_target_code = code.gsub(/\s*\z/, '').concat("\n") + tokens = self.class.ripper_lex_without_warning(check_target_code, context: @context) + check_state(check_target_code, tokens) end - def initialize_input - @ltype = nil - @indent = 0 - @continue = false - @line = "" - @exp_line_no = @line_no - @code_block_open = false + def save_prompt_to_context_io(ltype, indent, continue, line_num_offset) + # Implicitly saves prompt string to `@context.io.prompt`. This will be used in the next `@input.call`. + @prompt.call(ltype, indent, continue, @line_no + line_num_offset) end - def each_top_level_statement - initialize_input - catch(:TERM_INPUT) do - loop do - begin - prompt - unless l = lex - throw :TERM_INPUT if @line == '' - else - @line_no += l.count("\n") - if l == "\n" - @exp_line_no += 1 - next - end - @line.concat l - if @code_block_open or @ltype or @continue or @indent > 0 - next - end - end - if @line != "\n" - @line.force_encoding(@io.encoding) - yield @line, @exp_line_no - end - raise TerminateLineInput if @io.eof? - @line = '' - @exp_line_no = @line_no - - @indent = 0 - rescue TerminateLineInput - initialize_input - prompt - end + def readmultiline + save_prompt_to_context_io(nil, 0, false, 0) + + # multiline + return @input.call if @io.respond_to?(:check_termination) + + # nomultiline + code = '' + line_offset = 0 + loop do + line = @input.call + unless line + return code.empty? ? nil : code end + + code << line + # Accept any single-line input for symbol aliases or commands that transform args + return code if single_line_command?(code) + + ltype, indent, continue, code_block_open = check_code_state(code) + return code unless ltype or indent > 0 or continue or code_block_open + + line_offset += 1 + save_prompt_to_context_io(ltype, indent, continue, line_offset) end end - def lex - line = @input.call - if @io.respond_to?(:check_termination) - return line # multiline + def each_top_level_statement + loop do + code = readmultiline + break unless code + + if code != "\n" + code.force_encoding(@io.encoding) + yield code, @line_no + end + @line_no += code.count("\n") + rescue TerminateLineInput end - code = @line + (line.nil? ? '' : line) - code.gsub!(/\s*\z/, '').concat("\n") - @tokens = self.class.ripper_lex_without_warning(code, context: @context) - @ltype, @indent, @continue, @code_block_open = check_state(code, @tokens) - line end def process_continue(tokens) |