irb 1.3.6 → 1.4.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.
data/lib/irb/ruby-lex.rb CHANGED
@@ -30,26 +30,31 @@ class RubyLex
30
30
  @prompt = nil
31
31
  end
32
32
 
33
- def self.compile_with_errors_suppressed(code)
34
- line_no = 1
33
+ def self.compile_with_errors_suppressed(code, line_no: 1)
35
34
  begin
36
35
  result = yield code, line_no
37
36
  rescue ArgumentError
37
+ # Ruby can issue an error for the code if there is an
38
+ # incomplete magic comment for encoding in it. Force an
39
+ # expression with a new line before the code in this
40
+ # case to prevent magic comment handling. To make sure
41
+ # line numbers in the lexed code remain the same,
42
+ # decrease the line number by one.
38
43
  code = ";\n#{code}"
39
- line_no = 0
44
+ line_no -= 1
40
45
  result = yield code, line_no
41
46
  end
42
47
  result
43
48
  end
44
49
 
45
50
  # io functions
46
- def set_input(io, p = nil, &block)
51
+ def set_input(io, p = nil, context: nil, &block)
47
52
  @io = io
48
53
  if @io.respond_to?(:check_termination)
49
54
  @io.check_termination do |code|
50
55
  if Reline::IOGate.in_pasting?
51
56
  lex = RubyLex.new
52
- rest = lex.check_termination_in_prev_line(code)
57
+ rest = lex.check_termination_in_prev_line(code, context: context)
53
58
  if rest
54
59
  Reline.delete_text
55
60
  rest.bytes.reverse_each do |c|
@@ -61,7 +66,7 @@ class RubyLex
61
66
  end
62
67
  else
63
68
  code.gsub!(/\s*\z/, '').concat("\n")
64
- ltype, indent, continue, code_block_open = check_state(code)
69
+ ltype, indent, continue, code_block_open = check_state(code, context: context)
65
70
  if ltype or indent > 0 or continue or code_block_open
66
71
  false
67
72
  else
@@ -74,7 +79,7 @@ class RubyLex
74
79
  @io.dynamic_prompt do |lines|
75
80
  lines << '' if lines.empty?
76
81
  result = []
77
- tokens = self.class.ripper_lex_without_warning(lines.map{ |l| l + "\n" }.join)
82
+ tokens = self.class.ripper_lex_without_warning(lines.map{ |l| l + "\n" }.join, context: context)
78
83
  code = String.new
79
84
  partial_tokens = []
80
85
  unprocessed_tokens = []
@@ -82,26 +87,28 @@ class RubyLex
82
87
  tokens.each do |t|
83
88
  partial_tokens << t
84
89
  unprocessed_tokens << t
85
- if t[2].include?("\n")
86
- t_str = t[2]
90
+ if t.tok.include?("\n")
91
+ t_str = t.tok
87
92
  t_str.each_line("\n") do |s|
88
93
  code << s << "\n"
89
- ltype, indent, continue, code_block_open = check_state(code, partial_tokens)
94
+ ltype, indent, continue, code_block_open = check_state(code, partial_tokens, context: context)
90
95
  result << @prompt.call(ltype, indent, continue || code_block_open, @line_no + line_num_offset)
91
96
  line_num_offset += 1
92
97
  end
93
98
  unprocessed_tokens = []
94
99
  else
95
- code << t[2]
100
+ code << t.tok
96
101
  end
97
102
  end
103
+
98
104
  unless unprocessed_tokens.empty?
99
- ltype, indent, continue, code_block_open = check_state(code, unprocessed_tokens)
105
+ ltype, indent, continue, code_block_open = check_state(code, unprocessed_tokens, context: context)
100
106
  result << @prompt.call(ltype, indent, continue || code_block_open, @line_no + line_num_offset)
101
107
  end
102
108
  result
103
109
  end
104
110
  end
111
+
105
112
  if p.respond_to?(:call)
106
113
  @input = p
107
114
  elsif block_given?
@@ -129,28 +136,38 @@ class RubyLex
129
136
  :on_param_error
130
137
  ]
131
138
 
132
- def self.ripper_lex_without_warning(code)
139
+ def self.ripper_lex_without_warning(code, context: nil)
133
140
  verbose, $VERBOSE = $VERBOSE, nil
141
+ if context
142
+ lvars = context&.workspace&.binding&.local_variables
143
+ if lvars && !lvars.empty?
144
+ code = "#{lvars.join('=')}=nil\n#{code}"
145
+ line_no = 0
146
+ else
147
+ line_no = 1
148
+ end
149
+ end
134
150
  tokens = nil
135
- compile_with_errors_suppressed(code) do |inner_code, line_no|
151
+ compile_with_errors_suppressed(code, line_no: line_no) do |inner_code, line_no|
136
152
  lexer = Ripper::Lexer.new(inner_code, '-', line_no)
137
153
  if lexer.respond_to?(:scan) # Ruby 2.7+
138
154
  tokens = []
139
155
  pos_to_index = {}
140
156
  lexer.scan.each do |t|
141
- if pos_to_index.has_key?(t[0])
142
- index = pos_to_index[t[0]]
157
+ next if t.pos.first == 0
158
+ if pos_to_index.has_key?(t.pos)
159
+ index = pos_to_index[t.pos]
143
160
  found_tk = tokens[index]
144
- if ERROR_TOKENS.include?(found_tk[1]) && !ERROR_TOKENS.include?(t[1])
161
+ if ERROR_TOKENS.include?(found_tk.event) && !ERROR_TOKENS.include?(t.event)
145
162
  tokens[index] = t
146
163
  end
147
164
  else
148
- pos_to_index[t[0]] = tokens.size
165
+ pos_to_index[t.pos] = tokens.size
149
166
  tokens << t
150
167
  end
151
168
  end
152
169
  else
153
- tokens = lexer.parse
170
+ tokens = lexer.parse.reject { |it| it.pos.first == 0 }
154
171
  end
155
172
  end
156
173
  tokens
@@ -160,17 +177,17 @@ class RubyLex
160
177
 
161
178
  def find_prev_spaces(line_index)
162
179
  return 0 if @tokens.size == 0
163
- md = @tokens[0][2].match(/(\A +)/)
180
+ md = @tokens[0].tok.match(/(\A +)/)
164
181
  prev_spaces = md.nil? ? 0 : md[1].count(' ')
165
182
  line_count = 0
166
183
  @tokens.each_with_index do |t, i|
167
- if t[2].include?("\n")
168
- line_count += t[2].count("\n")
184
+ if t.tok.include?("\n")
185
+ line_count += t.tok.count("\n")
169
186
  if line_count >= line_index
170
187
  return prev_spaces
171
188
  end
172
189
  if (@tokens.size - 1) > i
173
- md = @tokens[i + 1][2].match(/(\A +)/)
190
+ md = @tokens[i + 1].tok.match(/(\A +)/)
174
191
  prev_spaces = md.nil? ? 0 : md[1].count(' ')
175
192
  end
176
193
  end
@@ -182,7 +199,7 @@ class RubyLex
182
199
  if @io.respond_to?(:auto_indent) and context.auto_indent_mode
183
200
  @io.auto_indent do |lines, line_index, byte_pointer, is_newline|
184
201
  if is_newline
185
- @tokens = self.class.ripper_lex_without_warning(lines[0..line_index].join("\n"))
202
+ @tokens = self.class.ripper_lex_without_warning(lines[0..line_index].join("\n"), context: context)
186
203
  prev_spaces = find_prev_spaces(line_index)
187
204
  depth_difference = check_newline_depth_difference
188
205
  depth_difference = 0 if depth_difference < 0
@@ -191,8 +208,8 @@ class RubyLex
191
208
  code = line_index.zero? ? '' : lines[0..(line_index - 1)].map{ |l| l + "\n" }.join
192
209
  last_line = lines[line_index]&.byteslice(0, byte_pointer)
193
210
  code += last_line if last_line
194
- @tokens = self.class.ripper_lex_without_warning(code)
195
- corresponding_token_depth = check_corresponding_token_depth
211
+ @tokens = self.class.ripper_lex_without_warning(code, context: context)
212
+ corresponding_token_depth = check_corresponding_token_depth(lines, line_index)
196
213
  if corresponding_token_depth
197
214
  corresponding_token_depth
198
215
  else
@@ -203,8 +220,8 @@ class RubyLex
203
220
  end
204
221
  end
205
222
 
206
- def check_state(code, tokens = nil)
207
- tokens = self.class.ripper_lex_without_warning(code) unless tokens
223
+ def check_state(code, tokens = nil, context: nil)
224
+ tokens = self.class.ripper_lex_without_warning(code, context: context) unless tokens
208
225
  ltype = process_literal_type(tokens)
209
226
  indent = process_nesting_level(tokens)
210
227
  continue = process_continue(tokens)
@@ -280,18 +297,18 @@ class RubyLex
280
297
 
281
298
  def process_continue(tokens = @tokens)
282
299
  # last token is always newline
283
- if tokens.size >= 2 and tokens[-2][1] == :on_regexp_end
300
+ if tokens.size >= 2 and tokens[-2].event == :on_regexp_end
284
301
  # end of regexp literal
285
302
  return false
286
- elsif tokens.size >= 2 and tokens[-2][1] == :on_semicolon
303
+ elsif tokens.size >= 2 and tokens[-2].event == :on_semicolon
287
304
  return false
288
- elsif tokens.size >= 2 and tokens[-2][1] == :on_kw and ['begin', 'else', 'ensure'].include?(tokens[-2][2])
305
+ elsif tokens.size >= 2 and tokens[-2].event == :on_kw and ['begin', 'else', 'ensure'].include?(tokens[-2].tok)
289
306
  return false
290
- elsif !tokens.empty? and tokens.last[2] == "\\\n"
307
+ elsif !tokens.empty? and tokens.last.tok == "\\\n"
291
308
  return true
292
- elsif tokens.size >= 1 and tokens[-1][1] == :on_heredoc_end # "EOH\n"
309
+ elsif tokens.size >= 1 and tokens[-1].event == :on_heredoc_end # "EOH\n"
293
310
  return false
294
- elsif tokens.size >= 2 and defined?(Ripper::EXPR_BEG) and tokens[-2][3].anybits?(Ripper::EXPR_BEG | Ripper::EXPR_FNAME) and tokens[-2][2] !~ /\A\.\.\.?\z/
311
+ elsif tokens.size >= 2 and defined?(Ripper::EXPR_BEG) and tokens[-2].state.anybits?(Ripper::EXPR_BEG | Ripper::EXPR_FNAME) and tokens[-2].tok !~ /\A\.\.\.?\z/
295
312
  # end of literal except for regexp
296
313
  # endless range at end of line is not a continue
297
314
  return true
@@ -301,7 +318,7 @@ class RubyLex
301
318
 
302
319
  def check_code_block(code, tokens = @tokens)
303
320
  return true if tokens.empty?
304
- if tokens.last[1] == :on_heredoc_beg
321
+ if tokens.last.event == :on_heredoc_beg
305
322
  return true
306
323
  end
307
324
 
@@ -373,7 +390,7 @@ class RubyLex
373
390
  end
374
391
 
375
392
  if defined?(Ripper::EXPR_BEG)
376
- last_lex_state = tokens.last[3]
393
+ last_lex_state = tokens.last.state
377
394
  if last_lex_state.allbits?(Ripper::EXPR_BEG)
378
395
  return false
379
396
  elsif last_lex_state.allbits?(Ripper::EXPR_DOT)
@@ -398,14 +415,14 @@ class RubyLex
398
415
  tokens.each_with_index { |t, index|
399
416
  # detecting one-liner method definition
400
417
  if in_oneliner_def.nil?
401
- if t[3].allbits?(Ripper::EXPR_ENDFN)
418
+ if t.state.allbits?(Ripper::EXPR_ENDFN)
402
419
  in_oneliner_def = :ENDFN
403
420
  end
404
421
  else
405
- if t[3].allbits?(Ripper::EXPR_ENDFN)
422
+ if t.state.allbits?(Ripper::EXPR_ENDFN)
406
423
  # continuing
407
- elsif t[3].allbits?(Ripper::EXPR_BEG)
408
- if t[2] == '='
424
+ elsif t.state.allbits?(Ripper::EXPR_BEG)
425
+ if t.tok == '='
409
426
  in_oneliner_def = :BODY
410
427
  end
411
428
  else
@@ -417,14 +434,14 @@ class RubyLex
417
434
  end
418
435
  end
419
436
 
420
- case t[1]
437
+ case t.event
421
438
  when :on_lbracket, :on_lbrace, :on_lparen, :on_tlambeg
422
439
  indent += 1
423
440
  when :on_rbracket, :on_rbrace, :on_rparen
424
441
  indent -= 1
425
442
  when :on_kw
426
- next if index > 0 and tokens[index - 1][3].allbits?(Ripper::EXPR_FNAME)
427
- case t[2]
443
+ next if index > 0 and tokens[index - 1].state.allbits?(Ripper::EXPR_FNAME)
444
+ case t.tok
428
445
  when 'do'
429
446
  syntax_of_do = take_corresponding_syntax_to_kw_do(tokens, index)
430
447
  indent += 1 if syntax_of_do == :method_calling
@@ -432,7 +449,7 @@ class RubyLex
432
449
  indent += 1
433
450
  when 'if', 'unless', 'while', 'until'
434
451
  # postfix if/unless/while/until must be Ripper::EXPR_LABEL
435
- indent += 1 unless t[3].allbits?(Ripper::EXPR_LABEL)
452
+ indent += 1 unless t.state.allbits?(Ripper::EXPR_LABEL)
436
453
  when 'end'
437
454
  indent -= 1
438
455
  end
@@ -444,14 +461,14 @@ class RubyLex
444
461
 
445
462
  def is_method_calling?(tokens, index)
446
463
  tk = tokens[index]
447
- if tk[3].anybits?(Ripper::EXPR_CMDARG) and tk[1] == :on_ident
464
+ if tk.state.anybits?(Ripper::EXPR_CMDARG) and tk.event == :on_ident
448
465
  # The target method call to pass the block with "do".
449
466
  return true
450
- elsif tk[3].anybits?(Ripper::EXPR_ARG) and tk[1] == :on_ident
451
- non_sp_index = tokens[0..(index - 1)].rindex{ |t| t[1] != :on_sp }
467
+ elsif tk.state.anybits?(Ripper::EXPR_ARG) and tk.event == :on_ident
468
+ non_sp_index = tokens[0..(index - 1)].rindex{ |t| t.event != :on_sp }
452
469
  if non_sp_index
453
470
  prev_tk = tokens[non_sp_index]
454
- if prev_tk[3].anybits?(Ripper::EXPR_DOT) and prev_tk[1] == :on_period
471
+ if prev_tk.state.anybits?(Ripper::EXPR_DOT) and prev_tk.event == :on_period
455
472
  # The target method call with receiver to pass the block with "do".
456
473
  return true
457
474
  end
@@ -462,21 +479,21 @@ class RubyLex
462
479
 
463
480
  def take_corresponding_syntax_to_kw_do(tokens, index)
464
481
  syntax_of_do = nil
465
- # Finding a syntax correnponding to "do".
482
+ # Finding a syntax corresponding to "do".
466
483
  index.downto(0) do |i|
467
484
  tk = tokens[i]
468
485
  # In "continue", the token isn't the corresponding syntax to "do".
469
- non_sp_index = tokens[0..(i - 1)].rindex{ |t| t[1] != :on_sp }
486
+ non_sp_index = tokens[0..(i - 1)].rindex{ |t| t.event != :on_sp }
470
487
  first_in_fomula = false
471
488
  if non_sp_index.nil?
472
489
  first_in_fomula = true
473
- elsif [:on_ignored_nl, :on_nl, :on_comment].include?(tokens[non_sp_index][1])
490
+ elsif [:on_ignored_nl, :on_nl, :on_comment].include?(tokens[non_sp_index].event)
474
491
  first_in_fomula = true
475
492
  end
476
493
  if is_method_calling?(tokens, i)
477
494
  syntax_of_do = :method_calling
478
495
  break if first_in_fomula
479
- elsif tk[1] == :on_kw && %w{while until for}.include?(tk[2])
496
+ elsif tk.event == :on_kw && %w{while until for}.include?(tk.tok)
480
497
  # A loop syntax in front of "do" found.
481
498
  #
482
499
  # while cond do # also "until" or "for"
@@ -493,18 +510,18 @@ class RubyLex
493
510
 
494
511
  def is_the_in_correspond_to_a_for(tokens, index)
495
512
  syntax_of_in = nil
496
- # Finding a syntax correnponding to "do".
513
+ # Finding a syntax corresponding to "do".
497
514
  index.downto(0) do |i|
498
515
  tk = tokens[i]
499
516
  # In "continue", the token isn't the corresponding syntax to "do".
500
- non_sp_index = tokens[0..(i - 1)].rindex{ |t| t[1] != :on_sp }
517
+ non_sp_index = tokens[0..(i - 1)].rindex{ |t| t.event != :on_sp }
501
518
  first_in_fomula = false
502
519
  if non_sp_index.nil?
503
520
  first_in_fomula = true
504
- elsif [:on_ignored_nl, :on_nl, :on_comment].include?(tokens[non_sp_index][1])
521
+ elsif [:on_ignored_nl, :on_nl, :on_comment].include?(tokens[non_sp_index].event)
505
522
  first_in_fomula = true
506
523
  end
507
- if tk[1] == :on_kw && tk[2] == 'for'
524
+ if tk.event == :on_kw && tk.tok == 'for'
508
525
  # A loop syntax in front of "do" found.
509
526
  #
510
527
  # while cond do # also "until" or "for"
@@ -526,14 +543,14 @@ class RubyLex
526
543
  @tokens.each_with_index do |t, index|
527
544
  # detecting one-liner method definition
528
545
  if in_oneliner_def.nil?
529
- if t[3].allbits?(Ripper::EXPR_ENDFN)
546
+ if t.state.allbits?(Ripper::EXPR_ENDFN)
530
547
  in_oneliner_def = :ENDFN
531
548
  end
532
549
  else
533
- if t[3].allbits?(Ripper::EXPR_ENDFN)
550
+ if t.state.allbits?(Ripper::EXPR_ENDFN)
534
551
  # continuing
535
- elsif t[3].allbits?(Ripper::EXPR_BEG)
536
- if t[2] == '='
552
+ elsif t.state.allbits?(Ripper::EXPR_BEG)
553
+ if t.tok == '='
537
554
  in_oneliner_def = :BODY
538
555
  end
539
556
  else
@@ -545,7 +562,7 @@ class RubyLex
545
562
  end
546
563
  end
547
564
 
548
- case t[1]
565
+ case t.event
549
566
  when :on_ignored_nl, :on_nl, :on_comment
550
567
  if index != (@tokens.size - 1) and in_oneliner_def != :BODY
551
568
  depth_difference = 0
@@ -555,15 +572,16 @@ class RubyLex
555
572
  when :on_sp
556
573
  next
557
574
  end
558
- case t[1]
575
+
576
+ case t.event
559
577
  when :on_lbracket, :on_lbrace, :on_lparen, :on_tlambeg
560
578
  depth_difference += 1
561
579
  open_brace_on_line += 1
562
580
  when :on_rbracket, :on_rbrace, :on_rparen
563
581
  depth_difference -= 1 if open_brace_on_line > 0
564
582
  when :on_kw
565
- next if index > 0 and @tokens[index - 1][3].allbits?(Ripper::EXPR_FNAME)
566
- case t[2]
583
+ next if index > 0 and @tokens[index - 1].state.allbits?(Ripper::EXPR_FNAME)
584
+ case t.tok
567
585
  when 'do'
568
586
  syntax_of_do = take_corresponding_syntax_to_kw_do(@tokens, index)
569
587
  depth_difference += 1 if syntax_of_do == :method_calling
@@ -571,7 +589,7 @@ class RubyLex
571
589
  depth_difference += 1
572
590
  when 'if', 'unless', 'while', 'until', 'rescue'
573
591
  # postfix if/unless/while/until/rescue must be Ripper::EXPR_LABEL
574
- unless t[3].allbits?(Ripper::EXPR_LABEL)
592
+ unless t.state.allbits?(Ripper::EXPR_LABEL)
575
593
  depth_difference += 1
576
594
  end
577
595
  when 'else', 'elsif', 'ensure', 'when'
@@ -588,7 +606,7 @@ class RubyLex
588
606
  depth_difference
589
607
  end
590
608
 
591
- def check_corresponding_token_depth
609
+ def check_corresponding_token_depth(lines, line_index)
592
610
  corresponding_token_depth = nil
593
611
  is_first_spaces_of_line = true
594
612
  is_first_printable_of_line = true
@@ -596,17 +614,22 @@ class RubyLex
596
614
  spaces_at_line_head = 0
597
615
  open_brace_on_line = 0
598
616
  in_oneliner_def = nil
617
+
618
+ if heredoc_scope?
619
+ return lines[line_index][/^ */].length
620
+ end
621
+
599
622
  @tokens.each_with_index do |t, index|
600
623
  # detecting one-liner method definition
601
624
  if in_oneliner_def.nil?
602
- if t[3].allbits?(Ripper::EXPR_ENDFN)
625
+ if t.state.allbits?(Ripper::EXPR_ENDFN)
603
626
  in_oneliner_def = :ENDFN
604
627
  end
605
628
  else
606
- if t[3].allbits?(Ripper::EXPR_ENDFN)
629
+ if t.state.allbits?(Ripper::EXPR_ENDFN)
607
630
  # continuing
608
- elsif t[3].allbits?(Ripper::EXPR_BEG)
609
- if t[2] == '='
631
+ elsif t.state.allbits?(Ripper::EXPR_BEG)
632
+ if t.tok == '='
610
633
  in_oneliner_def = :BODY
611
634
  end
612
635
  else
@@ -623,7 +646,7 @@ class RubyLex
623
646
  end
624
647
  end
625
648
 
626
- case t[1]
649
+ case t.event
627
650
  when :on_ignored_nl, :on_nl, :on_comment
628
651
  if in_oneliner_def != :BODY
629
652
  corresponding_token_depth = nil
@@ -634,11 +657,12 @@ class RubyLex
634
657
  end
635
658
  next
636
659
  when :on_sp
637
- spaces_at_line_head = t[2].count(' ') if is_first_spaces_of_line
660
+ spaces_at_line_head = t.tok.count(' ') if is_first_spaces_of_line
638
661
  is_first_spaces_of_line = false
639
662
  next
640
663
  end
641
- case t[1]
664
+
665
+ case t.event
642
666
  when :on_lbracket, :on_lbrace, :on_lparen, :on_tlambeg
643
667
  spaces_of_nest.push(spaces_at_line_head + open_brace_on_line * 2)
644
668
  open_brace_on_line += 1
@@ -651,8 +675,8 @@ class RubyLex
651
675
  end
652
676
  open_brace_on_line -= 1
653
677
  when :on_kw
654
- next if index > 0 and @tokens[index - 1][3].allbits?(Ripper::EXPR_FNAME)
655
- case t[2]
678
+ next if index > 0 and @tokens[index - 1].state.allbits?(Ripper::EXPR_FNAME)
679
+ case t.tok
656
680
  when 'do'
657
681
  syntax_of_do = take_corresponding_syntax_to_kw_do(@tokens, index)
658
682
  if syntax_of_do == :method_calling
@@ -661,16 +685,20 @@ class RubyLex
661
685
  when 'def', 'case', 'for', 'begin', 'class', 'module'
662
686
  spaces_of_nest.push(spaces_at_line_head)
663
687
  when 'rescue'
664
- unless t[3].allbits?(Ripper::EXPR_LABEL)
688
+ unless t.state.allbits?(Ripper::EXPR_LABEL)
665
689
  corresponding_token_depth = spaces_of_nest.last
666
690
  end
667
691
  when 'if', 'unless', 'while', 'until'
668
692
  # postfix if/unless/while/until must be Ripper::EXPR_LABEL
669
- unless t[3].allbits?(Ripper::EXPR_LABEL)
693
+ unless t.state.allbits?(Ripper::EXPR_LABEL)
670
694
  spaces_of_nest.push(spaces_at_line_head)
671
695
  end
672
- when 'else', 'elsif', 'ensure', 'when', 'in'
696
+ when 'else', 'elsif', 'ensure', 'when'
673
697
  corresponding_token_depth = spaces_of_nest.last
698
+ when 'in'
699
+ if in_keyword_case_scope?
700
+ corresponding_token_depth = spaces_of_nest.last
701
+ end
674
702
  when 'end'
675
703
  if is_first_printable_of_line
676
704
  corresponding_token_depth = spaces_of_nest.pop
@@ -692,7 +720,10 @@ class RubyLex
692
720
  end_type = []
693
721
  while i < tokens.size
694
722
  t = tokens[i]
695
- case t[1]
723
+ case t.event
724
+ when *end_type.last
725
+ start_token.pop
726
+ end_type.pop
696
727
  when :on_tstring_beg
697
728
  start_token << t
698
729
  end_type << [:on_tstring_end, :on_label_end]
@@ -700,10 +731,14 @@ class RubyLex
700
731
  start_token << t
701
732
  end_type << :on_regexp_end
702
733
  when :on_symbeg
703
- acceptable_single_tokens = %i{on_ident on_const on_op on_cvar on_ivar on_gvar on_kw}
704
- if (i + 1) < tokens.size and acceptable_single_tokens.all?{ |st| tokens[i + 1][1] != st }
705
- start_token << t
706
- end_type << :on_tstring_end
734
+ acceptable_single_tokens = %i{on_ident on_const on_op on_cvar on_ivar on_gvar on_kw on_int on_backtick}
735
+ if (i + 1) < tokens.size
736
+ if acceptable_single_tokens.all?{ |st| tokens[i + 1].event != st }
737
+ start_token << t
738
+ end_type << :on_tstring_end
739
+ else
740
+ i += 1
741
+ end
707
742
  end
708
743
  when :on_backtick
709
744
  start_token << t
@@ -714,20 +749,19 @@ class RubyLex
714
749
  when :on_heredoc_beg
715
750
  start_token << t
716
751
  end_type << :on_heredoc_end
717
- when *end_type.last
718
- start_token.pop
719
- end_type.pop
720
752
  end
721
753
  i += 1
722
754
  end
723
- start_token.last.nil? ? '' : start_token.last
755
+ start_token.last.nil? ? nil : start_token.last
724
756
  end
725
757
 
726
758
  def process_literal_type(tokens = @tokens)
727
759
  start_token = check_string_literal(tokens)
728
- case start_token[1]
760
+ return nil if start_token == ""
761
+
762
+ case start_token&.event
729
763
  when :on_tstring_beg
730
- case start_token[2]
764
+ case start_token&.tok
731
765
  when ?" then ?"
732
766
  when /^%.$/ then ?"
733
767
  when /^%Q.$/ then ?"
@@ -742,7 +776,7 @@ class RubyLex
742
776
  when :on_qsymbols_beg then ?]
743
777
  when :on_symbols_beg then ?]
744
778
  when :on_heredoc_beg
745
- start_token[2] =~ /<<[-~]?(['"`])[_a-zA-Z0-9]+\1/
779
+ start_token&.tok =~ /<<[-~]?(['"`])[_a-zA-Z0-9]+\1/
746
780
  case $1
747
781
  when ?" then ?"
748
782
  when ?' then ?'
@@ -754,8 +788,8 @@ class RubyLex
754
788
  end
755
789
  end
756
790
 
757
- def check_termination_in_prev_line(code)
758
- tokens = self.class.ripper_lex_without_warning(code)
791
+ def check_termination_in_prev_line(code, context: nil)
792
+ tokens = self.class.ripper_lex_without_warning(code, context: context)
759
793
  past_first_newline = false
760
794
  index = tokens.rindex do |t|
761
795
  # traverse first token before last line
@@ -770,6 +804,7 @@ class RubyLex
770
804
  false
771
805
  end
772
806
  end
807
+
773
808
  if index
774
809
  first_token = nil
775
810
  last_line_tokens = tokens[(index + 1)..(tokens.size - 1)]
@@ -779,6 +814,7 @@ class RubyLex
779
814
  break
780
815
  end
781
816
  end
817
+
782
818
  if first_token.nil?
783
819
  return false
784
820
  elsif first_token && first_token.state == Ripper::EXPR_DOT
@@ -798,5 +834,28 @@ class RubyLex
798
834
  end
799
835
  false
800
836
  end
837
+
838
+ private
839
+
840
+ def heredoc_scope?
841
+ heredoc_tokens = @tokens.select { |t| [:on_heredoc_beg, :on_heredoc_end].include?(t.event) }
842
+ heredoc_tokens[-1]&.event == :on_heredoc_beg
843
+ end
844
+
845
+ def in_keyword_case_scope?
846
+ kw_tokens = @tokens.select { |t| t.event == :on_kw && ['case', 'for', 'end'].include?(t.tok) }
847
+ counter = 0
848
+ kw_tokens.reverse.each do |t|
849
+ if t.tok == 'case'
850
+ return true if counter.zero?
851
+ counter += 1
852
+ elsif t.tok == 'for'
853
+ counter += 1
854
+ elsif t.tok == 'end'
855
+ counter -= 1
856
+ end
857
+ end
858
+ false
859
+ end
801
860
  end
802
861
  # :startdoc:
data/lib/irb/version.rb CHANGED
@@ -11,7 +11,7 @@
11
11
  #
12
12
 
13
13
  module IRB # :nodoc:
14
- VERSION = "1.3.6"
14
+ VERSION = "1.4.1"
15
15
  @RELEASE_VERSION = VERSION
16
- @LAST_UPDATE_DATE = "2021-06-19"
16
+ @LAST_UPDATE_DATE = "2021-12-25"
17
17
  end
data/lib/irb/workspace.rb CHANGED
@@ -12,6 +12,7 @@
12
12
 
13
13
  require "delegate"
14
14
 
15
+ IRB::TOPLEVEL_BINDING = binding
15
16
  module IRB # :nodoc:
16
17
  class WorkSpace
17
18
  # Creates a new workspace.
@@ -57,6 +58,8 @@ EOF
57
58
  __FILE__,
58
59
  __LINE__ - 3)
59
60
  when 4 # binding is a copy of TOPLEVEL_BINDING (default)
61
+ # Note that this will typically be IRB::TOPLEVEL_BINDING
62
+ # This is to avoid RubyGems' local variables (see issue #17623)
60
63
  @binding = TOPLEVEL_BINDING.dup
61
64
  end
62
65
  end