Skip to content

Commit a0e7fba

Browse files
authored
Nesting analysis using Prism (#1092)
* Nesting calculation by Prism * Avoid prism-1.8.0 used in test, use latest version on github * Fix open heredoc sorting * Rename old variable open_token to open_elem It was a token, but changed to NestingParser::NestingElement * Add detailed comment about NestingParse internal
1 parent 309230f commit a0e7fba

File tree

7 files changed

+463
-303
lines changed

7 files changed

+463
-303
lines changed

Gemfile

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@ if ENV['PRISM_VERSION'] == 'latest'
2828
gem "prism", github: "ruby/prism"
2929
elsif ENV['PRISM_VERSION']
3030
gem "prism", ENV['PRISM_VERSION']
31+
else
32+
gem "prism", "!= 1.8.0"
3133
end
3234

3335
if RUBY_VERSION >= "3.0.0" && !is_truffleruby

lib/irb.rb

Lines changed: 10 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
# by Keiju ISHITSUKA(keiju@ruby-lang.org)
66
#
77

8+
require "prism"
89
require "ripper"
910
require "reline"
1011

@@ -323,15 +324,13 @@ def configure_io
323324
end
324325
if @context.io.respond_to?(:dynamic_prompt)
325326
@context.io.dynamic_prompt do |lines|
326-
tokens = RubyLex.ripper_lex_without_warning(lines.map{ |l| l + "\n" }.join, local_variables: @context.local_variables)
327-
line_results = IRB::NestingParser.parse_by_line(tokens)
327+
code = lines.map{ |l| l + "\n" }.join
328+
tokens = RubyLex.ripper_lex_without_warning(code, local_variables: @context.local_variables)
329+
parse_lex_result = Prism.parse_lex(code, scopes: [@context.local_variables])
330+
line_results = IRB::NestingParser.parse_by_line(parse_lex_result)
328331
tokens_until_line = []
329-
line_results.map.with_index do |(line_tokens, _prev_opens, next_opens, _min_depth), line_num_offset|
330-
line_tokens.each do |token, _s|
331-
# Avoid appending duplicated token. Tokens that include "n" like multiline
332-
# tstring_content can exist in multiple lines.
333-
tokens_until_line << token if token != tokens_until_line.last
334-
end
332+
line_results.map.with_index do |(_prev_opens, next_opens, _min_depth), line_num_offset|
333+
tokens_until_line << tokens.shift while !tokens.empty? && tokens.first.pos[0] <= line_num_offset + 1
335334
continue = @scanner.should_continue?(tokens_until_line)
336335
generate_prompt(next_opens, continue, line_num_offset)
337336
end
@@ -344,8 +343,8 @@ def configure_io
344343
next nil if !is_newline && lines[line_index]&.byteslice(0, byte_pointer)&.match?(/\A\s*\z/)
345344

346345
code = lines[0..line_index].map { |l| "#{l}\n" }.join
347-
tokens = RubyLex.ripper_lex_without_warning(code, local_variables: @context.local_variables)
348-
@scanner.process_indent_level(tokens, lines, line_index, is_newline)
346+
parse_lex_result = Prism.parse_lex(code, scopes: [@context.local_variables])
347+
@scanner.process_indent_level(parse_lex_result, lines, line_index, is_newline)
349348
end
350349
end
351350
end
@@ -584,7 +583,7 @@ def with_prompt_part_cached
584583
end
585584

586585
def generate_prompt(opens, continue, line_offset)
587-
ltype = @scanner.ltype_from_open_tokens(opens)
586+
ltype = @scanner.ltype_from_open_nestings(opens)
588587
indent = @scanner.calc_indent_level(opens)
589588
continue = opens.any? || continue
590589
line_no = @line_no + line_offset

0 commit comments

Comments
 (0)