irb 1.14.0 → 1.14.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -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] unless t.state == Ripper::EXPR_ARG
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,16 @@ 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
+ begin
38
+ Process.kill("TERM", pid) if pid
39
+ rescue Errno::EINVAL
40
+ # SIGTERM not supported (windows)
41
+ Process.kill("KILL", pid)
42
+ end
43
+ rescue Errno::ESRCH
44
+ # Pager process already terminated
45
+ end
37
46
  nil
38
47
  rescue Errno::EPIPE
39
48
  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)