parser 2.7.1.3 → 2.7.1.4
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.travis.yml +7 -7
- data/CHANGELOG.md +16 -1
- data/README.md +1 -0
- data/doc/AST_FORMAT.md +56 -2
- data/lib/parser/ast/processor.rb +2 -0
- data/lib/parser/builders/default.rb +50 -3
- data/lib/parser/context.rb +1 -0
- data/lib/parser/lexer.rl +8 -1
- data/lib/parser/macruby.y +14 -4
- data/lib/parser/meta.rb +2 -2
- data/lib/parser/ruby18.y +2 -0
- data/lib/parser/ruby19.y +14 -4
- data/lib/parser/ruby20.y +14 -4
- data/lib/parser/ruby21.y +9 -2
- data/lib/parser/ruby22.y +9 -2
- data/lib/parser/ruby23.y +9 -2
- data/lib/parser/ruby24.y +9 -2
- data/lib/parser/ruby25.y +9 -2
- data/lib/parser/ruby26.y +9 -2
- data/lib/parser/ruby27.y +15 -6
- data/lib/parser/ruby28.y +65 -38
- data/lib/parser/rubymotion.y +14 -4
- data/lib/parser/runner.rb +1 -1
- data/lib/parser/source/range.rb +1 -1
- data/lib/parser/source/tree_rewriter.rb +67 -1
- data/lib/parser/source/tree_rewriter/action.rb +39 -0
- data/lib/parser/version.rb +1 -1
- data/parser.gemspec +1 -1
- data/test/helper.rb +24 -0
- data/test/parse_helper.rb +16 -6
- data/test/test_parser.rb +225 -41
- data/test/test_source_tree_rewriter.rb +109 -11
- metadata +10 -10
data/lib/parser/rubymotion.y
CHANGED
@@ -1018,11 +1018,15 @@ rule
|
|
1018
1018
|
result = @builder.block(val[0],
|
1019
1019
|
begin_t, args, body, end_t)
|
1020
1020
|
}
|
1021
|
-
| tLAMBDA
|
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[
|
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
|
1438
|
+
f_larglist
|
1439
|
+
{
|
1440
|
+
@context.pop
|
1441
|
+
}
|
1442
|
+
lambda_body
|
1433
1443
|
{
|
1434
|
-
result = [ val[1], val[
|
1444
|
+
result = [ val[1], val[3] ]
|
1435
1445
|
|
1436
1446
|
@static_env.unextend
|
1437
1447
|
}
|
data/lib/parser/runner.rb
CHANGED
@@ -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__}"
|
data/lib/parser/source/range.rb
CHANGED
@@ -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
|
data/lib/parser/version.rb
CHANGED
data/parser.gemspec
CHANGED
@@ -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.
|
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'
|
data/test/helper.rb
CHANGED
@@ -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
|
data/test/parse_helper.rb
CHANGED
@@ -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
|
-
|
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
|
-
|
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
|
data/test/test_parser.rb
CHANGED
@@ -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
|
-
|
6570
|
-
|
6571
|
-
%q{def m;}
|
6572
|
-
|
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
|
-
|
6577
|
-
|
6578
|
-
%q{def foo.m;}
|
6579
|
-
|
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{
|
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{
|
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
|
-
|
6640
|
-
|
6641
|
-
def m
|
6642
|
-
|
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
|
-
|
6656
|
-
|
6657
|
-
def m
|
6658
|
-
|
6659
|
-
|
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
|
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
|
-
|
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
|
-
|
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
|