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.
- 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
|