parser 2.7.1.3 → 2.7.1.4

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.
@@ -1018,11 +1018,15 @@ rule
1018
1018
  result = @builder.block(val[0],
1019
1019
  begin_t, args, body, end_t)
1020
1020
  }
1021
- | tLAMBDA lambda
1021
+ | tLAMBDA
1022
+ {
1023
+ @context.push(:lambda)
1024
+ }
1025
+ lambda
1022
1026
  {
1023
1027
  lambda_call = @builder.call_lambda(val[0])
1024
1028
 
1025
- args, (begin_t, body, end_t) = val[1]
1029
+ args, (begin_t, body, end_t) = val[2]
1026
1030
  result = @builder.block(lambda_call,
1027
1031
  begin_t, args, body, end_t)
1028
1032
  }
@@ -1136,6 +1140,7 @@ rule
1136
1140
  {
1137
1141
  @static_env.extend_static
1138
1142
  @lexer.push_cmdarg
1143
+ @context.push(:module)
1139
1144
  }
1140
1145
  bodystmt kEND
1141
1146
  {
@@ -1148,6 +1153,7 @@ rule
1148
1153
 
1149
1154
  @lexer.pop_cmdarg
1150
1155
  @static_env.unextend
1156
+ @context.pop
1151
1157
  }
1152
1158
  | kDEF fname
1153
1159
  {
@@ -1429,9 +1435,13 @@ rule
1429
1435
  lambda: {
1430
1436
  @static_env.extend_dynamic
1431
1437
  }
1432
- f_larglist lambda_body
1438
+ f_larglist
1439
+ {
1440
+ @context.pop
1441
+ }
1442
+ lambda_body
1433
1443
  {
1434
- result = [ val[1], val[2] ]
1444
+ result = [ val[1], val[3] ]
1435
1445
 
1436
1446
  @static_env.unextend
1437
1447
  }
@@ -37,7 +37,7 @@ module Parser
37
37
 
38
38
  private
39
39
 
40
- LEGACY_MODES = %i[lambda procarg0 encoding index arg_inside_procarg0].freeze
40
+ LEGACY_MODES = %i[lambda procarg0 encoding index arg_inside_procarg0 forward_arg].freeze
41
41
 
42
42
  def runner_name
43
43
  raise NotImplementedError, "implement #{self.class}##{__callee__}"
@@ -13,7 +13,7 @@ module Parser
13
13
  # ^^
14
14
  #
15
15
  # @!attribute [r] source_buffer
16
- # @return [Parser::Diagnostic::Engine]
16
+ # @return [Parser::Source::Buffer]
17
17
  #
18
18
  # @!attribute [r] begin_pos
19
19
  # @return [Integer] index of the first character in the range
@@ -129,6 +129,8 @@ module Parser
129
129
  ##
130
130
  # Merges the updates of argument with the receiver.
131
131
  # Policies of the receiver are used.
132
+ # This action is atomic in that it won't change the receiver
133
+ # unless it succeeds.
132
134
  #
133
135
  # @param [Rewriter] with
134
136
  # @return [Rewriter] self
@@ -154,6 +156,32 @@ module Parser
154
156
  dup.merge!(with)
155
157
  end
156
158
 
159
+ ##
160
+ # For special cases where one needs to merge a rewriter attached to a different source_buffer
161
+ # or that needs to be offset. Policies of the receiver are used.
162
+ #
163
+ # @param [TreeRewriter] rewriter from different source_buffer
164
+ # @param [Integer] offset
165
+ # @return [Rewriter] self
166
+ # @raise [IndexError] if action ranges (once offset) don't fit the current buffer
167
+ #
168
+ def import!(foreign_rewriter, offset: 0)
169
+ return self if foreign_rewriter.empty?
170
+
171
+ contracted = foreign_rewriter.action_root.contract
172
+ merge_effective_range = ::Parser::Source::Range.new(
173
+ @source_buffer,
174
+ contracted.range.begin_pos + offset,
175
+ contracted.range.end_pos + offset,
176
+ )
177
+ check_range_validity(merge_effective_range)
178
+
179
+ merge_with = contracted.moved(@source_buffer, offset)
180
+
181
+ @action_root = @action_root.combine(merge_with)
182
+ self
183
+ end
184
+
157
185
  ##
158
186
  # Replaces the code of the source range `range` with `content`.
159
187
  #
@@ -234,6 +262,44 @@ module Parser
234
262
  chunks.join
235
263
  end
236
264
 
265
+ ##
266
+ # Returns a representation of the rewriter as an ordered list of replacements.
267
+ #
268
+ # rewriter.as_replacements # => [ [1...1, '('],
269
+ # [2...4, 'foo'],
270
+ # [5...6, ''],
271
+ # [6...6, '!'],
272
+ # [10...10, ')'],
273
+ # ]
274
+ #
275
+ # This representation is sufficient to recreate the result of `process` but it is
276
+ # not sufficient to recreate completely the rewriter for further merging/actions.
277
+ # See `as_nested_actions`
278
+ #
279
+ # @return [Array<Range, String>] an ordered list of pairs of range & replacement
280
+ #
281
+ def as_replacements
282
+ @action_root.ordered_replacements
283
+ end
284
+
285
+ ##
286
+ # Returns a representation of the rewriter as nested insertions (:wrap) and replacements.
287
+ #
288
+ # rewriter.as_actions # =>[ [:wrap, 1...10, '(', ')'],
289
+ # [:wrap, 2...6, '', '!'], # aka "insert_after"
290
+ # [:replace, 2...4, 'foo'],
291
+ # [:replace, 5...6, ''], # aka "removal"
292
+ # ],
293
+ #
294
+ # Contrary to `as_replacements`, this representation is sufficient to recreate exactly
295
+ # the rewriter.
296
+ #
297
+ # @return [Array<(Symbol, Range, String{, String})>]
298
+ #
299
+ def as_nested_actions
300
+ @action_root.nested_actions
301
+ end
302
+
237
303
  ##
238
304
  # Provides a protected block where a sequence of multiple rewrite actions
239
305
  # are handled atomically. If any of the actions failed by clobbering,
@@ -310,7 +376,7 @@ module Parser
310
376
 
311
377
  def check_range_validity(range)
312
378
  if range.begin_pos < 0 || range.end_pos > @source_buffer.source.size
313
- raise IndexError, "The range #{range} is outside the bounds of the source"
379
+ raise IndexError, "The range #{range.to_range} is outside the bounds of the source"
314
380
  end
315
381
  range
316
382
  end
@@ -46,10 +46,49 @@ module Parser
46
46
  reps
47
47
  end
48
48
 
49
+ def nested_actions
50
+ actions = []
51
+ actions << [:wrap, @range, @insert_before, @insert_after] if !@insert_before.empty? ||
52
+ !@insert_after.empty?
53
+ actions << [:replace, @range, @replacement] if @replacement
54
+ actions.concat(@children.flat_map(&:nested_actions))
55
+ end
56
+
49
57
  def insertion?
50
58
  !insert_before.empty? || !insert_after.empty? || (replacement && !replacement.empty?)
51
59
  end
52
60
 
61
+ ##
62
+ # A root action has its range set to the whole source range, even
63
+ # though it typically do not act on that range.
64
+ # This method returns the action as if it was a child action with
65
+ # its range contracted.
66
+ # @return [Action]
67
+ def contract
68
+ raise 'Empty actions can not be contracted' if empty?
69
+ return self if insertion?
70
+ range = @range.with(
71
+ begin_pos: children.first.range.begin_pos,
72
+ end_pos: children.last.range.end_pos,
73
+ )
74
+ with(range: range)
75
+ end
76
+
77
+ ##
78
+ # @return [Action] that has been moved to the given source_buffer and with the given offset
79
+ # No check is done on validity of resulting range.
80
+ def moved(source_buffer, offset)
81
+ moved_range = ::Parser::Source::Range.new(
82
+ source_buffer,
83
+ @range.begin_pos + offset,
84
+ @range.end_pos + offset
85
+ )
86
+ with(
87
+ range: moved_range,
88
+ children: children.map { |child| child.moved(source_buffer, offset) }
89
+ )
90
+ end
91
+
53
92
  protected
54
93
 
55
94
  attr_reader :children
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Parser
4
- VERSION = '2.7.1.3'
4
+ VERSION = '2.7.1.4'
5
5
  end
@@ -42,7 +42,7 @@ Gem::Specification.new do |spec|
42
42
 
43
43
  spec.required_ruby_version = '>= 2.0.0'
44
44
 
45
- spec.add_dependency 'ast', '~> 2.4.0'
45
+ spec.add_dependency 'ast', '~> 2.4.1'
46
46
 
47
47
  spec.add_development_dependency 'bundler', '>= 1.15', '< 3.0.0'
48
48
  spec.add_development_dependency 'rake', '~> 13.0.1'
@@ -77,3 +77,27 @@ class Parser::AST::Node
77
77
  super
78
78
  end
79
79
  end
80
+
81
+ # Special test extension that records a context of the parser
82
+ # for any node that is created
83
+ module NodeContextExt
84
+ module NodeExt
85
+ attr_reader :context
86
+
87
+ def assign_properties(properties)
88
+ super
89
+
90
+ if (context = properties[:context])
91
+ @context = context
92
+ end
93
+ end
94
+ end
95
+ Parser::AST::Node.prepend(NodeExt)
96
+
97
+ module BuilderExt
98
+ def n(type, children, source_map)
99
+ super.updated(nil, nil, context: @parser.context.stack.dup)
100
+ end
101
+ end
102
+ Parser::Builders::Default.prepend(BuilderExt)
103
+ end
@@ -241,13 +241,13 @@ module ParseHelper
241
241
  with_versions(versions) do |version, parser|
242
242
  source_file = Parser::Source::Buffer.new('(assert_context)', source: code)
243
243
 
244
- begin
245
- parser.parse(source_file)
246
- rescue Parser::SyntaxError
247
- # do nothing; the diagnostic was reported
248
- end
244
+ parsed_ast = parser.parse(source_file)
249
245
 
250
- assert_equal parser.context.stack, context, "(#{version}) parsing context"
246
+ nodes = find_matching_nodes(parsed_ast) { |node| node.type == :send && node.children[1] == :get_context }
247
+ assert_equal 1, nodes.count, "there must exactly 1 `get_context()` call"
248
+
249
+ node = nodes.first
250
+ assert_equal context, node.context, "(#{version}) expect parsing context to match"
251
251
  end
252
252
  end
253
253
 
@@ -310,4 +310,14 @@ module ParseHelper
310
310
  matching_children[index]
311
311
  end
312
312
  end
313
+
314
+ def find_matching_nodes(ast, &block)
315
+ return [] unless ast.is_a?(AST::Node)
316
+
317
+ result = []
318
+ result << ast if block.call(ast)
319
+ ast.children.each { |child| result += find_matching_nodes(child, &block) }
320
+
321
+ result
322
+ end
313
323
  end
@@ -6551,39 +6551,64 @@ class TestParser < Minitest::Test
6551
6551
 
6552
6552
  def test_context_class
6553
6553
  [
6554
- %q{class A;},
6555
- %q{class A < B;}
6554
+ %q{class A; get_context; end},
6555
+ %q{class A < B; get_context; end}
6556
6556
  ].each do |code|
6557
6557
  assert_context([:class], code, ALL_VERSIONS)
6558
6558
  end
6559
6559
  end
6560
6560
 
6561
+ def test_context_module
6562
+ assert_context(
6563
+ [:module],
6564
+ %q{module M; get_context; end},
6565
+ ALL_VERSIONS)
6566
+ end
6567
+
6561
6568
  def test_context_sclass
6562
6569
  assert_context(
6563
6570
  [:sclass],
6564
- %q{class << foo;},
6571
+ %q{class << foo; get_context; end},
6565
6572
  ALL_VERSIONS)
6566
6573
  end
6567
6574
 
6568
6575
  def test_context_def
6569
- assert_context(
6570
- [:def],
6571
- %q{def m;},
6572
- ALL_VERSIONS)
6576
+ [
6577
+ %q{def m; get_context; end},
6578
+ %q{def m(a = get_context); end}
6579
+ ].each do |code|
6580
+ assert_context([:def], code, ALL_VERSIONS)
6581
+ end
6582
+
6583
+ [
6584
+ %q{def m() = get_context},
6585
+ %q{def m(a = get_context) = 42}
6586
+ ].each do |code|
6587
+ assert_context([:def], code, SINCE_2_8)
6588
+ end
6573
6589
  end
6574
6590
 
6575
6591
  def test_context_defs
6576
- assert_context(
6577
- [:defs],
6578
- %q{def foo.m;},
6579
- ALL_VERSIONS)
6592
+ [
6593
+ %q{def foo.m; get_context; end},
6594
+ %q{def foo.m(a = get_context); end}
6595
+ ].each do |code|
6596
+ assert_context([:defs], code, ALL_VERSIONS)
6597
+ end
6598
+
6599
+ [
6600
+ %q{def foo.m() = get_context},
6601
+ %q{def foo.m(a = get_context) = 42}
6602
+ ].each do |code|
6603
+ assert_context([:defs], code, SINCE_2_8)
6604
+ end
6580
6605
  end
6581
6606
 
6582
6607
  def test_context_cmd_brace_block
6583
6608
  [
6584
- 'tap foo {',
6585
- 'foo.tap foo {',
6586
- 'foo::tap foo {'
6609
+ 'tap foo { get_context }',
6610
+ 'foo.tap foo { get_context }',
6611
+ 'foo::tap foo { get_context }'
6587
6612
  ].each do |code|
6588
6613
  assert_context([:block], code, ALL_VERSIONS)
6589
6614
  end
@@ -6591,12 +6616,12 @@ class TestParser < Minitest::Test
6591
6616
 
6592
6617
  def test_context_brace_block
6593
6618
  [
6594
- 'tap {',
6595
- 'foo.tap {',
6596
- 'foo::tap {',
6597
- 'tap do',
6598
- 'foo.tap do',
6599
- 'foo::tap do'
6619
+ 'tap { get_context }',
6620
+ 'foo.tap { get_context }',
6621
+ 'foo::tap { get_context }',
6622
+ 'tap do get_context end',
6623
+ 'foo.tap do get_context end',
6624
+ 'foo::tap do get_context end'
6600
6625
  ].each do |code|
6601
6626
  assert_context([:block], code, ALL_VERSIONS)
6602
6627
  end
@@ -6604,9 +6629,9 @@ class TestParser < Minitest::Test
6604
6629
 
6605
6630
  def test_context_do_block
6606
6631
  [
6607
- %q{tap 1 do},
6608
- %q{foo.tap do},
6609
- %q{foo::tap do}
6632
+ %q{tap 1 do get_context end},
6633
+ %q{foo.tap do get_context end},
6634
+ %q{foo::tap do get_context end}
6610
6635
  ].each do |code|
6611
6636
  assert_context([:block], code, ALL_VERSIONS)
6612
6637
  end
@@ -6614,8 +6639,12 @@ class TestParser < Minitest::Test
6614
6639
 
6615
6640
  def test_context_lambda
6616
6641
  [
6617
- '->() {',
6618
- '->() do'
6642
+ '->() { get_context }',
6643
+ '->() do get_context end',
6644
+ '-> { get_context }',
6645
+ '-> do get_context end',
6646
+ '->(a = get_context) {}',
6647
+ '->(a = get_context) do end'
6619
6648
  ].each do |code|
6620
6649
  assert_context([:lambda], code, SINCE_1_9)
6621
6650
  end
@@ -6623,28 +6652,61 @@ class TestParser < Minitest::Test
6623
6652
 
6624
6653
  def test_context_nested
6625
6654
  assert_context(
6626
- [:class, :sclass, :defs, :def, :block],
6627
- %q{class A; class << foo; def bar.m; def m; tap do},
6655
+ [:class, :module, :sclass, :defs, :def, :block],
6656
+ %q{
6657
+ class A
6658
+ module M
6659
+ class << foo
6660
+ def bar.m
6661
+ def m
6662
+ tap do
6663
+ get_context
6664
+ end
6665
+ end
6666
+ end
6667
+ end
6668
+ end
6669
+ end
6670
+ },
6628
6671
  ALL_VERSIONS)
6629
6672
 
6630
6673
  assert_context(
6631
- [:class, :sclass, :defs, :def, :lambda, :block],
6632
- %q{class A; class << foo; def bar.m; def m; -> do; tap do},
6674
+ [:class, :module, :sclass, :defs, :def, :lambda, :block],
6675
+ %q{
6676
+ class A
6677
+ module M
6678
+ class << foo
6679
+ def bar.m
6680
+ def m
6681
+ -> do
6682
+ tap do
6683
+ get_context
6684
+ end
6685
+ end
6686
+ end
6687
+ end
6688
+ end
6689
+ end
6690
+ end
6691
+ },
6633
6692
  SINCE_1_9)
6634
6693
 
6635
6694
  assert_context(
6636
6695
  [],
6637
6696
  %q{
6638
6697
  class A
6639
- class << foo
6640
- def bar.m
6641
- def m
6642
- tap do
6698
+ module M
6699
+ class << foo
6700
+ def bar.m
6701
+ def m
6702
+ tap do
6703
+ end
6643
6704
  end
6644
6705
  end
6645
6706
  end
6646
6707
  end
6647
6708
  end
6709
+ get_context
6648
6710
  },
6649
6711
  ALL_VERSIONS)
6650
6712
 
@@ -6652,17 +6714,20 @@ class TestParser < Minitest::Test
6652
6714
  [],
6653
6715
  %q{
6654
6716
  class A
6655
- class << foo
6656
- def bar.m
6657
- def m
6658
- -> do
6659
- tap do
6717
+ module M
6718
+ class << foo
6719
+ def bar.m
6720
+ def m
6721
+ -> do
6722
+ tap do
6723
+ end
6660
6724
  end
6661
6725
  end
6662
6726
  end
6663
6727
  end
6664
6728
  end
6665
6729
  end
6730
+ get_context
6666
6731
  },
6667
6732
  SINCE_1_9)
6668
6733
  end
@@ -7746,7 +7811,8 @@ class TestParser < Minitest::Test
7746
7811
  end
7747
7812
  end
7748
7813
 
7749
- def test_forward_args
7814
+ def test_forward_args_legacy
7815
+ Parser::Builders::Default.emit_forward_arg = false
7750
7816
  assert_parses(
7751
7817
  s(:def, :foo,
7752
7818
  s(:forward_args),
@@ -7778,7 +7844,27 @@ class TestParser < Minitest::Test
7778
7844
  %q{def foo(...); end},
7779
7845
  %q{},
7780
7846
  SINCE_2_7)
7847
+ ensure
7848
+ Parser::Builders::Default.emit_forward_arg = true
7849
+ end
7850
+
7851
+ def test_forward_arg
7852
+ assert_parses(
7853
+ s(:def, :foo,
7854
+ s(:args,
7855
+ s(:forward_arg)),
7856
+ s(:send, nil, :bar,
7857
+ s(:forwarded_args))),
7858
+ %q{def foo(...); bar(...); end},
7859
+ %q{ ~ begin (args)
7860
+ | ~~~~~ expression (args)
7861
+ | ~ end (args)
7862
+ | ~~~ expression (args.forward_arg)
7863
+ | ~~~ expression (send.forwarded_args)},
7864
+ SINCE_2_7)
7865
+ end
7781
7866
 
7867
+ def test_forward_args_invalid
7782
7868
  assert_diagnoses(
7783
7869
  [:error, :block_and_blockarg],
7784
7870
  %q{def foo(...) bar(...) { }; end},
@@ -7804,6 +7890,12 @@ class TestParser < Minitest::Test
7804
7890
  %q{ ^^^ location},
7805
7891
  SINCE_2_7)
7806
7892
 
7893
+ assert_diagnoses(
7894
+ [:error, :unexpected_token, { :token => 'tBDOT3' }],
7895
+ %q{def foo(x,y,z); bar(x, y, z, ...); end},
7896
+ %q{ ^^^ location},
7897
+ SINCE_2_8)
7898
+
7807
7899
  assert_diagnoses(
7808
7900
  [:error, :unexpected_token, { :token => 'tBDOT3' }],
7809
7901
  %q{def foo(x,y,z); super(...); end},
@@ -7820,7 +7912,13 @@ class TestParser < Minitest::Test
7820
7912
  [:error, :unexpected_token, { :token => 'tBDOT3' }],
7821
7913
  %q{->(...) {}},
7822
7914
  %q{ ^^^ location},
7823
- SINCE_2_7)
7915
+ ['2.7'])
7916
+
7917
+ assert_diagnoses(
7918
+ [:error, :unexpected_token, { :token => 'tDOT3' }],
7919
+ %q{->(...) {}},
7920
+ %q{ ^^^ location},
7921
+ SINCE_2_8)
7824
7922
 
7825
7923
  # Here and below the parser asssumes that
7826
7924
  # it can be a beginningless range, so the error comes after reducing right paren
@@ -7873,6 +7971,26 @@ class TestParser < Minitest::Test
7873
7971
  SINCE_2_7)
7874
7972
  end
7875
7973
 
7974
+ def test_trailing_forward_arg
7975
+ assert_parses(
7976
+ s(:def, :foo,
7977
+ s(:args,
7978
+ s(:arg, :a),
7979
+ s(:arg, :b),
7980
+ s(:forward_arg)),
7981
+ s(:send, nil, :bar,
7982
+ s(:lvar, :a),
7983
+ s(:int, 42),
7984
+ s(:forwarded_args))),
7985
+ %q{def foo(a, b, ...); bar(a, 42, ...); end},
7986
+ %q{ ~ begin (args)
7987
+ | ~~~~~~~~~~~ expression (args)
7988
+ | ~ end (args)
7989
+ | ~~~ expression (args.forward_arg)},
7990
+ SINCE_2_8)
7991
+ end
7992
+
7993
+
7876
7994
  def test_erange_without_parentheses_at_eol
7877
7995
  assert_diagnoses(
7878
7996
  [:warning, :triple_dot_at_eol],
@@ -8342,7 +8460,7 @@ class TestParser < Minitest::Test
8342
8460
  nil),
8343
8461
  "#{case_pre}#{code}; end",
8344
8462
  source_maps,
8345
- SINCE_2_7
8463
+ versions
8346
8464
  )
8347
8465
  end
8348
8466
 
@@ -9491,7 +9609,10 @@ class TestParser < Minitest::Test
9491
9609
  | ^ assignment
9492
9610
  |~~~~~~~~~~~~~~~~~~~~~~ expression},
9493
9611
  SINCE_2_8)
9612
+ end
9494
9613
 
9614
+ def test_endless_method_forwarded_args_legacy
9615
+ Parser::Builders::Default.emit_forward_arg = false
9495
9616
  assert_parses(
9496
9617
  s(:def_e, :foo,
9497
9618
  s(:forward_args),
@@ -9503,6 +9624,7 @@ class TestParser < Minitest::Test
9503
9624
  | ^ assignment
9504
9625
  |~~~~~~~~~~~~~~~~~~~~~~~ expression},
9505
9626
  SINCE_2_8)
9627
+ Parser::Builders::Default.emit_forward_arg = true
9506
9628
  end
9507
9629
 
9508
9630
  def test_endless_method_without_brackets
@@ -9593,4 +9715,66 @@ class TestParser < Minitest::Test
9593
9715
  %{ ^^ location},
9594
9716
  SINCE_2_8)
9595
9717
  end
9718
+
9719
+ def test_find_pattern
9720
+ assert_parses_pattern_match(
9721
+ s(:in_pattern,
9722
+ s(:find_pattern,
9723
+ s(:match_rest,
9724
+ s(:match_var, :x)),
9725
+ s(:match_as,
9726
+ s(:int, 1),
9727
+ s(:match_var, :a)),
9728
+ s(:match_rest,
9729
+ s(:match_var, :y))),
9730
+ nil,
9731
+ s(:true)),
9732
+ %q{in [*x, 1 => a, *y] then true},
9733
+ %q{ ~~~~~~~~~~~~~~~~ expression (in_pattern.find_pattern)
9734
+ | ~ begin (in_pattern.find_pattern)
9735
+ | ~ end (in_pattern.find_pattern)
9736
+ | ~~ expression (in_pattern.find_pattern.match_rest/1)
9737
+ | ~~ expression (in_pattern.find_pattern.match_rest/2)},
9738
+ SINCE_2_8)
9739
+
9740
+ assert_parses_pattern_match(
9741
+ s(:in_pattern,
9742
+ s(:const_pattern,
9743
+ s(:const, nil, :String),
9744
+ s(:find_pattern,
9745
+ s(:match_rest),
9746
+ s(:int, 1),
9747
+ s(:match_rest))),
9748
+ nil,
9749
+ s(:true)),
9750
+ %q{in String(*, 1, *) then true},
9751
+ %q{ ~~~~~~~ expression (in_pattern.const_pattern.find_pattern)},
9752
+ SINCE_2_8)
9753
+
9754
+ assert_parses_pattern_match(
9755
+ s(:in_pattern,
9756
+ s(:const_pattern,
9757
+ s(:const, nil, :Array),
9758
+ s(:find_pattern,
9759
+ s(:match_rest),
9760
+ s(:int, 1),
9761
+ s(:match_rest))),
9762
+ nil,
9763
+ s(:true)),
9764
+ %q{in Array[*, 1, *] then true},
9765
+ %q{ ~~~~~~~ expression (in_pattern.const_pattern.find_pattern)},
9766
+ SINCE_2_8)
9767
+
9768
+ assert_parses_pattern_match(
9769
+ s(:in_pattern,
9770
+ s(:find_pattern,
9771
+ s(:match_rest),
9772
+ s(:int, 42),
9773
+ s(:match_rest)),
9774
+ nil,
9775
+ s(:true)),
9776
+ %q{in *, 42, * then true},
9777
+ %q{ ~~~~~~~~ expression (in_pattern.find_pattern)},
9778
+ SINCE_2_8)
9779
+ end
9596
9780
  end