irb 1.14.0 → 1.14.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -3,235 +3,237 @@ module IRB
3
3
  module NestingParser
4
4
  IGNORE_TOKENS = %i[on_sp on_ignored_nl on_comment on_embdoc_beg on_embdoc on_embdoc_end]
5
5
 
6
- # Scan each token and call the given block with array of token and other information for parsing
7
- def self.scan_opens(tokens)
8
- opens = []
9
- pending_heredocs = []
10
- first_token_on_line = true
11
- tokens.each do |t|
12
- skip = false
13
- last_tok, state, args = opens.last
14
- case state
15
- when :in_alias_undef
16
- skip = t.event == :on_kw
17
- when :in_unquoted_symbol
18
- unless IGNORE_TOKENS.include?(t.event)
19
- opens.pop
20
- skip = true
21
- end
22
- when :in_lambda_head
23
- opens.pop if t.event == :on_tlambeg || (t.event == :on_kw && t.tok == 'do')
24
- when :in_method_head
25
- unless IGNORE_TOKENS.include?(t.event)
26
- next_args = []
27
- body = nil
28
- if args.include?(:receiver)
29
- case t.event
30
- when :on_lparen, :on_ivar, :on_gvar, :on_cvar
31
- # def (receiver). | def @ivar. | def $gvar. | def @@cvar.
32
- next_args << :dot
33
- when :on_kw
34
- case t.tok
35
- when 'self', 'true', 'false', 'nil'
36
- # def self(arg) | def self.
37
- next_args.push(:arg, :dot)
38
- else
39
- # def if(arg)
6
+ class << self
7
+ # Scan each token and call the given block with array of token and other information for parsing
8
+ def scan_opens(tokens)
9
+ opens = []
10
+ pending_heredocs = []
11
+ first_token_on_line = true
12
+ tokens.each do |t|
13
+ skip = false
14
+ last_tok, state, args = opens.last
15
+ case state
16
+ when :in_alias_undef
17
+ skip = t.event == :on_kw
18
+ when :in_unquoted_symbol
19
+ unless IGNORE_TOKENS.include?(t.event)
20
+ opens.pop
21
+ skip = true
22
+ end
23
+ when :in_lambda_head
24
+ opens.pop if t.event == :on_tlambeg || (t.event == :on_kw && t.tok == 'do')
25
+ when :in_method_head
26
+ unless IGNORE_TOKENS.include?(t.event)
27
+ next_args = []
28
+ body = nil
29
+ if args.include?(:receiver)
30
+ case t.event
31
+ when :on_lparen, :on_ivar, :on_gvar, :on_cvar
32
+ # def (receiver). | def @ivar. | def $gvar. | def @@cvar.
33
+ next_args << :dot
34
+ when :on_kw
35
+ case t.tok
36
+ when 'self', 'true', 'false', 'nil'
37
+ # def self(arg) | def self.
38
+ next_args.push(:arg, :dot)
39
+ else
40
+ # def if(arg)
41
+ skip = true
42
+ next_args << :arg
43
+ end
44
+ when :on_op, :on_backtick
45
+ # def +(arg)
40
46
  skip = true
41
47
  next_args << :arg
48
+ when :on_ident, :on_const
49
+ # def a(arg) | def a.
50
+ next_args.push(:arg, :dot)
42
51
  end
43
- when :on_op, :on_backtick
44
- # def +(arg)
45
- skip = true
46
- next_args << :arg
47
- when :on_ident, :on_const
48
- # def a(arg) | def a.
49
- next_args.push(:arg, :dot)
50
52
  end
51
- end
52
- if args.include?(:dot)
53
- # def receiver.name
54
- next_args << :name if t.event == :on_period || (t.event == :on_op && t.tok == '::')
55
- end
56
- if args.include?(:name)
57
- if %i[on_ident on_const on_op on_kw on_backtick].include?(t.event)
58
- # def name(arg) | def receiver.name(arg)
59
- next_args << :arg
60
- skip = true
53
+ if args.include?(:dot)
54
+ # def receiver.name
55
+ next_args << :name if t.event == :on_period || (t.event == :on_op && t.tok == '::')
61
56
  end
62
- end
63
- if args.include?(:arg)
64
- case t.event
65
- when :on_nl, :on_semicolon
66
- # def receiver.f;
67
- body = :normal
68
- when :on_lparen
69
- # def receiver.f()
70
- next_args << :eq
71
- else
57
+ if args.include?(:name)
58
+ if %i[on_ident on_const on_op on_kw on_backtick].include?(t.event)
59
+ # def name(arg) | def receiver.name(arg)
60
+ next_args << :arg
61
+ skip = true
62
+ end
63
+ end
64
+ if args.include?(:arg)
65
+ case t.event
66
+ when :on_nl, :on_semicolon
67
+ # def receiver.f;
68
+ body = :normal
69
+ when :on_lparen
70
+ # def receiver.f()
71
+ next_args << :eq
72
+ else
73
+ if t.event == :on_op && t.tok == '='
74
+ # def receiver.f =
75
+ body = :oneliner
76
+ else
77
+ # def receiver.f arg
78
+ next_args << :arg_without_paren
79
+ end
80
+ end
81
+ end
82
+ if args.include?(:eq)
72
83
  if t.event == :on_op && t.tok == '='
73
- # def receiver.f =
74
84
  body = :oneliner
75
85
  else
76
- # def receiver.f arg
77
- next_args << :arg_without_paren
86
+ body = :normal
78
87
  end
79
88
  end
80
- end
81
- if args.include?(:eq)
82
- if t.event == :on_op && t.tok == '='
83
- body = :oneliner
84
- else
85
- body = :normal
89
+ if args.include?(:arg_without_paren)
90
+ if %i[on_semicolon on_nl].include?(t.event)
91
+ # def f a;
92
+ body = :normal
93
+ else
94
+ # def f a, b
95
+ next_args << :arg_without_paren
96
+ end
86
97
  end
87
- end
88
- if args.include?(:arg_without_paren)
89
- if %i[on_semicolon on_nl].include?(t.event)
90
- # def f a;
91
- body = :normal
98
+ if body == :oneliner
99
+ opens.pop
100
+ elsif body
101
+ opens[-1] = [last_tok, nil]
92
102
  else
93
- # def f a, b
94
- next_args << :arg_without_paren
103
+ opens[-1] = [last_tok, :in_method_head, next_args]
95
104
  end
96
105
  end
97
- if body == :oneliner
98
- opens.pop
99
- elsif body
106
+ when :in_for_while_until_condition
107
+ if t.event == :on_semicolon || t.event == :on_nl || (t.event == :on_kw && t.tok == 'do')
108
+ skip = true if t.event == :on_kw && t.tok == 'do'
100
109
  opens[-1] = [last_tok, nil]
101
- else
102
- opens[-1] = [last_tok, :in_method_head, next_args]
103
110
  end
104
111
  end
105
- when :in_for_while_until_condition
106
- if t.event == :on_semicolon || t.event == :on_nl || (t.event == :on_kw && t.tok == 'do')
107
- skip = true if t.event == :on_kw && t.tok == 'do'
108
- opens[-1] = [last_tok, nil]
109
- end
110
- end
111
112
 
112
- unless skip
113
- case t.event
114
- when :on_kw
115
- case t.tok
116
- when 'begin', 'class', 'module', 'do', 'case'
117
- opens << [t, nil]
118
- when 'end'
119
- opens.pop
120
- when 'def'
121
- opens << [t, :in_method_head, [:receiver, :name]]
122
- when 'if', 'unless'
123
- unless t.state.allbits?(Ripper::EXPR_LABEL)
113
+ unless skip
114
+ case t.event
115
+ when :on_kw
116
+ case t.tok
117
+ when 'begin', 'class', 'module', 'do', 'case'
124
118
  opens << [t, nil]
125
- end
126
- when 'while', 'until'
127
- unless t.state.allbits?(Ripper::EXPR_LABEL)
128
- opens << [t, :in_for_while_until_condition]
129
- end
130
- when 'ensure', 'rescue'
131
- unless t.state.allbits?(Ripper::EXPR_LABEL)
119
+ when 'end'
120
+ opens.pop
121
+ when 'def'
122
+ opens << [t, :in_method_head, [:receiver, :name]]
123
+ when 'if', 'unless'
124
+ unless t.state.allbits?(Ripper::EXPR_LABEL)
125
+ opens << [t, nil]
126
+ end
127
+ when 'while', 'until'
128
+ unless t.state.allbits?(Ripper::EXPR_LABEL)
129
+ opens << [t, :in_for_while_until_condition]
130
+ end
131
+ when 'ensure', 'rescue'
132
+ unless t.state.allbits?(Ripper::EXPR_LABEL)
133
+ opens.pop
134
+ opens << [t, nil]
135
+ end
136
+ when 'alias'
137
+ opens << [t, :in_alias_undef, 2]
138
+ when 'undef'
139
+ opens << [t, :in_alias_undef, 1]
140
+ when 'elsif', 'else', 'when'
132
141
  opens.pop
133
142
  opens << [t, nil]
143
+ when 'for'
144
+ opens << [t, :in_for_while_until_condition]
145
+ when 'in'
146
+ if last_tok&.event == :on_kw && %w[case in].include?(last_tok.tok) && first_token_on_line
147
+ opens.pop
148
+ opens << [t, nil]
149
+ end
134
150
  end
135
- when 'alias'
136
- opens << [t, :in_alias_undef, 2]
137
- when 'undef'
138
- opens << [t, :in_alias_undef, 1]
139
- when 'elsif', 'else', 'when'
151
+ when :on_tlambda
152
+ opens << [t, :in_lambda_head]
153
+ when :on_lparen, :on_lbracket, :on_lbrace, :on_tlambeg, :on_embexpr_beg, :on_embdoc_beg
154
+ opens << [t, nil]
155
+ when :on_rparen, :on_rbracket, :on_rbrace, :on_embexpr_end, :on_embdoc_end
156
+ opens.pop
157
+ when :on_heredoc_beg
158
+ pending_heredocs << t
159
+ when :on_heredoc_end
140
160
  opens.pop
161
+ when :on_backtick
162
+ opens << [t, nil] if t.state.allbits?(Ripper::EXPR_BEG)
163
+ when :on_tstring_beg, :on_words_beg, :on_qwords_beg, :on_symbols_beg, :on_qsymbols_beg, :on_regexp_beg
141
164
  opens << [t, nil]
142
- when 'for'
143
- opens << [t, :in_for_while_until_condition]
144
- when 'in'
145
- if last_tok&.event == :on_kw && %w[case in].include?(last_tok.tok) && first_token_on_line
146
- opens.pop
165
+ when :on_tstring_end, :on_regexp_end, :on_label_end
166
+ opens.pop
167
+ when :on_symbeg
168
+ if t.tok == ':'
169
+ opens << [t, :in_unquoted_symbol]
170
+ else
147
171
  opens << [t, nil]
148
172
  end
149
173
  end
150
- when :on_tlambda
151
- opens << [t, :in_lambda_head]
152
- when :on_lparen, :on_lbracket, :on_lbrace, :on_tlambeg, :on_embexpr_beg, :on_embdoc_beg
153
- opens << [t, nil]
154
- when :on_rparen, :on_rbracket, :on_rbrace, :on_embexpr_end, :on_embdoc_end
155
- opens.pop
156
- when :on_heredoc_beg
157
- pending_heredocs << t
158
- when :on_heredoc_end
159
- opens.pop
160
- when :on_backtick
161
- opens << [t, nil] if t.state.allbits?(Ripper::EXPR_BEG)
162
- when :on_tstring_beg, :on_words_beg, :on_qwords_beg, :on_symbols_beg, :on_qsymbols_beg, :on_regexp_beg
163
- opens << [t, nil]
164
- when :on_tstring_end, :on_regexp_end, :on_label_end
165
- opens.pop
166
- when :on_symbeg
167
- if t.tok == ':'
168
- opens << [t, :in_unquoted_symbol]
169
- else
170
- opens << [t, nil]
171
- end
172
174
  end
175
+ if t.event == :on_nl || t.event == :on_semicolon
176
+ first_token_on_line = true
177
+ elsif t.event != :on_sp
178
+ first_token_on_line = false
179
+ end
180
+ if pending_heredocs.any? && t.tok.include?("\n")
181
+ pending_heredocs.reverse_each { |t| opens << [t, nil] }
182
+ pending_heredocs = []
183
+ end
184
+ if opens.last && opens.last[1] == :in_alias_undef && !IGNORE_TOKENS.include?(t.event) && t.event != :on_heredoc_end
185
+ tok, state, arg = opens.pop
186
+ opens << [tok, state, arg - 1] if arg >= 1
187
+ end
188
+ yield t, opens if block_given?
173
189
  end
174
- if t.event == :on_nl || t.event == :on_semicolon
175
- first_token_on_line = true
176
- elsif t.event != :on_sp
177
- first_token_on_line = false
178
- end
179
- if pending_heredocs.any? && t.tok.include?("\n")
180
- pending_heredocs.reverse_each { |t| opens << [t, nil] }
181
- pending_heredocs = []
182
- end
183
- if opens.last && opens.last[1] == :in_alias_undef && !IGNORE_TOKENS.include?(t.event) && t.event != :on_heredoc_end
184
- tok, state, arg = opens.pop
185
- opens << [tok, state, arg - 1] if arg >= 1
186
- end
187
- yield t, opens if block_given?
190
+ opens.map(&:first) + pending_heredocs.reverse
188
191
  end
189
- opens.map(&:first) + pending_heredocs.reverse
190
- end
191
192
 
192
- def self.open_tokens(tokens)
193
- # scan_opens without block will return a list of open tokens at last token position
194
- scan_opens(tokens)
195
- end
193
+ def open_tokens(tokens)
194
+ # scan_opens without block will return a list of open tokens at last token position
195
+ scan_opens(tokens)
196
+ end
196
197
 
197
- # Calculates token information [line_tokens, prev_opens, next_opens, min_depth] for each line.
198
- # Example code
199
- # ["hello
200
- # world"+(
201
- # First line
202
- # line_tokens: [[lbracket, '['], [tstring_beg, '"'], [tstring_content("hello\nworld"), "hello\n"]]
203
- # prev_opens: []
204
- # next_tokens: [lbracket, tstring_beg]
205
- # min_depth: 0 (minimum at beginning of line)
206
- # Second line
207
- # line_tokens: [[tstring_content("hello\nworld"), "world"], [tstring_end, '"'], [op, '+'], [lparen, '(']]
208
- # prev_opens: [lbracket, tstring_beg]
209
- # next_tokens: [lbracket, lparen]
210
- # min_depth: 1 (minimum just after tstring_end)
211
- def self.parse_by_line(tokens)
212
- line_tokens = []
213
- prev_opens = []
214
- min_depth = 0
215
- output = []
216
- last_opens = scan_opens(tokens) do |t, opens|
217
- depth = t == opens.last&.first ? opens.size - 1 : opens.size
218
- min_depth = depth if depth < min_depth
219
- if t.tok.include?("\n")
220
- t.tok.each_line do |line|
221
- line_tokens << [t, line]
222
- next if line[-1] != "\n"
223
- next_opens = opens.map(&:first)
224
- output << [line_tokens, prev_opens, next_opens, min_depth]
225
- prev_opens = next_opens
226
- min_depth = prev_opens.size
227
- line_tokens = []
198
+ # Calculates token information [line_tokens, prev_opens, next_opens, min_depth] for each line.
199
+ # Example code
200
+ # ["hello
201
+ # world"+(
202
+ # First line
203
+ # line_tokens: [[lbracket, '['], [tstring_beg, '"'], [tstring_content("hello\nworld"), "hello\n"]]
204
+ # prev_opens: []
205
+ # next_tokens: [lbracket, tstring_beg]
206
+ # min_depth: 0 (minimum at beginning of line)
207
+ # Second line
208
+ # line_tokens: [[tstring_content("hello\nworld"), "world"], [tstring_end, '"'], [op, '+'], [lparen, '(']]
209
+ # prev_opens: [lbracket, tstring_beg]
210
+ # next_tokens: [lbracket, lparen]
211
+ # min_depth: 1 (minimum just after tstring_end)
212
+ def parse_by_line(tokens)
213
+ line_tokens = []
214
+ prev_opens = []
215
+ min_depth = 0
216
+ output = []
217
+ last_opens = scan_opens(tokens) do |t, opens|
218
+ depth = t == opens.last&.first ? opens.size - 1 : opens.size
219
+ min_depth = depth if depth < min_depth
220
+ if t.tok.include?("\n")
221
+ t.tok.each_line do |line|
222
+ line_tokens << [t, line]
223
+ next if line[-1] != "\n"
224
+ next_opens = opens.map(&:first)
225
+ output << [line_tokens, prev_opens, next_opens, min_depth]
226
+ prev_opens = next_opens
227
+ min_depth = prev_opens.size
228
+ line_tokens = []
229
+ end
230
+ else
231
+ line_tokens << [t, t.tok]
228
232
  end
229
- else
230
- line_tokens << [t, t.tok]
231
233
  end
234
+ output << [line_tokens, prev_opens, last_opens, min_depth] if line_tokens.any?
235
+ output
232
236
  end
233
- output << [line_tokens, prev_opens, last_opens, min_depth] if line_tokens.any?
234
- output
235
237
  end
236
238
  end
237
239
  end
data/lib/irb/pager.rb CHANGED
@@ -33,7 +33,11 @@ module IRB
33
33
  # the `IRB::Abort` exception only interrupts IRB's execution but doesn't affect the pager
34
34
  # So to properly terminate the pager with Ctrl-C, we need to catch `IRB::Abort` and kill the pager process
35
35
  rescue IRB::Abort
36
- Process.kill("TERM", pid) if pid
36
+ begin
37
+ Process.kill("TERM", pid) if pid
38
+ rescue Errno::ESRCH
39
+ # Pager process already terminated
40
+ end
37
41
  nil
38
42
  rescue Errno::EPIPE
39
43
  end
data/lib/irb/ruby-lex.rb CHANGED
@@ -36,29 +36,6 @@ module IRB
36
36
  :massign,
37
37
  ]
38
38
 
39
- class TerminateLineInput < StandardError
40
- def initialize
41
- super("Terminate Line Input")
42
- end
43
- end
44
-
45
- def self.compile_with_errors_suppressed(code, line_no: 1)
46
- begin
47
- result = yield code, line_no
48
- rescue ArgumentError
49
- # Ruby can issue an error for the code if there is an
50
- # incomplete magic comment for encoding in it. Force an
51
- # expression with a new line before the code in this
52
- # case to prevent magic comment handling. To make sure
53
- # line numbers in the lexed code remain the same,
54
- # decrease the line number by one.
55
- code = ";\n#{code}"
56
- line_no -= 1
57
- result = yield code, line_no
58
- end
59
- result
60
- end
61
-
62
39
  ERROR_TOKENS = [
63
40
  :on_parse_error,
64
41
  :compile_error,
@@ -68,70 +45,102 @@ module IRB
68
45
  :on_param_error
69
46
  ]
70
47
 
71
- def self.generate_local_variables_assign_code(local_variables)
72
- "#{local_variables.join('=')}=nil;" unless local_variables.empty?
48
+ LTYPE_TOKENS = %i[
49
+ on_heredoc_beg on_tstring_beg
50
+ on_regexp_beg on_symbeg on_backtick
51
+ on_symbols_beg on_qsymbols_beg
52
+ on_words_beg on_qwords_beg
53
+ ]
54
+
55
+ class TerminateLineInput < StandardError
56
+ def initialize
57
+ super("Terminate Line Input")
58
+ end
73
59
  end
74
60
 
75
- # Some part of the code is not included in Ripper's token.
76
- # Example: DATA part, token after heredoc_beg when heredoc has unclosed embexpr.
77
- # With interpolated tokens, tokens.map(&:tok).join will be equal to code.
78
- def self.interpolate_ripper_ignored_tokens(code, tokens)
79
- line_positions = [0]
80
- code.lines.each do |line|
81
- line_positions << line_positions.last + line.bytesize
61
+ class << self
62
+ def compile_with_errors_suppressed(code, line_no: 1)
63
+ begin
64
+ result = yield code, line_no
65
+ rescue ArgumentError
66
+ # Ruby can issue an error for the code if there is an
67
+ # incomplete magic comment for encoding in it. Force an
68
+ # expression with a new line before the code in this
69
+ # case to prevent magic comment handling. To make sure
70
+ # line numbers in the lexed code remain the same,
71
+ # decrease the line number by one.
72
+ code = ";\n#{code}"
73
+ line_no -= 1
74
+ result = yield code, line_no
75
+ end
76
+ result
77
+ end
78
+
79
+ def generate_local_variables_assign_code(local_variables)
80
+ "#{local_variables.join('=')}=nil;" unless local_variables.empty?
82
81
  end
83
- prev_byte_pos = 0
84
- interpolated = []
85
- prev_line = 1
86
- tokens.each do |t|
87
- line, col = t.pos
88
- byte_pos = line_positions[line - 1] + col
89
- if prev_byte_pos < byte_pos
90
- tok = code.byteslice(prev_byte_pos...byte_pos)
82
+
83
+ # Some part of the code is not included in Ripper's token.
84
+ # Example: DATA part, token after heredoc_beg when heredoc has unclosed embexpr.
85
+ # With interpolated tokens, tokens.map(&:tok).join will be equal to code.
86
+ def interpolate_ripper_ignored_tokens(code, tokens)
87
+ line_positions = [0]
88
+ code.lines.each do |line|
89
+ line_positions << line_positions.last + line.bytesize
90
+ end
91
+ prev_byte_pos = 0
92
+ interpolated = []
93
+ prev_line = 1
94
+ tokens.each do |t|
95
+ line, col = t.pos
96
+ byte_pos = line_positions[line - 1] + col
97
+ if prev_byte_pos < byte_pos
98
+ tok = code.byteslice(prev_byte_pos...byte_pos)
99
+ pos = [prev_line, prev_byte_pos - line_positions[prev_line - 1]]
100
+ interpolated << Ripper::Lexer::Elem.new(pos, :on_ignored_by_ripper, tok, 0)
101
+ prev_line += tok.count("\n")
102
+ end
103
+ interpolated << t
104
+ prev_byte_pos = byte_pos + t.tok.bytesize
105
+ prev_line += t.tok.count("\n")
106
+ end
107
+ if prev_byte_pos < code.bytesize
108
+ tok = code.byteslice(prev_byte_pos..)
91
109
  pos = [prev_line, prev_byte_pos - line_positions[prev_line - 1]]
92
110
  interpolated << Ripper::Lexer::Elem.new(pos, :on_ignored_by_ripper, tok, 0)
93
- prev_line += tok.count("\n")
94
111
  end
95
- interpolated << t
96
- prev_byte_pos = byte_pos + t.tok.bytesize
97
- prev_line += t.tok.count("\n")
98
- end
99
- if prev_byte_pos < code.bytesize
100
- tok = code.byteslice(prev_byte_pos..)
101
- pos = [prev_line, prev_byte_pos - line_positions[prev_line - 1]]
102
- interpolated << Ripper::Lexer::Elem.new(pos, :on_ignored_by_ripper, tok, 0)
112
+ interpolated
103
113
  end
104
- interpolated
105
- end
106
114
 
107
- def self.ripper_lex_without_warning(code, local_variables: [])
108
- verbose, $VERBOSE = $VERBOSE, nil
109
- lvars_code = generate_local_variables_assign_code(local_variables)
110
- original_code = code
111
- if lvars_code
112
- code = "#{lvars_code}\n#{code}"
113
- line_no = 0
114
- else
115
- line_no = 1
116
- end
115
+ def ripper_lex_without_warning(code, local_variables: [])
116
+ verbose, $VERBOSE = $VERBOSE, nil
117
+ lvars_code = generate_local_variables_assign_code(local_variables)
118
+ original_code = code
119
+ if lvars_code
120
+ code = "#{lvars_code}\n#{code}"
121
+ line_no = 0
122
+ else
123
+ line_no = 1
124
+ end
117
125
 
118
- compile_with_errors_suppressed(code, line_no: line_no) do |inner_code, line_no|
119
- lexer = Ripper::Lexer.new(inner_code, '-', line_no)
120
- tokens = []
121
- lexer.scan.each do |t|
122
- next if t.pos.first == 0
123
- prev_tk = tokens.last
124
- position_overlapped = prev_tk && t.pos[0] == prev_tk.pos[0] && t.pos[1] < prev_tk.pos[1] + prev_tk.tok.bytesize
125
- if position_overlapped
126
- tokens[-1] = t if ERROR_TOKENS.include?(prev_tk.event) && !ERROR_TOKENS.include?(t.event)
127
- else
128
- tokens << t
126
+ compile_with_errors_suppressed(code, line_no: line_no) do |inner_code, line_no|
127
+ lexer = Ripper::Lexer.new(inner_code, '-', line_no)
128
+ tokens = []
129
+ lexer.scan.each do |t|
130
+ next if t.pos.first == 0
131
+ prev_tk = tokens.last
132
+ position_overlapped = prev_tk && t.pos[0] == prev_tk.pos[0] && t.pos[1] < prev_tk.pos[1] + prev_tk.tok.bytesize
133
+ if position_overlapped
134
+ tokens[-1] = t if ERROR_TOKENS.include?(prev_tk.event) && !ERROR_TOKENS.include?(t.event)
135
+ else
136
+ tokens << t
137
+ end
129
138
  end
139
+ interpolate_ripper_ignored_tokens(original_code, tokens)
130
140
  end
131
- interpolate_ripper_ignored_tokens(original_code, tokens)
141
+ ensure
142
+ $VERBOSE = verbose
132
143
  end
133
- ensure
134
- $VERBOSE = verbose
135
144
  end
136
145
 
137
146
  def check_code_state(code, local_variables:)
@@ -391,13 +400,6 @@ module IRB
391
400
  end
392
401
  end
393
402
 
394
- LTYPE_TOKENS = %i[
395
- on_heredoc_beg on_tstring_beg
396
- on_regexp_beg on_symbeg on_backtick
397
- on_symbols_beg on_qsymbols_beg
398
- on_words_beg on_qwords_beg
399
- ]
400
-
401
403
  def ltype_from_open_tokens(opens)
402
404
  start_token = opens.reverse_each.find do |tok|
403
405
  LTYPE_TOKENS.include?(tok.event)