Skip to content

Commit babb122

Browse files
committed
Call ripper only once when generating dynamic prompt
1 parent 44d2fe4 commit babb122

File tree

1 file changed

+46
-41
lines changed

1 file changed

+46
-41
lines changed

lib/irb/ruby-lex.rb

Lines changed: 46 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -60,11 +60,19 @@ def set_input(io, p = nil, &block)
6060
@io.dynamic_prompt do |lines|
6161
lines << '' if lines.empty?
6262
result = []
63-
lines.each_index { |i|
64-
c = lines[0..i].map{ |l| l + "\n" }.join
65-
ltype, indent, continue, code_block_open = check_state(c)
66-
result << @prompt.call(ltype, indent, continue || code_block_open, @line_no + i)
67-
}
63+
tokens = ripper_lex_without_warning(lines.map{ |l| l + "\n" }.join)
64+
code = String.new
65+
partial_tokens = []
66+
line_num_offset = 0
67+
tokens.each do |t|
68+
code << t[2]
69+
partial_tokens << t
70+
if t[2].include?("\n")
71+
ltype, indent, continue, code_block_open = check_state(code, partial_tokens)
72+
result << @prompt.call(ltype, indent, continue || code_block_open, @line_no + line_num_offset)
73+
line_num_offset += 1
74+
end
75+
end
6876
result
6977
end
7078
end
@@ -88,12 +96,9 @@ def set_prompt(p = nil, &block)
8896

8997
def ripper_lex_without_warning(code)
9098
verbose, $VERBOSE = $VERBOSE, nil
91-
tokens = []
99+
tokens = nil
92100
self.class.compile_with_errors_suppressed(code) do |inner_code, line_no|
93-
lexer = Ripper::Lexer.new(inner_code, '-', line_no)
94-
until (ts = lexer.lex).empty?
95-
tokens.concat(ts)
96-
end
101+
tokens = Ripper.lex(inner_code, '-', line_no)
97102
end
98103
$VERBOSE = verbose
99104
tokens
@@ -124,12 +129,12 @@ def set_auto_indent(context)
124129
end
125130
end
126131

127-
def check_state(code)
128-
@tokens = ripper_lex_without_warning(code)
129-
ltype = process_literal_type
130-
indent = process_nesting_level
131-
continue = process_continue
132-
code_block_open = check_code_block(code)
132+
def check_state(code, tokens = nil)
133+
tokens = ripper_lex_without_warning(code) unless tokens
134+
ltype = process_literal_type(tokens)
135+
indent = process_nesting_level(tokens)
136+
continue = process_continue(tokens)
137+
code_block_open = check_code_block(code, tokens)
133138
[ltype, indent, continue, code_block_open]
134139
end
135140

@@ -189,36 +194,36 @@ def lex
189194
code = @line + (line.nil? ? '' : line)
190195
code.gsub!(/\s*\z/, '').concat("\n")
191196
@tokens = ripper_lex_without_warning(code)
192-
@continue = process_continue
193-
@code_block_open = check_code_block(code)
194-
@indent = process_nesting_level
195-
@ltype = process_literal_type
197+
@continue = process_continue(@tokens)
198+
@code_block_open = check_code_block(code, @tokens)
199+
@indent = process_nesting_level(@tokens)
200+
@ltype = process_literal_type(@tokens)
196201
line
197202
end
198203

199-
def process_continue
204+
def process_continue(tokens)
200205
# last token is always newline
201-
if @tokens.size >= 2 and @tokens[-2][1] == :on_regexp_end
206+
if tokens.size >= 2 and tokens[-2][1] == :on_regexp_end
202207
# end of regexp literal
203208
return false
204-
elsif @tokens.size >= 2 and @tokens[-2][1] == :on_semicolon
209+
elsif tokens.size >= 2 and tokens[-2][1] == :on_semicolon
205210
return false
206-
elsif @tokens.size >= 2 and @tokens[-2][1] == :on_kw and ['begin', 'else', 'ensure'].include?(@tokens[-2][2])
211+
elsif tokens.size >= 2 and tokens[-2][1] == :on_kw and ['begin', 'else', 'ensure'].include?(tokens[-2][2])
207212
return false
208-
elsif !@tokens.empty? and @tokens.last[2] == "\\\n"
213+
elsif !tokens.empty? and tokens.last[2] == "\\\n"
209214
return true
210-
elsif @tokens.size >= 1 and @tokens[-1][1] == :on_heredoc_end # "EOH\n"
215+
elsif tokens.size >= 1 and tokens[-1][1] == :on_heredoc_end # "EOH\n"
211216
return false
212-
elsif @tokens.size >= 2 and defined?(Ripper::EXPR_BEG) and @tokens[-2][3].anybits?(Ripper::EXPR_BEG | Ripper::EXPR_FNAME)
217+
elsif tokens.size >= 2 and defined?(Ripper::EXPR_BEG) and tokens[-2][3].anybits?(Ripper::EXPR_BEG | Ripper::EXPR_FNAME)
213218
# end of literal except for regexp
214219
return true
215220
end
216221
false
217222
end
218223

219-
def check_code_block(code)
220-
return true if @tokens.empty?
221-
if @tokens.last[1] == :on_heredoc_beg
224+
def check_code_block(code, tokens)
225+
return true if tokens.empty?
226+
if tokens.last[1] == :on_heredoc_beg
222227
return true
223228
end
224229

@@ -290,7 +295,7 @@ def check_code_block(code)
290295
end
291296

292297
if defined?(Ripper::EXPR_BEG)
293-
last_lex_state = @tokens.last[3]
298+
last_lex_state = tokens.last[3]
294299
if last_lex_state.allbits?(Ripper::EXPR_BEG)
295300
return false
296301
elsif last_lex_state.allbits?(Ripper::EXPR_DOT)
@@ -309,10 +314,10 @@ def check_code_block(code)
309314
false
310315
end
311316

312-
def process_nesting_level
317+
def process_nesting_level(tokens)
313318
indent = 0
314319
in_oneliner_def = nil
315-
@tokens.each_with_index { |t, index|
320+
tokens.each_with_index { |t, index|
316321
# detecting one-liner method definition
317322
if in_oneliner_def.nil?
318323
if t[3].allbits?(Ripper::EXPR_ENDFN)
@@ -340,10 +345,10 @@ def process_nesting_level
340345
when :on_rbracket, :on_rbrace, :on_rparen
341346
indent -= 1
342347
when :on_kw
343-
next if index > 0 and @tokens[index - 1][3].allbits?(Ripper::EXPR_FNAME)
348+
next if index > 0 and tokens[index - 1][3].allbits?(Ripper::EXPR_FNAME)
344349
case t[2]
345350
when 'do'
346-
if index > 0 and @tokens[index - 1][3].anybits?(Ripper::EXPR_CMDARG | Ripper::EXPR_ENDFN | Ripper::EXPR_ARG)
351+
if index > 0 and tokens[index - 1][3].anybits?(Ripper::EXPR_CMDARG | Ripper::EXPR_ENDFN | Ripper::EXPR_ARG)
347352
# method_with_block do; end
348353
indent += 1
349354
else
@@ -525,12 +530,12 @@ def check_corresponding_token_depth
525530
corresponding_token_depth
526531
end
527532

528-
def check_string_literal
533+
def check_string_literal(tokens)
529534
i = 0
530535
start_token = []
531536
end_type = []
532-
while i < @tokens.size
533-
t = @tokens[i]
537+
while i < tokens.size
538+
t = tokens[i]
534539
case t[1]
535540
when :on_tstring_beg
536541
start_token << t
@@ -540,7 +545,7 @@ def check_string_literal
540545
end_type << :on_regexp_end
541546
when :on_symbeg
542547
acceptable_single_tokens = %i{on_ident on_const on_op on_cvar on_ivar on_gvar on_kw}
543-
if (i + 1) < @tokens.size and acceptable_single_tokens.all?{ |t| @tokens[i + 1][1] != t }
548+
if (i + 1) < tokens.size and acceptable_single_tokens.all?{ |t| tokens[i + 1][1] != t }
544549
start_token << t
545550
end_type << :on_tstring_end
546551
end
@@ -562,8 +567,8 @@ def check_string_literal
562567
start_token.last.nil? ? '' : start_token.last
563568
end
564569

565-
def process_literal_type
566-
start_token = check_string_literal
570+
def process_literal_type(tokens)
571+
start_token = check_string_literal(tokens)
567572
case start_token[1]
568573
when :on_tstring_beg
569574
case start_token[2]

0 commit comments

Comments
 (0)