parser 2.6.5.0 → 2.7.0.4

Sign up to get free protection for your applications and to get access to all the features.
@@ -56,11 +56,11 @@ module Parser
56
56
  if action.range == @range
57
57
  merge(action)
58
58
  else
59
- place_in_hierachy(action)
59
+ place_in_hierarchy(action)
60
60
  end
61
61
  end
62
62
 
63
- def place_in_hierachy(action)
63
+ def place_in_hierarchy(action)
64
64
  family = @children.group_by { |child| child.relationship_with(action) }
65
65
 
66
66
  if family[:fusible]
@@ -3,6 +3,8 @@
3
3
  module Parser
4
4
 
5
5
  class StaticEnvironment
6
+ FORWARD_ARGS = :FORWARD_ARGS
7
+
6
8
  def initialize
7
9
  reset
8
10
  end
@@ -41,6 +43,14 @@ module Parser
41
43
  def declared?(name)
42
44
  @variables.include?(name.to_sym)
43
45
  end
46
+
47
+ def declare_forward_args
48
+ declare(FORWARD_ARGS)
49
+ end
50
+
51
+ def declared_forward_args?
52
+ declared?(FORWARD_ARGS)
53
+ end
44
54
  end
45
55
 
46
56
  end
@@ -0,0 +1,32 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Parser
4
+
5
+ class VariablesStack
6
+ def initialize
7
+ @stack = []
8
+ push
9
+ end
10
+
11
+ def push
12
+ @stack << Set.new
13
+ end
14
+
15
+ def pop
16
+ @stack.pop
17
+ end
18
+
19
+ def reset
20
+ @stack.clear
21
+ end
22
+
23
+ def declare(name)
24
+ @stack.last << name.to_sym
25
+ end
26
+
27
+ def declared?(name)
28
+ @stack.last.include?(name.to_sym)
29
+ end
30
+ end
31
+
32
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Parser
4
- VERSION = '2.6.5.0'
4
+ VERSION = '2.7.0.4'
5
5
  end
@@ -13,6 +13,13 @@ Gem::Specification.new do |spec|
13
13
  spec.homepage = 'https://github.com/whitequark/parser'
14
14
  spec.license = 'MIT'
15
15
 
16
+ spec.metadata = {
17
+ 'bug_tracker_uri' => 'https://github.com/whitequark/parser/issues',
18
+ 'changelog_uri' => "https://github.com/whitequark/parser/blob/v#{spec.version}/CHANGELOG.md",
19
+ 'documentation_uri' => "https://www.rubydoc.info/gems/parser/#{spec.version}",
20
+ 'source_code_uri' => "https://github.com/whitequark/parser/tree/v#{spec.version}"
21
+ }
22
+
16
23
  spec.files = `git ls-files`.split + %w(
17
24
  lib/parser/lexer.rb
18
25
  lib/parser/ruby18.rb
@@ -19,6 +19,7 @@ if ENV.include?('COVERAGE') && SimpleCov.usable?
19
19
  ruby24.y
20
20
  ruby25.y
21
21
  ruby26.y
22
+ ruby27.y
22
23
  ),
23
24
  File.expand_path('../../lib/parser', __FILE__))
24
25
 
@@ -127,6 +127,9 @@ module ParseHelper
127
127
 
128
128
  assert parser.instance_eval { @lexer }.cmdarg.empty?,
129
129
  "(#{version}) expected cmdarg to be empty after parsing"
130
+
131
+ assert_equal 0, parser.instance_eval { @lexer.instance_eval { @paren_nest } },
132
+ "(#{version}) expected paren_nest to be 0 after parsing"
130
133
  end
131
134
 
132
135
  # Use like this:
@@ -1507,6 +1507,13 @@ class TestLexer < Minitest::Test
1507
1507
  assert_scanned "||", :tOROP, "||", [0, 2]
1508
1508
  end
1509
1509
 
1510
+ def test_or2__after_27
1511
+ setup_lexer(27)
1512
+ assert_scanned("||",
1513
+ :tPIPE, "|", [0, 1],
1514
+ :tPIPE, "|", [1, 2])
1515
+ end
1516
+
1510
1517
  def test_or2_equals
1511
1518
  assert_scanned "||=", :tOP_ASGN, "||", [0, 3]
1512
1519
  end
@@ -3562,51 +3569,6 @@ class TestLexer < Minitest::Test
3562
3569
  :tIDENTIFIER, 're', [1, 3])
3563
3570
  end
3564
3571
 
3565
- def test_meth_ref
3566
- setup_lexer(27)
3567
-
3568
- assert_scanned('foo.:bar',
3569
- :tIDENTIFIER, 'foo', [0, 3],
3570
- :tMETHREF, '.:', [3, 5],
3571
- :tIDENTIFIER, 'bar', [5, 8])
3572
-
3573
- assert_scanned('foo .:bar',
3574
- :tIDENTIFIER, 'foo', [0, 3],
3575
- :tMETHREF, '.:', [4, 6],
3576
- :tIDENTIFIER, 'bar', [6, 9])
3577
- end
3578
-
3579
- def test_meth_ref_unary_op
3580
- setup_lexer(27)
3581
-
3582
- assert_scanned('foo.:+',
3583
- :tIDENTIFIER, 'foo', [0, 3],
3584
- :tMETHREF, '.:', [3, 5],
3585
- :tPLUS, '+', [5, 6])
3586
-
3587
- assert_scanned('foo.:-@',
3588
- :tIDENTIFIER, 'foo', [0, 3],
3589
- :tMETHREF, '.:', [3, 5],
3590
- :tUMINUS, '-@', [5, 7])
3591
- end
3592
-
3593
- def test_meth_ref_unsupported_newlines
3594
- # MRI emits exactly the same sequence of tokens,
3595
- # the error happens later in the parser
3596
-
3597
- assert_scanned('foo. :+',
3598
- :tIDENTIFIER, 'foo', [0, 3],
3599
- :tDOT, '.', [3, 4],
3600
- :tCOLON, ':', [5, 6],
3601
- :tUPLUS, '+', [6, 7])
3602
-
3603
- assert_scanned('foo.: +',
3604
- :tIDENTIFIER, 'foo', [0, 3],
3605
- :tDOT, '.', [3, 4],
3606
- :tCOLON, ':', [4, 5],
3607
- :tPLUS, '+', [6, 7])
3608
- end
3609
-
3610
3572
  def lex_numbered_parameter(input)
3611
3573
  @lex.max_numparam_stack.push
3612
3574
 
@@ -3643,25 +3605,4 @@ class TestLexer < Minitest::Test
3643
3605
  end
3644
3606
  end
3645
3607
 
3646
- def test_numbered_args_before_27
3647
- setup_lexer(26)
3648
- refute_scanned_numbered_parameter('@1')
3649
- end
3650
-
3651
- def test_numbered_args_27
3652
- setup_lexer(27)
3653
- assert_scanned_numbered_parameter('@1')
3654
- assert_equal(@lex.max_numparam, 1)
3655
-
3656
- setup_lexer(27)
3657
- assert_scanned_numbered_parameter('@9')
3658
- assert_equal(@lex.max_numparam, 9)
3659
-
3660
- setup_lexer(27)
3661
- refute_scanned_numbered_parameter('@10', :too_large_numparam)
3662
-
3663
- setup_lexer(27)
3664
- refute_scanned_numbered_parameter('@01', :leading_zero_in_numparam)
3665
- end
3666
-
3667
3608
  end
@@ -324,7 +324,7 @@ class TestParser < Minitest::Test
324
324
  assert_parses(
325
325
  s(:send, nil, :p,
326
326
  s(:dstr,
327
- s(:str, "x\n"),
327
+ s(:str, "\tx\n"),
328
328
  s(:str, "y\n"))),
329
329
  %Q{p <<~E\n\tx\n y\nE},
330
330
  %q{},
@@ -432,6 +432,14 @@ class TestParser < Minitest::Test
432
432
  SINCE_2_3)
433
433
  end
434
434
 
435
+ def test_parser_bug_640
436
+ assert_parses(
437
+ s(:str, "bazqux\n"),
438
+ %Q{<<~FOO\n baz\\\n qux\nFOO},
439
+ %q{},
440
+ SINCE_2_3)
441
+ end
442
+
435
443
  # Symbols
436
444
 
437
445
  def test_symbol_plain
@@ -2168,7 +2176,7 @@ class TestParser < Minitest::Test
2168
2176
  s(:lvar, :var)),
2169
2177
  %q{def f(var = defined?(var)) var end},
2170
2178
  %q{},
2171
- SINCE_2_1)
2179
+ SINCE_2_7 - SINCE_2_1)
2172
2180
 
2173
2181
  assert_parses(
2174
2182
  s(:def, :f,
@@ -2176,7 +2184,7 @@ class TestParser < Minitest::Test
2176
2184
  s(:lvar, :var)),
2177
2185
  %q{def f(var: defined?(var)) var end},
2178
2186
  %q{},
2179
- SINCE_2_1)
2187
+ SINCE_2_7 - SINCE_2_1)
2180
2188
 
2181
2189
  assert_parses(
2182
2190
  s(:block,
@@ -2477,7 +2485,7 @@ class TestParser < Minitest::Test
2477
2485
  %Q{|;\na\n|},
2478
2486
  SINCE_2_0)
2479
2487
 
2480
- # tOROP
2488
+ # tOROP before 2.7 / tPIPE+tPIPE after
2481
2489
  assert_parses_blockargs(
2482
2490
  s(:args),
2483
2491
  %q{||})
@@ -7214,52 +7222,6 @@ class TestParser < Minitest::Test
7214
7222
  end
7215
7223
  end
7216
7224
 
7217
- def test_meth_ref__27
7218
- assert_parses(
7219
- s(:meth_ref, s(:lvar, :foo), :bar),
7220
- %q{foo.:bar},
7221
- %q{ ^^ dot
7222
- | ~~~ selector
7223
- |~~~~~~~~ expression},
7224
- SINCE_2_7)
7225
-
7226
- assert_parses(
7227
- s(:meth_ref, s(:lvar, :foo), :+@),
7228
- %q{foo.:+@},
7229
- %q{ ^^ dot
7230
- | ~~ selector
7231
- |~~~~~~~ expression},
7232
- SINCE_2_7)
7233
- end
7234
-
7235
- def test_meth_ref__before_27
7236
- assert_diagnoses(
7237
- [:error, :unexpected_token, { :token => 'tCOLON' }],
7238
- %q{foo.:bar},
7239
- %q{ ^ location },
7240
- ALL_VERSIONS - SINCE_2_7)
7241
-
7242
- assert_diagnoses(
7243
- [:error, :unexpected_token, { :token => 'tCOLON' }],
7244
- %q{foo.:+@},
7245
- %q{ ^ location },
7246
- ALL_VERSIONS - SINCE_2_7)
7247
- end
7248
-
7249
- def test_meth_ref_unsupported_newlines
7250
- assert_diagnoses(
7251
- [:error, :unexpected_token, { :token => 'tCOLON' }],
7252
- %Q{foo. :+},
7253
- %q{ ^ location},
7254
- SINCE_2_7)
7255
-
7256
- assert_diagnoses(
7257
- [:error, :unexpected_token, { :token => 'tCOLON' }],
7258
- %Q{foo.: +},
7259
- %q{ ^ location},
7260
- SINCE_2_7)
7261
- end
7262
-
7263
7225
  def test_unterimated_heredoc_id__27
7264
7226
  assert_diagnoses(
7265
7227
  [:error, :unterminated_heredoc_id],
@@ -7282,29 +7244,20 @@ class TestParser < Minitest::Test
7282
7244
  end
7283
7245
  end
7284
7246
 
7285
- def test_numbered_args_before_27
7286
- assert_diagnoses(
7287
- [:error, :ivar_name, { :name => '@1' }],
7288
- %q{m { @1 }},
7289
- %q{ ^^ location},
7290
- ALL_VERSIONS - SINCE_2_7
7291
- )
7292
- end
7293
-
7294
7247
  def test_numbered_args_after_27
7295
7248
  assert_parses(
7296
7249
  s(:numblock,
7297
7250
  s(:send, nil, :m),
7298
7251
  9,
7299
7252
  s(:send,
7300
- s(:numparam, 1), :+,
7301
- s(:numparam, 9))),
7302
- %q{m { @1 + @9 }},
7253
+ s(:lvar, :_1), :+,
7254
+ s(:lvar, :_9))),
7255
+ %q{m { _1 + _9 }},
7303
7256
  %q{^^^^^^^^^^^^^ expression
7304
- | ^^ name (send/2.numparam/1)
7305
- | ^^ expression (send/2.numparam/1)
7306
- | ^^ name (send/2.numparam/2)
7307
- | ^^ expression (send/2.numparam/2)},
7257
+ | ^^ name (send/2.lvar/1)
7258
+ | ^^ expression (send/2.lvar/1)
7259
+ | ^^ name (send/2.lvar/2)
7260
+ | ^^ expression (send/2.lvar/2)},
7308
7261
  SINCE_2_7)
7309
7262
 
7310
7263
  assert_parses(
@@ -7312,14 +7265,14 @@ class TestParser < Minitest::Test
7312
7265
  s(:send, nil, :m),
7313
7266
  9,
7314
7267
  s(:send,
7315
- s(:numparam, 1), :+,
7316
- s(:numparam, 9))),
7317
- %q{m do @1 + @9 end},
7268
+ s(:lvar, :_1), :+,
7269
+ s(:lvar, :_9))),
7270
+ %q{m do _1 + _9 end},
7318
7271
  %q{^^^^^^^^^^^^^^^^ expression
7319
- | ^^ name (send/2.numparam/1)
7320
- | ^^ expression (send/2.numparam/1)
7321
- | ^^ name (send/2.numparam/2)
7322
- | ^^ expression (send/2.numparam/2)},
7272
+ | ^^ name (send/2.lvar/1)
7273
+ | ^^ expression (send/2.lvar/1)
7274
+ | ^^ name (send/2.lvar/2)
7275
+ | ^^ expression (send/2.lvar/2)},
7323
7276
  SINCE_2_7)
7324
7277
 
7325
7278
  # Lambdas
@@ -7329,14 +7282,14 @@ class TestParser < Minitest::Test
7329
7282
  s(:lambda),
7330
7283
  9,
7331
7284
  s(:send,
7332
- s(:numparam, 1), :+,
7333
- s(:numparam, 9))),
7334
- %q{-> { @1 + @9}},
7285
+ s(:lvar, :_1), :+,
7286
+ s(:lvar, :_9))),
7287
+ %q{-> { _1 + _9}},
7335
7288
  %q{^^^^^^^^^^^^^ expression
7336
- | ^^ name (send.numparam/1)
7337
- | ^^ expression (send.numparam/1)
7338
- | ^^ name (send.numparam/2)
7339
- | ^^ expression (send.numparam/2)},
7289
+ | ^^ name (send.lvar/1)
7290
+ | ^^ expression (send.lvar/1)
7291
+ | ^^ name (send.lvar/2)
7292
+ | ^^ expression (send.lvar/2)},
7340
7293
  SINCE_2_7)
7341
7294
 
7342
7295
  assert_parses(
@@ -7344,14 +7297,14 @@ class TestParser < Minitest::Test
7344
7297
  s(:lambda),
7345
7298
  9,
7346
7299
  s(:send,
7347
- s(:numparam, 1), :+,
7348
- s(:numparam, 9))),
7349
- %q{-> do @1 + @9 end},
7300
+ s(:lvar, :_1), :+,
7301
+ s(:lvar, :_9))),
7302
+ %q{-> do _1 + _9 end},
7350
7303
  %q{^^^^^^^^^^^^^^^^^ expression
7351
- | ^^ name (send.numparam/1)
7352
- | ^^ expression (send.numparam/1)
7353
- | ^^ name (send.numparam/2)
7354
- | ^^ expression (send.numparam/2)},
7304
+ | ^^ name (send.lvar/1)
7305
+ | ^^ expression (send.lvar/1)
7306
+ | ^^ name (send.lvar/2)
7307
+ | ^^ expression (send.lvar/2)},
7355
7308
  SINCE_2_7)
7356
7309
  end
7357
7310
 
@@ -7360,37 +7313,37 @@ class TestParser < Minitest::Test
7360
7313
 
7361
7314
  assert_diagnoses(
7362
7315
  [:error, :ordinary_param_defined],
7363
- %q{m { || @1 } },
7316
+ %q{m { || _1 } },
7364
7317
  %q{ ^^ location},
7365
7318
  SINCE_2_7)
7366
7319
 
7367
7320
  assert_diagnoses(
7368
7321
  [:error, :ordinary_param_defined],
7369
- %q{m { |a| @1 } },
7322
+ %q{m { |a| _1 } },
7370
7323
  %q{ ^^ location},
7371
7324
  SINCE_2_7)
7372
7325
 
7373
7326
  assert_diagnoses(
7374
7327
  [:error, :ordinary_param_defined],
7375
- %q{m do || @1 end },
7328
+ %q{m do || _1 end },
7376
7329
  %q{ ^^ location},
7377
7330
  SINCE_2_7)
7378
7331
 
7379
7332
  assert_diagnoses(
7380
7333
  [:error, :ordinary_param_defined],
7381
- %q{m do |a, b| @1 end },
7334
+ %q{m do |a, b| _1 end },
7382
7335
  %q{ ^^ location},
7383
7336
  SINCE_2_7)
7384
7337
 
7385
7338
  assert_diagnoses(
7386
7339
  [:error, :ordinary_param_defined],
7387
- %q{m { |x = @1| }},
7340
+ %q{m { |x = _1| }},
7388
7341
  %q{ ^^ location},
7389
7342
  SINCE_2_7)
7390
7343
 
7391
7344
  assert_diagnoses(
7392
7345
  [:error, :ordinary_param_defined],
7393
- %q{m { |x: @1| }},
7346
+ %q{m { |x: _1| }},
7394
7347
  %q{ ^^ location},
7395
7348
  SINCE_2_7)
7396
7349
 
@@ -7398,77 +7351,161 @@ class TestParser < Minitest::Test
7398
7351
 
7399
7352
  assert_diagnoses(
7400
7353
  [:error, :ordinary_param_defined],
7401
- %q{->() { @1 } },
7354
+ %q{->() { _1 } },
7402
7355
  %q{ ^^ location},
7403
7356
  SINCE_2_7)
7404
7357
 
7405
7358
  assert_diagnoses(
7406
7359
  [:error, :ordinary_param_defined],
7407
- %q{->(a) { @1 } },
7360
+ %q{->(a) { _1 } },
7408
7361
  %q{ ^^ location},
7409
7362
  SINCE_2_7)
7410
7363
 
7411
7364
  assert_diagnoses(
7412
7365
  [:error, :ordinary_param_defined],
7413
- %q{->() do @1 end },
7366
+ %q{->() do _1 end },
7414
7367
  %q{ ^^ location},
7415
7368
  SINCE_2_7)
7416
7369
 
7417
7370
  assert_diagnoses(
7418
7371
  [:error, :ordinary_param_defined],
7419
- %q{->(a, b) do @1 end},
7372
+ %q{->(a, b) do _1 end},
7420
7373
  %q{ ^^ location},
7421
7374
  SINCE_2_7)
7422
7375
 
7423
7376
  assert_diagnoses(
7424
7377
  [:error, :ordinary_param_defined],
7425
- %q{->(x=@1) {}},
7378
+ %q{->(x=_1) {}},
7426
7379
  %q{ ^^ location},
7427
7380
  SINCE_2_7)
7428
7381
 
7429
7382
  assert_diagnoses(
7430
7383
  [:error, :ordinary_param_defined],
7431
- %q{->(x: @1) {}},
7384
+ %q{->(x: _1) {}},
7432
7385
  %q{ ^^ location},
7433
7386
  SINCE_2_7)
7434
7387
 
7435
7388
  assert_diagnoses(
7436
7389
  [:error, :ordinary_param_defined],
7437
- %q{proc {|;a| @1}},
7390
+ %q{proc {|;a| _1}},
7438
7391
  %q{ ^^ location},
7439
7392
  SINCE_2_7)
7440
7393
 
7441
7394
  assert_diagnoses(
7442
7395
  [:error, :ordinary_param_defined],
7443
- "proc {|\n| @1}",
7396
+ "proc {|\n| _1}",
7444
7397
  %q{ ^^ location},
7445
7398
  SINCE_2_7)
7446
7399
  end
7447
7400
 
7448
7401
  def test_numparam_outside_block
7402
+ assert_parses(
7403
+ s(:class,
7404
+ s(:const, nil, :A), nil,
7405
+ s(:send, nil, :_1)),
7406
+ %q{class A; _1; end},
7407
+ %q{},
7408
+ SINCE_2_7)
7409
+
7410
+ assert_parses(
7411
+ s(:module,
7412
+ s(:const, nil, :A),
7413
+ s(:send, nil, :_1)),
7414
+ %q{module A; _1; end},
7415
+ %q{},
7416
+ SINCE_2_7)
7417
+
7418
+ assert_parses(
7419
+ s(:sclass,
7420
+ s(:lvar, :foo),
7421
+ s(:send, nil, :_1)),
7422
+ %q{class << foo; _1; end},
7423
+ %q{},
7424
+ SINCE_2_7)
7425
+
7426
+ assert_parses(
7427
+ s(:defs,
7428
+ s(:self), :m,
7429
+ s(:args),
7430
+ s(:send, nil, :_1)),
7431
+ %q{def self.m; _1; end},
7432
+ %q{},
7433
+ SINCE_2_7)
7434
+
7435
+ assert_parses(
7436
+ s(:send, nil, :_1),
7437
+ %q{_1},
7438
+ %q{},
7439
+ SINCE_2_7)
7440
+ end
7441
+
7442
+ def test_assignment_to_numparams
7443
+ assert_parses(
7444
+ s(:block,
7445
+ s(:send, nil, :proc),
7446
+ s(:args),
7447
+ s(:lvasgn, :_1,
7448
+ s(:nil))),
7449
+ %q{proc {_1 = nil}},
7450
+ %q{},
7451
+ SINCE_2_7)
7452
+
7449
7453
  assert_diagnoses(
7450
- [:error, :numparam_outside_block],
7451
- %q{class A; @1; end},
7452
- %q{ ^^ location},
7454
+ [:error, :cant_assign_to_numparam, { :name => '_1' }],
7455
+ %q{proc {_1; _1 = nil}},
7456
+ %q{ ^^ location},
7453
7457
  SINCE_2_7)
7454
7458
 
7455
7459
  assert_diagnoses(
7456
- [:error, :numparam_outside_block],
7457
- %q{module A; @1; end},
7460
+ [:error, :cant_assign_to_numparam, { :name => '_1' }],
7461
+ %q{proc {_1; _1, foo = [nil, nil]}},
7458
7462
  %q{ ^^ location},
7459
7463
  SINCE_2_7)
7460
7464
 
7461
7465
  assert_diagnoses(
7462
- [:error, :numparam_outside_block],
7463
- %q{class << foo; @1; end},
7464
- %q{ ^^ location},
7466
+ [:error, :cant_assign_to_numparam, { :name => '_1' }],
7467
+ %q{proc {_9; _1 = nil}},
7468
+ %q{ ^^ location},
7465
7469
  SINCE_2_7)
7466
7470
 
7467
7471
  assert_diagnoses(
7468
- [:error, :numparam_outside_block],
7469
- %q{def self.m; @1; end},
7470
- %q{ ^^ location},
7472
+ [:error, :cant_assign_to_numparam, { :name => '_9' }],
7473
+ %q{proc {_1; _9 = nil}},
7474
+ %q{ ^^ location},
7475
+ SINCE_2_7)
7476
+
7477
+ refute_diagnoses(
7478
+ %q{proc { _1 = nil; _1}},
7479
+ SINCE_2_7)
7480
+ end
7481
+
7482
+ def test_numparams_in_nested_blocks
7483
+ assert_diagnoses(
7484
+ [:error, :numparam_used_in_outer_scope],
7485
+ %q{foo { _1; bar { _2 }; }},
7486
+ %q{ ^^ location},
7471
7487
  SINCE_2_7)
7488
+
7489
+ assert_diagnoses(
7490
+ [:error, :numparam_used_in_outer_scope],
7491
+ %q{-> { _1; -> { _2 }; }},
7492
+ %q{ ^^ location},
7493
+ SINCE_2_7)
7494
+
7495
+ [
7496
+ ['class A', 'end'],
7497
+ ['class << foo', 'end'],
7498
+ ['def m', 'end'],
7499
+ ['def self.m', 'end']
7500
+ ].each do |open_scope, close_scope|
7501
+ refute_diagnoses(
7502
+ "proc { _1; #{open_scope}; proc { _2 }; #{close_scope}; }",
7503
+ SINCE_2_7)
7504
+
7505
+ refute_diagnoses(
7506
+ "-> { _1; #{open_scope}; -> { _2 }; #{close_scope}; }",
7507
+ SINCE_2_7)
7508
+ end
7472
7509
  end
7473
7510
 
7474
7511
  def test_ruby_bug_15789
@@ -7480,9 +7517,9 @@ class TestParser < Minitest::Test
7480
7517
  s(:optarg, :a,
7481
7518
  s(:numblock,
7482
7519
  s(:lambda), 1,
7483
- s(:numparam, 1)))),
7520
+ s(:lvar, :_1)))),
7484
7521
  s(:lvar, :a))),
7485
- %q{m ->(a = ->{@1}) {a}},
7522
+ %q{m ->(a = ->{_1}) {a}},
7486
7523
  %q{},
7487
7524
  SINCE_2_7)
7488
7525
 
@@ -7494,9 +7531,9 @@ class TestParser < Minitest::Test
7494
7531
  s(:kwoptarg, :a,
7495
7532
  s(:numblock,
7496
7533
  s(:lambda), 1,
7497
- s(:numparam, 1)))),
7534
+ s(:lvar, :_1)))),
7498
7535
  s(:lvar, :a))),
7499
- %q{m ->(a: ->{@1}) {a}},
7536
+ %q{m ->(a: ->{_1}) {a}},
7500
7537
  %q{},
7501
7538
  SINCE_2_7)
7502
7539
  end
@@ -7607,6 +7644,13 @@ class TestParser < Minitest::Test
7607
7644
  %q{},
7608
7645
  SINCE_2_7)
7609
7646
 
7647
+ assert_parses(
7648
+ s(:send,
7649
+ s(:send, nil, :a), :foo),
7650
+ %Q{a #\n #\n.foo\n},
7651
+ %q{},
7652
+ SINCE_2_7)
7653
+
7610
7654
  assert_parses(
7611
7655
  s(:csend,
7612
7656
  s(:send, nil, :a), :foo),
@@ -7615,9 +7659,9 @@ class TestParser < Minitest::Test
7615
7659
  SINCE_2_7)
7616
7660
 
7617
7661
  assert_parses(
7618
- s(:meth_ref,
7662
+ s(:csend,
7619
7663
  s(:send, nil, :a), :foo),
7620
- %Q{a #\n#\n.:foo\n},
7664
+ %Q{a #\n #\n&.foo\n},
7621
7665
  %q{},
7622
7666
  SINCE_2_7)
7623
7667
  end
@@ -7641,4 +7685,1673 @@ class TestParser < Minitest::Test
7641
7685
  %q{ ^ location},
7642
7686
  ALL_VERSIONS - SINCE_2_7)
7643
7687
  end
7688
+
7689
+ def test_circular_argument_reference_error
7690
+ assert_diagnoses(
7691
+ [:error, :circular_argument_reference, { :var_name => 'foo' }],
7692
+ %q{def m(foo = foo) end},
7693
+ %q{ ^^^ location},
7694
+ SINCE_2_7)
7695
+
7696
+ assert_diagnoses(
7697
+ [:error, :circular_argument_reference, { :var_name => 'foo' }],
7698
+ %q{def m(foo: foo) end},
7699
+ %q{ ^^^ location},
7700
+ SINCE_2_7)
7701
+
7702
+ assert_diagnoses(
7703
+ [:error, :circular_argument_reference, { :var_name => 'foo' }],
7704
+ %q{m { |foo = foo| } },
7705
+ %q{ ^^^ location},
7706
+ SINCE_2_7)
7707
+
7708
+ assert_diagnoses(
7709
+ [:error, :circular_argument_reference, { :var_name => 'foo' }],
7710
+ %q{m { |foo: foo| } },
7711
+ %q{ ^^^ location},
7712
+ SINCE_2_7)
7713
+
7714
+ # Traversing
7715
+
7716
+ assert_diagnoses(
7717
+ [:error, :circular_argument_reference, { :var_name => 'foo' }],
7718
+ %q{def m(foo = class << foo; end) end},
7719
+ %q{ ^^^ location},
7720
+ SINCE_2_7)
7721
+
7722
+ assert_diagnoses(
7723
+ [:error, :circular_argument_reference, { :var_name => 'foo' }],
7724
+ %q{def m(foo = def foo.m; end); end},
7725
+ %q{ ^^^ location},
7726
+ SINCE_2_7)
7727
+
7728
+ assert_diagnoses(
7729
+ [:error, :circular_argument_reference, { :var_name => 'foo' }],
7730
+ %q{m { |foo = proc { 1 + foo }| } },
7731
+ %q{ ^^^ location},
7732
+ SINCE_2_7)
7733
+
7734
+ # Valid cases
7735
+
7736
+ [
7737
+ 'm { |foo = class A; foo; end| }',
7738
+ 'm { |foo = class << self; foo; end| }',
7739
+ 'm { |foo = def m(foo = bar); foo; end| }',
7740
+ 'm { |foo = def m(bar = foo); foo; end| }',
7741
+ 'm { |foo = def self.m(bar = foo); foo; end| }',
7742
+ 'def m(foo = def m; foo; end) end',
7743
+ 'def m(foo = def self.m; foo; end) end',
7744
+ 'm { |foo = proc { |bar| 1 + foo }| }',
7745
+ 'm { |foo = proc { || 1 + foo }| }'
7746
+ ].each do |code|
7747
+ refute_diagnoses(code, SINCE_2_7)
7748
+ end
7749
+ end
7750
+
7751
+ def test_forward_args
7752
+ assert_parses(
7753
+ s(:def, :foo,
7754
+ s(:forward_args),
7755
+ s(:send, nil, :bar,
7756
+ s(:forwarded_args))),
7757
+ %q{def foo(...); bar(...); end},
7758
+ %q{ ~ begin (forward_args)
7759
+ | ~~~~~ expression (forward_args)
7760
+ | ~ end (forward_args)
7761
+ | ~~~ expression (send.forwarded_args)},
7762
+ SINCE_2_7)
7763
+
7764
+ assert_parses(
7765
+ s(:def, :foo,
7766
+ s(:forward_args),
7767
+ s(:super,
7768
+ s(:forwarded_args))),
7769
+ %q{def foo(...); super(...); end},
7770
+ %q{ ~ begin (forward_args)
7771
+ | ~~~~~ expression (forward_args)
7772
+ | ~ end (forward_args)
7773
+ | ~~~ expression (super.forwarded_args)},
7774
+ SINCE_2_7)
7775
+
7776
+ assert_parses(
7777
+ s(:def, :foo,
7778
+ s(:forward_args),
7779
+ nil),
7780
+ %q{def foo(...); end},
7781
+ %q{},
7782
+ SINCE_2_7)
7783
+
7784
+ assert_diagnoses(
7785
+ [:error, :block_and_blockarg],
7786
+ %q{def foo(...) bar(...) { }; end},
7787
+ %q{ ^^^ location
7788
+ | ~ highlights (0)},
7789
+ SINCE_2_7)
7790
+
7791
+ assert_diagnoses(
7792
+ [:error, :unexpected_token, { :token => 'tBDOT3' }],
7793
+ %q{foo do |...| end},
7794
+ %q{ ^^^ location},
7795
+ SINCE_2_7)
7796
+
7797
+ assert_diagnoses(
7798
+ [:error, :unexpected_token, { :token => 'tBDOT3' }],
7799
+ %q{foo { |...| }},
7800
+ %q{ ^^^ location},
7801
+ SINCE_2_7)
7802
+
7803
+ assert_diagnoses(
7804
+ [:error, :unexpected_token, { :token => 'tBDOT3' }],
7805
+ %q{def foo(x,y,z); bar(...); end},
7806
+ %q{ ^^^ location},
7807
+ SINCE_2_7)
7808
+
7809
+ assert_diagnoses(
7810
+ [:error, :unexpected_token, { :token => 'tBDOT3' }],
7811
+ %q{def foo(x,y,z); super(...); end},
7812
+ %q{ ^^^ location},
7813
+ SINCE_2_7)
7814
+
7815
+ assert_diagnoses(
7816
+ [:error, :unexpected_token, { :token => 'tDOT3' }],
7817
+ %q{->... {}},
7818
+ %q{ ^^^ location},
7819
+ SINCE_2_7)
7820
+
7821
+ assert_diagnoses(
7822
+ [:error, :unexpected_token, { :token => 'tBDOT3' }],
7823
+ %q{->(...) {}},
7824
+ %q{ ^^^ location},
7825
+ SINCE_2_7)
7826
+
7827
+ # Here and below the parser asssumes that
7828
+ # it can be a beginningless range, so the error comes after reducing right paren
7829
+ assert_diagnoses(
7830
+ [:error, :unexpected_token, { :token => 'tRPAREN' }],
7831
+ %q{def foo(...); yield(...); end},
7832
+ %q{ ^ location},
7833
+ SINCE_2_7)
7834
+
7835
+ assert_diagnoses(
7836
+ [:error, :unexpected_token, { :token => 'tRPAREN' }],
7837
+ %q{def foo(...); return(...); end},
7838
+ %q{ ^ location},
7839
+ SINCE_2_7)
7840
+
7841
+ assert_diagnoses(
7842
+ [:error, :unexpected_token, { :token => 'tRPAREN' }],
7843
+ %q{def foo(...); a = (...); end},
7844
+ %q{ ^ location},
7845
+ SINCE_2_7)
7846
+
7847
+ assert_diagnoses(
7848
+ [:error, :unexpected_token, { :token => 'tRBRACK' }],
7849
+ %q{def foo(...); [...]; end},
7850
+ %q{ ^ location},
7851
+ SINCE_2_7)
7852
+
7853
+ assert_diagnoses(
7854
+ [:error, :unexpected_token, { :token => 'tRBRACK' }],
7855
+ %q{def foo(...) bar[...]; end},
7856
+ %q{ ^ location},
7857
+ SINCE_2_7)
7858
+
7859
+ assert_diagnoses(
7860
+ [:error, :unexpected_token, { :token => 'tRBRACK' }],
7861
+ %q{def foo(...) bar[...] = x; end},
7862
+ %q{ ^ location},
7863
+ SINCE_2_7)
7864
+
7865
+ assert_diagnoses(
7866
+ [:error, :unexpected_token, { :token => 'tRPAREN' }],
7867
+ %q{def foo(...) defined?(...); end},
7868
+ %q{ ^ location},
7869
+ SINCE_2_7)
7870
+
7871
+ assert_diagnoses(
7872
+ [:error, :unexpected_token, { :token => 'tDOT3' }],
7873
+ %q{def foo ...; end},
7874
+ %q{ ^^^ location},
7875
+ SINCE_2_7)
7876
+ end
7877
+
7878
+ def test_erange_without_parentheses_at_eol
7879
+ assert_diagnoses(
7880
+ [:warning, :triple_dot_at_eol],
7881
+ %Q{1...\n2},
7882
+ %q{ ^^^ location},
7883
+ SINCE_2_7)
7884
+
7885
+ refute_diagnoses('(1...)', SINCE_2_7)
7886
+ refute_diagnoses("(1...\n)", SINCE_2_7)
7887
+ refute_diagnoses("[1...\n]", SINCE_2_7)
7888
+ refute_diagnoses("{a: 1...\n2}", SINCE_2_7)
7889
+ end
7890
+
7891
+ def test_embedded_document_with_eof
7892
+ refute_diagnoses("=begin\n""=end", SINCE_2_7)
7893
+ refute_diagnoses("=begin\n""=end\0", SINCE_2_7)
7894
+ refute_diagnoses("=begin\n""=end\C-d", SINCE_2_7)
7895
+ refute_diagnoses("=begin\n""=end\C-z", SINCE_2_7)
7896
+
7897
+ assert_diagnoses(
7898
+ [:fatal, :embedded_document],
7899
+ "=begin\n",
7900
+ %q{},
7901
+ SINCE_2_7)
7902
+
7903
+ assert_diagnoses(
7904
+ [:fatal, :embedded_document],
7905
+ "=begin",
7906
+ %q{},
7907
+ SINCE_2_7)
7908
+ end
7909
+
7910
+ def test_interp_digit_var
7911
+ # '#@1'
7912
+ assert_parses(
7913
+ s(:str, '#@1'),
7914
+ %q{ '#@1' },
7915
+ %q{},
7916
+ ALL_VERSIONS)
7917
+
7918
+ assert_parses(
7919
+ s(:str, '#@@1'),
7920
+ %q{ '#@@1' },
7921
+ %q{},
7922
+ ALL_VERSIONS)
7923
+
7924
+ # <<-'HERE'
7925
+ # #@1
7926
+ # HERE
7927
+ assert_parses(
7928
+ s(:str, '#@1' + "\n"),
7929
+ %q{<<-'HERE'!#@1!HERE}.gsub('!', "\n"),
7930
+ %q{},
7931
+ ALL_VERSIONS)
7932
+
7933
+ assert_parses(
7934
+ s(:str, '#@@1' + "\n"),
7935
+ %q{<<-'HERE'!#@@1!HERE}.gsub('!', "\n"),
7936
+ %q{},
7937
+ ALL_VERSIONS)
7938
+
7939
+ # %q{#@1}
7940
+ assert_parses(
7941
+ s(:str, '#@1'),
7942
+ %q{ %q{#@1} },
7943
+ %q{},
7944
+ ALL_VERSIONS)
7945
+
7946
+ assert_parses(
7947
+ s(:str, '#@@1'),
7948
+ %q{ %q{#@@1} },
7949
+ %q{},
7950
+ ALL_VERSIONS)
7951
+
7952
+ # "#@1"
7953
+ assert_diagnoses(
7954
+ [:error, :ivar_name, { :name => '@1' }],
7955
+ %q{ "#@1" },
7956
+ %q{ ^^ location},
7957
+ ALL_VERSIONS - SINCE_2_7)
7958
+
7959
+ assert_diagnoses(
7960
+ [:error, :cvar_name, { :name => '@@1' }],
7961
+ %q{ "#@@1" },
7962
+ %q{ ^^^ location},
7963
+ ALL_VERSIONS - SINCE_2_7)
7964
+
7965
+ assert_parses(
7966
+ s(:str, '#@1'),
7967
+ %q{ "#@1" },
7968
+ %q{},
7969
+ SINCE_2_7)
7970
+
7971
+ assert_parses(
7972
+ s(:str, '#@@1'),
7973
+ %q{ "#@@1" },
7974
+ %q{},
7975
+ SINCE_2_7)
7976
+
7977
+ # <<-"HERE"
7978
+ # #@1
7979
+ # HERE
7980
+ assert_diagnoses(
7981
+ [:error, :ivar_name, { :name => '@1' }],
7982
+ %q{ <<-"HERE"!#@1!HERE }.gsub('!', "\n"),
7983
+ %q{ ^^ location},
7984
+ ALL_VERSIONS - SINCE_2_7)
7985
+
7986
+ assert_diagnoses(
7987
+ [:error, :cvar_name, { :name => '@@1' }],
7988
+ %q{ <<-"HERE"!#@@1!HERE }.gsub('!', "\n"),
7989
+ %q{ ^^^ location},
7990
+ ALL_VERSIONS - SINCE_2_7)
7991
+
7992
+ assert_parses(
7993
+ s(:str, '#@1' + "\n"),
7994
+ %q{<<-"HERE"!#@1!HERE}.gsub('!', "\n"),
7995
+ %q{},
7996
+ SINCE_2_7)
7997
+
7998
+ assert_parses(
7999
+ s(:str, '#@@1' + "\n"),
8000
+ %q{<<-"HERE"!#@@1!HERE}.gsub('!', "\n"),
8001
+ %q{},
8002
+ SINCE_2_7)
8003
+
8004
+ # %{#@1}
8005
+ assert_diagnoses(
8006
+ [:error, :ivar_name, { :name => '@1' }],
8007
+ %q{ %{#@1} },
8008
+ %q{ ^^ location},
8009
+ ALL_VERSIONS - SINCE_2_7)
8010
+
8011
+ assert_diagnoses(
8012
+ [:error, :cvar_name, { :name => '@@1' }],
8013
+ %q{ %{#@@1} },
8014
+ %q{ ^^^ location},
8015
+ ALL_VERSIONS - SINCE_2_7)
8016
+
8017
+ assert_parses(
8018
+ s(:str, '#@1'),
8019
+ %q{ %{#@1} },
8020
+ %q{},
8021
+ SINCE_2_7)
8022
+
8023
+ assert_parses(
8024
+ s(:str, '#@@1'),
8025
+ %q{ %{#@@1} },
8026
+ %q{},
8027
+ SINCE_2_7)
8028
+
8029
+ # %Q{#@1}
8030
+ assert_diagnoses(
8031
+ [:error, :ivar_name, { :name => '@1' }],
8032
+ %q{ %Q{#@1} },
8033
+ %q{ ^^ location},
8034
+ ALL_VERSIONS - SINCE_2_7)
8035
+
8036
+ assert_diagnoses(
8037
+ [:error, :cvar_name, { :name => '@@1' }],
8038
+ %q{ %Q{#@@1} },
8039
+ %q{ ^^^ location},
8040
+ ALL_VERSIONS - SINCE_2_7)
8041
+
8042
+ assert_parses(
8043
+ s(:str, '#@1'),
8044
+ %q{ %Q{#@1} },
8045
+ %q{},
8046
+ SINCE_2_7)
8047
+
8048
+ assert_parses(
8049
+ s(:str, '#@@1'),
8050
+ %q{ %Q{#@@1} },
8051
+ %q{},
8052
+ SINCE_2_7)
8053
+
8054
+ # %w[#@1]
8055
+ assert_parses(
8056
+ s(:array,
8057
+ s(:str, '#@1')),
8058
+ %q{ %w[ #@1 ] },
8059
+ %q{},
8060
+ ALL_VERSIONS)
8061
+
8062
+ assert_parses(
8063
+ s(:array,
8064
+ s(:str, '#@@1')),
8065
+ %q{ %w[ #@@1 ] },
8066
+ %q{},
8067
+ ALL_VERSIONS)
8068
+
8069
+ # %W[#@1]
8070
+ assert_diagnoses(
8071
+ [:error, :ivar_name, { :name => '@1' }],
8072
+ %q{ %W[#@1] },
8073
+ %q{ ^^ location},
8074
+ ALL_VERSIONS - SINCE_2_7)
8075
+
8076
+ assert_diagnoses(
8077
+ [:error, :cvar_name, { :name => '@@1' }],
8078
+ %q{ %W[#@@1] },
8079
+ %q{ ^^^ location},
8080
+ ALL_VERSIONS - SINCE_2_7)
8081
+
8082
+ assert_parses(
8083
+ s(:array,
8084
+ s(:str, '#@1')),
8085
+ %q{ %W[#@1] },
8086
+ %q{},
8087
+ SINCE_2_7)
8088
+
8089
+ assert_parses(
8090
+ s(:array,
8091
+ s(:str, '#@@1')),
8092
+ %q{ %W[#@@1] },
8093
+ %q{},
8094
+ SINCE_2_7)
8095
+
8096
+ # %i[#@1]
8097
+ assert_parses(
8098
+ s(:array,
8099
+ s(:sym, :'#@1')),
8100
+ %q{ %i[ #@1 ] },
8101
+ %q{},
8102
+ SINCE_2_0)
8103
+
8104
+ assert_parses(
8105
+ s(:array,
8106
+ s(:sym, :'#@@1')),
8107
+ %q{ %i[ #@@1 ] },
8108
+ %q{},
8109
+ SINCE_2_0)
8110
+
8111
+ # %I[#@1]
8112
+ assert_diagnoses(
8113
+ [:error, :ivar_name, { :name => '@1' }],
8114
+ %q{ %I[#@1] },
8115
+ %q{ ^^ location},
8116
+ SINCE_2_0 - SINCE_2_7)
8117
+
8118
+ assert_diagnoses(
8119
+ [:error, :cvar_name, { :name => '@@1' }],
8120
+ %q{ %I[#@@1] },
8121
+ %q{ ^^^ location},
8122
+ SINCE_2_0 - SINCE_2_7)
8123
+
8124
+ assert_parses(
8125
+ s(:array,
8126
+ s(:sym, :'#@1')),
8127
+ %q{ %I[#@1] },
8128
+ %q{},
8129
+ SINCE_2_7)
8130
+
8131
+ assert_parses(
8132
+ s(:array,
8133
+ s(:sym, :'#@@1')),
8134
+ %q{ %I[#@@1] },
8135
+ %q{},
8136
+ SINCE_2_7)
8137
+
8138
+ # :'#@1'
8139
+ assert_parses(
8140
+ s(:sym, :'#@1'),
8141
+ %q{ :'#@1' },
8142
+ %q{},
8143
+ ALL_VERSIONS)
8144
+
8145
+ assert_parses(
8146
+ s(:sym, :'#@@1'),
8147
+ %q{ :'#@@1' },
8148
+ %q{},
8149
+ ALL_VERSIONS)
8150
+
8151
+ # %s{#@1}
8152
+ assert_parses(
8153
+ s(:sym, :'#@1'),
8154
+ %q{ %s{#@1} },
8155
+ %q{},
8156
+ ALL_VERSIONS)
8157
+
8158
+ assert_parses(
8159
+ s(:sym, :'#@@1'),
8160
+ %q{ %s{#@@1} },
8161
+ %q{},
8162
+ ALL_VERSIONS)
8163
+
8164
+ # :"#@1"
8165
+ assert_diagnoses(
8166
+ [:error, :ivar_name, { :name => '@1' }],
8167
+ %q{ :"#@1" },
8168
+ %q{ ^^ location},
8169
+ ALL_VERSIONS - SINCE_2_7)
8170
+
8171
+ assert_diagnoses(
8172
+ [:error, :cvar_name, { :name => '@@1' }],
8173
+ %q{ :"#@@1" },
8174
+ %q{ ^^^ location},
8175
+ ALL_VERSIONS - SINCE_2_7)
8176
+
8177
+ assert_parses(
8178
+ s(:sym, :'#@1'),
8179
+ %q{ :"#@1" },
8180
+ %q{},
8181
+ SINCE_2_7)
8182
+
8183
+ assert_parses(
8184
+ s(:sym, :'#@@1'),
8185
+ %q{ :"#@@1" },
8186
+ %q{},
8187
+ SINCE_2_7)
8188
+
8189
+ # /#@1/
8190
+ assert_diagnoses(
8191
+ [:error, :ivar_name, { :name => '@1' }],
8192
+ %q{ /#@1/ },
8193
+ %q{ ^^ location},
8194
+ ALL_VERSIONS - SINCE_2_7)
8195
+
8196
+ assert_diagnoses(
8197
+ [:error, :cvar_name, { :name => '@@1' }],
8198
+ %q{ /#@@1/ },
8199
+ %q{ ^^^ location},
8200
+ ALL_VERSIONS - SINCE_2_7)
8201
+
8202
+ assert_parses(
8203
+ s(:regexp,
8204
+ s(:str, '#@1'),
8205
+ s(:regopt)),
8206
+ %q{ /#@1/ },
8207
+ %q{},
8208
+ SINCE_2_7)
8209
+
8210
+ assert_parses(
8211
+ s(:regexp,
8212
+ s(:str, '#@@1'),
8213
+ s(:regopt)),
8214
+ %q{ /#@@1/ },
8215
+ %q{},
8216
+ SINCE_2_7)
8217
+
8218
+ # %r{#@1}
8219
+ assert_diagnoses(
8220
+ [:error, :ivar_name, { :name => '@1' }],
8221
+ %q{ %r{#@1} },
8222
+ %q{ ^^ location},
8223
+ ALL_VERSIONS - SINCE_2_7)
8224
+
8225
+ assert_diagnoses(
8226
+ [:error, :cvar_name, { :name => '@@1' }],
8227
+ %q{ %r{#@@1} },
8228
+ %q{ ^^^ location},
8229
+ ALL_VERSIONS - SINCE_2_7)
8230
+
8231
+ assert_parses(
8232
+ s(:regexp,
8233
+ s(:str, '#@1'),
8234
+ s(:regopt)),
8235
+ %q{ %r{#@1} },
8236
+ %q{},
8237
+ SINCE_2_7)
8238
+
8239
+ assert_parses(
8240
+ s(:regexp,
8241
+ s(:str, '#@@1'),
8242
+ s(:regopt)),
8243
+ %q{ %r{#@@1} },
8244
+ %q{},
8245
+ SINCE_2_7)
8246
+
8247
+ # %x{#@1}
8248
+ assert_diagnoses(
8249
+ [:error, :ivar_name, { :name => '@1' }],
8250
+ %q{ %x{#@1} },
8251
+ %q{ ^^ location},
8252
+ ALL_VERSIONS - SINCE_2_7)
8253
+
8254
+ assert_diagnoses(
8255
+ [:error, :cvar_name, { :name => '@@1' }],
8256
+ %q{ %x{#@@1} },
8257
+ %q{ ^^^ location},
8258
+ ALL_VERSIONS - SINCE_2_7)
8259
+
8260
+ assert_parses(
8261
+ s(:xstr,
8262
+ s(:str, '#@1')),
8263
+ %q{ %x{#@1} },
8264
+ %q{},
8265
+ SINCE_2_7)
8266
+
8267
+ assert_parses(
8268
+ s(:xstr,
8269
+ s(:str, '#@@1')),
8270
+ %q{ %x{#@@1} },
8271
+ %q{},
8272
+ SINCE_2_7)
8273
+
8274
+ # `#@1`
8275
+ assert_diagnoses(
8276
+ [:error, :ivar_name, { :name => '@1' }],
8277
+ %q{ `#@1` },
8278
+ %q{ ^^ location},
8279
+ ALL_VERSIONS - SINCE_2_7)
8280
+
8281
+ assert_diagnoses(
8282
+ [:error, :cvar_name, { :name => '@@1' }],
8283
+ %q{ `#@@1` },
8284
+ %q{ ^^^ location},
8285
+ ALL_VERSIONS - SINCE_2_7)
8286
+
8287
+ assert_parses(
8288
+ s(:xstr,
8289
+ s(:str, '#@1')),
8290
+ %q{ `#@1` },
8291
+ %q{},
8292
+ SINCE_2_7)
8293
+
8294
+ assert_parses(
8295
+ s(:xstr,
8296
+ s(:str, '#@@1')),
8297
+ %q{ `#@@1` },
8298
+ %q{},
8299
+ SINCE_2_7)
8300
+
8301
+ # <<-`HERE`
8302
+ # #@1
8303
+ # HERE
8304
+ assert_diagnoses(
8305
+ [:error, :ivar_name, { :name => '@1' }],
8306
+ %q{ <<-`HERE`!#@1!HERE }.gsub('!', "\n"),
8307
+ %q{ ^^ location},
8308
+ ALL_VERSIONS - SINCE_2_7)
8309
+
8310
+ assert_diagnoses(
8311
+ [:error, :cvar_name, { :name => '@@1' }],
8312
+ %q{ <<-`HERE`!#@@1!HERE }.gsub('!', "\n"),
8313
+ %q{ ^^^ location},
8314
+ ALL_VERSIONS - SINCE_2_7)
8315
+
8316
+ assert_parses(
8317
+ s(:xstr,
8318
+ s(:str, '#@1' + "\n")),
8319
+ %q{<<-`HERE`!#@1!HERE}.gsub('!', "\n"),
8320
+ %q{},
8321
+ SINCE_2_7)
8322
+
8323
+ assert_parses(
8324
+ s(:xstr,
8325
+ s(:str, '#@@1' + "\n")),
8326
+ %q{<<-`HERE`!#@@1!HERE}.gsub('!', "\n"),
8327
+ %q{},
8328
+ SINCE_2_7)
8329
+ end
8330
+
8331
+ def assert_parses_pattern_match(ast, code, source_maps = '', versions = SINCE_2_7)
8332
+ case_pre = "case foo; "
8333
+ source_maps_offset = case_pre.length
8334
+ source_maps_prefix = ' ' * source_maps_offset
8335
+ source_maps = source_maps
8336
+ .lines
8337
+ .map { |line| source_maps_prefix + line.sub(/^\s*\|/, '') }
8338
+ .join("\n")
8339
+
8340
+ assert_parses(
8341
+ s(:case_match,
8342
+ s(:lvar, :foo),
8343
+ ast,
8344
+ nil),
8345
+ "#{case_pre}#{code}; end",
8346
+ source_maps,
8347
+ SINCE_2_7
8348
+ )
8349
+ end
8350
+
8351
+ def test_pattern_matching_single_match
8352
+ assert_parses_pattern_match(
8353
+ s(:in_pattern,
8354
+ s(:match_var, :x),
8355
+ nil,
8356
+ s(:lvar, :x)),
8357
+ %q{in x then x},
8358
+ %q{~~ keyword (in_pattern)
8359
+ |~~~~~~~~~~~ expression (in_pattern)
8360
+ | ~~~~ begin (in_pattern)
8361
+ | ~ expression (in_pattern.match_var)
8362
+ | ~ name (in_pattern.match_var)}
8363
+ )
8364
+ end
8365
+
8366
+ def test_pattern_matching_no_body
8367
+ assert_parses_pattern_match(
8368
+ s(:in_pattern,
8369
+ s(:int, 1), nil, nil),
8370
+ %q{in 1}
8371
+ )
8372
+ end
8373
+
8374
+ def test_pattern_matching_if_unless_modifiers
8375
+ assert_parses_pattern_match(
8376
+ s(:in_pattern,
8377
+ s(:match_var, :x),
8378
+ s(:if_guard, s(:true)),
8379
+ s(:nil)
8380
+ ),
8381
+ %q{in x if true; nil},
8382
+ %q{~~ keyword (in_pattern)
8383
+ |~~~~~~~~~~~~~~~~~ expression (in_pattern)
8384
+ | ~ begin (in_pattern)
8385
+ | ~~ keyword (in_pattern.if_guard)
8386
+ | ~~~~~~~ expression (in_pattern.if_guard)}
8387
+ )
8388
+
8389
+ assert_parses_pattern_match(
8390
+ s(:in_pattern,
8391
+ s(:match_var, :x),
8392
+ s(:unless_guard, s(:true)),
8393
+ s(:nil)
8394
+ ),
8395
+ %q{in x unless true; nil},
8396
+ %q{~~ keyword (in_pattern)
8397
+ |~~~~~~~~~~~~~~~~~~~~~ expression (in_pattern)
8398
+ | ~ begin (in_pattern)
8399
+ | ~~~~~~ keyword (in_pattern.unless_guard)
8400
+ | ~~~~~~~~~~~ expression (in_pattern.unless_guard)}
8401
+ )
8402
+ end
8403
+
8404
+ def test_pattern_matching_pin_variable
8405
+ assert_parses_pattern_match(
8406
+ s(:in_pattern,
8407
+ s(:pin, s(:lvar, :foo)),
8408
+ nil,
8409
+ s(:nil)),
8410
+ %q{in ^foo then nil},
8411
+ %q{ ~ selector (in_pattern.pin)
8412
+ | ~~~~ expression (in_pattern.pin)
8413
+ | ~~~ name (in_pattern.pin.lvar)}
8414
+ )
8415
+ end
8416
+
8417
+ def test_pattern_matching_implicit_array_match
8418
+ assert_parses_pattern_match(
8419
+ s(:in_pattern,
8420
+ s(:array_pattern_with_tail,
8421
+ s(:match_var, :x)),
8422
+ nil,
8423
+ s(:nil)),
8424
+ %q{in x, then nil},
8425
+ %q{ ~ expression (in_pattern.array_pattern_with_tail)}
8426
+ )
8427
+
8428
+ assert_parses_pattern_match(
8429
+ s(:in_pattern,
8430
+ s(:array_pattern,
8431
+ s(:match_rest,
8432
+ s(:match_var, :x))),
8433
+ nil,
8434
+ s(:nil)),
8435
+ %q{in *x then nil},
8436
+ %q{ ~~ expression (in_pattern.array_pattern)
8437
+ | ~ operator (in_pattern.array_pattern.match_rest)
8438
+ | ~ name (in_pattern.array_pattern.match_rest.match_var)}
8439
+ )
8440
+
8441
+ assert_parses_pattern_match(
8442
+ s(:in_pattern,
8443
+ s(:array_pattern,
8444
+ s(:match_rest)),
8445
+ nil,
8446
+ s(:nil)),
8447
+ %q{in * then nil},
8448
+ %q{ ~ expression (in_pattern.array_pattern)
8449
+ | ~ operator (in_pattern.array_pattern.match_rest)}
8450
+ )
8451
+
8452
+ assert_parses_pattern_match(
8453
+ s(:in_pattern,
8454
+ s(:array_pattern,
8455
+ s(:match_var, :x),
8456
+ s(:match_var, :y)),
8457
+ nil,
8458
+ s(:nil)),
8459
+ %q{in x, y then nil},
8460
+ %q{ ~~~~ expression (in_pattern.array_pattern)}
8461
+ )
8462
+
8463
+ assert_parses_pattern_match(
8464
+ s(:in_pattern,
8465
+ s(:array_pattern_with_tail,
8466
+ s(:match_var, :x),
8467
+ s(:match_var, :y)),
8468
+ nil,
8469
+ s(:nil)),
8470
+ %q{in x, y, then nil},
8471
+ %q{ ~~~~ expression (in_pattern.array_pattern_with_tail)}
8472
+ )
8473
+
8474
+ assert_parses_pattern_match(
8475
+ s(:in_pattern,
8476
+ s(:array_pattern,
8477
+ s(:match_var, :x),
8478
+ s(:match_rest, s(:match_var, :y)),
8479
+ s(:match_var, :z)),
8480
+ nil,
8481
+ s(:nil)),
8482
+ %q{in x, *y, z then nil},
8483
+ %q{ ~~~~~~~~ expression (in_pattern.array_pattern)}
8484
+ )
8485
+
8486
+ assert_parses_pattern_match(
8487
+ s(:in_pattern,
8488
+ s(:array_pattern,
8489
+ s(:match_rest, s(:match_var, :x)),
8490
+ s(:match_var, :y),
8491
+ s(:match_var, :z)),
8492
+ nil,
8493
+ s(:nil)),
8494
+ %q{in *x, y, z then nil},
8495
+ %q{ ~~~~~~~~ expression (in_pattern.array_pattern)}
8496
+ )
8497
+
8498
+ assert_parses_pattern_match(
8499
+ s(:in_pattern,
8500
+ s(:array_pattern,
8501
+ s(:int, 1),
8502
+ s(:str, 'a'),
8503
+ s(:array_pattern),
8504
+ s(:hash_pattern)),
8505
+ nil,
8506
+ s(:nil)),
8507
+ %q{in 1, "a", [], {} then nil},
8508
+ %q{ ~~~~~~~~~~~~~~ expression (in_pattern.array_pattern)}
8509
+ )
8510
+ end
8511
+
8512
+ def test_pattern_matching_explicit_array_match
8513
+ assert_parses_pattern_match(
8514
+ s(:in_pattern,
8515
+ s(:array_pattern,
8516
+ s(:match_var, :x)),
8517
+ nil,
8518
+ s(:nil)),
8519
+ %q{in [x] then nil},
8520
+ %q{ ~~~ expression (in_pattern.array_pattern)
8521
+ | ~ begin (in_pattern.array_pattern)
8522
+ | ~ end (in_pattern.array_pattern)}
8523
+ )
8524
+
8525
+ assert_parses_pattern_match(
8526
+ s(:in_pattern,
8527
+ s(:array_pattern_with_tail,
8528
+ s(:match_var, :x)),
8529
+ nil,
8530
+ s(:nil)),
8531
+ %q{in [x,] then nil},
8532
+ %q{ ~~~~ expression (in_pattern.array_pattern_with_tail)
8533
+ | ~ begin (in_pattern.array_pattern_with_tail)
8534
+ | ~ end (in_pattern.array_pattern_with_tail)}
8535
+ )
8536
+
8537
+ assert_parses_pattern_match(
8538
+ s(:in_pattern,
8539
+ s(:array_pattern,
8540
+ s(:match_var, :x),
8541
+ s(:match_var, :y)),
8542
+ nil,
8543
+ s(:true)),
8544
+ %q{in [x, y] then true},
8545
+ %q{ ~~~~~~ expression (in_pattern.array_pattern)
8546
+ | ~ begin (in_pattern.array_pattern)
8547
+ | ~ end (in_pattern.array_pattern)}
8548
+ )
8549
+
8550
+ assert_parses_pattern_match(
8551
+ s(:in_pattern,
8552
+ s(:array_pattern_with_tail,
8553
+ s(:match_var, :x),
8554
+ s(:match_var, :y)),
8555
+ nil,
8556
+ s(:true)),
8557
+ %q{in [x, y,] then true},
8558
+ %q{ ~~~~~~~ expression (in_pattern.array_pattern_with_tail)
8559
+ | ~ begin (in_pattern.array_pattern_with_tail)
8560
+ | ~ end (in_pattern.array_pattern_with_tail)}
8561
+ )
8562
+
8563
+ assert_parses_pattern_match(
8564
+ s(:in_pattern,
8565
+ s(:array_pattern,
8566
+ s(:match_var, :x),
8567
+ s(:match_var, :y),
8568
+ s(:match_rest)),
8569
+ nil,
8570
+ s(:true)),
8571
+ %q{in [x, y, *] then true},
8572
+ %q{ ~~~~~~~~~ expression (in_pattern.array_pattern)
8573
+ | ~ begin (in_pattern.array_pattern)
8574
+ | ~ end (in_pattern.array_pattern)}
8575
+ )
8576
+
8577
+ assert_parses_pattern_match(
8578
+ s(:in_pattern,
8579
+ s(:array_pattern,
8580
+ s(:match_var, :x),
8581
+ s(:match_var, :y),
8582
+ s(:match_rest, s(:match_var, :z))),
8583
+ nil,
8584
+ s(:true)),
8585
+ %q{in [x, y, *z] then true},
8586
+ %q{ ~~~~~~~~~~ expression (in_pattern.array_pattern)
8587
+ | ~ begin (in_pattern.array_pattern)
8588
+ | ~ end (in_pattern.array_pattern)}
8589
+ )
8590
+
8591
+ assert_parses_pattern_match(
8592
+ s(:in_pattern,
8593
+ s(:array_pattern,
8594
+ s(:match_var, :x),
8595
+ s(:match_rest, s(:match_var, :y)),
8596
+ s(:match_var, :z)),
8597
+ nil,
8598
+ s(:true)),
8599
+ %q{in [x, *y, z] then true},
8600
+ %q{ ~~~~~~~~~~ expression (in_pattern.array_pattern)
8601
+ | ~ begin (in_pattern.array_pattern)
8602
+ | ~ end (in_pattern.array_pattern)}
8603
+ )
8604
+
8605
+ assert_parses_pattern_match(
8606
+ s(:in_pattern,
8607
+ s(:array_pattern,
8608
+ s(:match_var, :x),
8609
+ s(:match_rest),
8610
+ s(:match_var, :y)),
8611
+ nil,
8612
+ s(:true)),
8613
+ %q{in [x, *, y] then true},
8614
+ %q{ ~~~~~~~~~ expression (in_pattern.array_pattern)
8615
+ | ~ begin (in_pattern.array_pattern)
8616
+ | ~ end (in_pattern.array_pattern)}
8617
+ )
8618
+
8619
+ assert_parses_pattern_match(
8620
+ s(:in_pattern,
8621
+ s(:array_pattern,
8622
+ s(:match_rest, s(:match_var, :x)),
8623
+ s(:match_var, :y)),
8624
+ nil,
8625
+ s(:true)),
8626
+ %q{in [*x, y] then true},
8627
+ %q{ ~~~~~~~ expression (in_pattern.array_pattern)
8628
+ | ~ begin (in_pattern.array_pattern)
8629
+ | ~ end (in_pattern.array_pattern)}
8630
+ )
8631
+
8632
+ assert_parses_pattern_match(
8633
+ s(:in_pattern,
8634
+ s(:array_pattern,
8635
+ s(:match_rest),
8636
+ s(:match_var, :x)),
8637
+ nil,
8638
+ s(:true)),
8639
+ %q{in [*, x] then true},
8640
+ %q{ ~~~~~~ expression (in_pattern.array_pattern)
8641
+ | ~ begin (in_pattern.array_pattern)
8642
+ | ~ end (in_pattern.array_pattern)}
8643
+ )
8644
+ end
8645
+
8646
+ def test_pattern_matching_hash
8647
+ assert_parses_pattern_match(
8648
+ s(:in_pattern,
8649
+ s(:hash_pattern),
8650
+ nil,
8651
+ s(:true)),
8652
+ %q{in {} then true},
8653
+ %q{ ~~ expression (in_pattern.hash_pattern)}
8654
+ )
8655
+
8656
+ assert_parses_pattern_match(
8657
+ s(:in_pattern,
8658
+ s(:hash_pattern,
8659
+ s(:pair, s(:sym, :a), s(:int, 1))),
8660
+ nil,
8661
+ s(:true)),
8662
+ %q{in a: 1 then true},
8663
+ %q{ ~~~~ expression (in_pattern.hash_pattern)}
8664
+ )
8665
+
8666
+ assert_parses_pattern_match(
8667
+ s(:in_pattern,
8668
+ s(:hash_pattern,
8669
+ s(:pair, s(:sym, :a), s(:int, 1))),
8670
+ nil,
8671
+ s(:true)),
8672
+ %q{in { a: 1 } then true},
8673
+ %q{ ~~~~~~~~ expression (in_pattern.hash_pattern)
8674
+ | ~ begin (in_pattern.hash_pattern)
8675
+ | ~ end (in_pattern.hash_pattern)}
8676
+ )
8677
+
8678
+ assert_parses_pattern_match(
8679
+ s(:in_pattern,
8680
+ s(:hash_pattern,
8681
+ s(:match_var, :a)),
8682
+ nil,
8683
+ s(:true)),
8684
+ %q{in a: then true},
8685
+ %q{ ~~ expression (in_pattern.hash_pattern)
8686
+ | ~ name (in_pattern.hash_pattern.match_var)
8687
+ | ~~ expression (in_pattern.hash_pattern.match_var)}
8688
+ )
8689
+
8690
+ assert_parses_pattern_match(
8691
+ s(:in_pattern,
8692
+ s(:hash_pattern,
8693
+ s(:match_rest, s(:match_var, :a))),
8694
+ nil,
8695
+ s(:true)),
8696
+ %q{in **a then true},
8697
+ %q{ ~~~ expression (in_pattern.hash_pattern)
8698
+ | ~~~ expression (in_pattern.hash_pattern.match_rest)
8699
+ | ~~ operator (in_pattern.hash_pattern.match_rest)
8700
+ | ~ expression (in_pattern.hash_pattern.match_rest.match_var)
8701
+ | ~ name (in_pattern.hash_pattern.match_rest.match_var)}
8702
+ )
8703
+
8704
+ assert_parses_pattern_match(
8705
+ s(:in_pattern,
8706
+ s(:hash_pattern,
8707
+ s(:match_rest)),
8708
+ nil,
8709
+ s(:true)),
8710
+ %q{in ** then true},
8711
+ %q{ ~~ expression (in_pattern.hash_pattern)
8712
+ | ~~ expression (in_pattern.hash_pattern.match_rest)
8713
+ | ~~ operator (in_pattern.hash_pattern.match_rest)}
8714
+ )
8715
+
8716
+ assert_parses_pattern_match(
8717
+ s(:in_pattern,
8718
+ s(:hash_pattern,
8719
+ s(:pair, s(:sym, :a), s(:int, 1)),
8720
+ s(:pair, s(:sym, :b), s(:int, 2))),
8721
+ nil,
8722
+ s(:true)),
8723
+ %q{in a: 1, b: 2 then true},
8724
+ %q{ ~~~~~~~~~~ expression (in_pattern.hash_pattern)}
8725
+ )
8726
+
8727
+ assert_parses_pattern_match(
8728
+ s(:in_pattern,
8729
+ s(:hash_pattern,
8730
+ s(:match_var, :a),
8731
+ s(:match_var, :b)),
8732
+ nil,
8733
+ s(:true)),
8734
+ %q{in a:, b: then true},
8735
+ %q{ ~~~~~~ expression (in_pattern.hash_pattern)}
8736
+ )
8737
+
8738
+ assert_parses_pattern_match(
8739
+ s(:in_pattern,
8740
+ s(:hash_pattern,
8741
+ s(:pair, s(:sym, :a), s(:int, 1)),
8742
+ s(:match_var, :_a),
8743
+ s(:match_rest)),
8744
+ nil,
8745
+ s(:true)),
8746
+ %q{in a: 1, _a:, ** then true},
8747
+ %q{ ~~~~~~~~~~~~~ expression (in_pattern.hash_pattern)}
8748
+ )
8749
+ end
8750
+
8751
+ def test_pattern_matching_hash_with_string_keys
8752
+ # Match + assign
8753
+
8754
+ assert_parses_pattern_match(
8755
+ s(:in_pattern,
8756
+ s(:hash_pattern,
8757
+ s(:match_var, :a)),
8758
+ nil,
8759
+ s(:true)),
8760
+ %q{in "a": then true},
8761
+ %q{ ~~~~ expression (in_pattern.hash_pattern.match_var)
8762
+ | ~ name (in_pattern.hash_pattern.match_var)}
8763
+ )
8764
+
8765
+ assert_parses_pattern_match(
8766
+ s(:in_pattern,
8767
+ s(:hash_pattern,
8768
+ s(:match_var, :a)),
8769
+ nil,
8770
+ s(:true)),
8771
+ %q{in "#{ 'a' }": then true},
8772
+ %q{ ~~~~~~~~~~~ expression (in_pattern.hash_pattern.match_var)
8773
+ | ~ name (in_pattern.hash_pattern.match_var)}
8774
+ )
8775
+
8776
+ assert_parses_pattern_match(
8777
+ s(:in_pattern,
8778
+ s(:hash_pattern,
8779
+ s(:match_var, :a)),
8780
+ nil,
8781
+ s(:true)),
8782
+ %q{in "#{ %q{a} }": then true},
8783
+ %q{ ~~~~~~~~~~~~~ expression (in_pattern.hash_pattern.match_var)
8784
+ | ~ name (in_pattern.hash_pattern.match_var)}
8785
+ )
8786
+
8787
+ assert_parses_pattern_match(
8788
+ s(:in_pattern,
8789
+ s(:hash_pattern,
8790
+ s(:match_var, :a)),
8791
+ nil,
8792
+ s(:true)),
8793
+ %q{in "#{ %Q{a} }": then true},
8794
+ %q{ ~~~~~~~~~~~~~ expression (in_pattern.hash_pattern.match_var)
8795
+ | ~ name (in_pattern.hash_pattern.match_var)}
8796
+ )
8797
+
8798
+ # Only match
8799
+
8800
+ assert_parses_pattern_match(
8801
+ s(:in_pattern,
8802
+ s(:hash_pattern,
8803
+ s(:pair, s(:sym, :a), s(:int, 1))),
8804
+ nil,
8805
+ s(:true)),
8806
+ %q{in "a": 1 then true},
8807
+ )
8808
+
8809
+ assert_parses_pattern_match(
8810
+ s(:in_pattern,
8811
+ s(:hash_pattern,
8812
+ s(:pair,
8813
+ s(:dsym, s(:begin, s(:str, "a"))),
8814
+ s(:int, 1))),
8815
+ nil,
8816
+ s(:true)),
8817
+ %q{in "#{ 'a' }": 1 then true},
8818
+ )
8819
+
8820
+ assert_parses_pattern_match(
8821
+ s(:in_pattern,
8822
+ s(:hash_pattern,
8823
+ s(:pair,
8824
+ s(:dsym, s(:begin, s(:str, "a"))),
8825
+ s(:int, 1))),
8826
+ nil,
8827
+ s(:true)),
8828
+ %q{in "#{ %q{a} }": 1 then true},
8829
+ )
8830
+
8831
+ assert_parses_pattern_match(
8832
+ s(:in_pattern,
8833
+ s(:hash_pattern,
8834
+ s(:pair,
8835
+ s(:dsym, s(:begin, s(:str, "a"))),
8836
+ s(:int, 1))),
8837
+ nil,
8838
+ s(:true)),
8839
+ %q{in "#{ %Q{a} }": 1 then true},
8840
+ )
8841
+ end
8842
+
8843
+ def test_pattern_matching_hash_with_heredoc_keys
8844
+ # Ruby <3, the following case is acceptable by the MRI's grammar,
8845
+ # so it has to be reducable by parser.
8846
+ # We have a code for that in the builder.rb that reject it via
8847
+ # diagnostic error because of the wrong lvar name
8848
+ assert_diagnoses(
8849
+ [:error, :lvar_name, { name: "a\n" }],
8850
+ %Q{case nil; in "\#{ <<-HERE }":;\na\nHERE\nelse\nend},
8851
+ %q{ ~~~~~~~ location},
8852
+ SINCE_2_7
8853
+ )
8854
+ end
8855
+
8856
+ def test_pattern_matching_hash_with_string_interpolation_keys
8857
+ assert_diagnoses(
8858
+ [:error, :pm_interp_in_var_name],
8859
+ %q{case a; in "#{a}": 1; end},
8860
+ %q{ ~~~~~~~ location},
8861
+ SINCE_2_7
8862
+ )
8863
+ end
8864
+
8865
+ def test_pattern_matching_keyword_variable
8866
+ assert_parses_pattern_match(
8867
+ s(:in_pattern,
8868
+ s(:self),
8869
+ nil,
8870
+ s(:true)),
8871
+ %q{in self then true}
8872
+ )
8873
+ end
8874
+
8875
+ def test_pattern_matching_lambda
8876
+ assert_parses_pattern_match(
8877
+ s(:in_pattern,
8878
+ s(:block,
8879
+ s(:lambda),
8880
+ s(:args),
8881
+ s(:int, 42)),
8882
+ nil,
8883
+ s(:true)),
8884
+ %q{in ->{ 42 } then true}
8885
+ )
8886
+ end
8887
+
8888
+ def test_pattern_matching_ranges
8889
+ assert_parses_pattern_match(
8890
+ s(:in_pattern,
8891
+ s(:irange, s(:int, 1), s(:int, 2)),
8892
+ nil,
8893
+ s(:true)),
8894
+ %q{in 1..2 then true}
8895
+ )
8896
+
8897
+ assert_parses_pattern_match(
8898
+ s(:in_pattern,
8899
+ s(:irange, s(:int, 1), nil),
8900
+ nil,
8901
+ s(:true)),
8902
+ %q{in 1.. then true}
8903
+ )
8904
+
8905
+ assert_parses_pattern_match(
8906
+ s(:in_pattern,
8907
+ s(:irange, nil, s(:int, 2)),
8908
+ nil,
8909
+ s(:true)),
8910
+ %q{in ..2 then true}
8911
+ )
8912
+
8913
+ assert_parses_pattern_match(
8914
+ s(:in_pattern,
8915
+ s(:erange, s(:int, 1), s(:int, 2)),
8916
+ nil,
8917
+ s(:true)),
8918
+ %q{in 1...2 then true}
8919
+ )
8920
+
8921
+ assert_parses_pattern_match(
8922
+ s(:in_pattern,
8923
+ s(:erange, s(:int, 1), nil),
8924
+ nil,
8925
+ s(:true)),
8926
+ %q{in 1... then true}
8927
+ )
8928
+
8929
+ assert_parses_pattern_match(
8930
+ s(:in_pattern,
8931
+ s(:erange, nil, s(:int, 2)),
8932
+ nil,
8933
+ s(:true)),
8934
+ %q{in ...2 then true}
8935
+ )
8936
+ end
8937
+
8938
+ def test_pattern_matching_expr_in_paren
8939
+ assert_parses_pattern_match(
8940
+ s(:in_pattern,
8941
+ s(:begin, s(:int, 1)),
8942
+ nil,
8943
+ s(:true)),
8944
+ %q{in (1) then true},
8945
+ %q{ ~~~ expression (in_pattern.begin)
8946
+ | ~ begin (in_pattern.begin)
8947
+ | ~ end (in_pattern.begin)}
8948
+ )
8949
+ end
8950
+
8951
+ def test_pattern_matching_constants
8952
+ assert_parses_pattern_match(
8953
+ s(:in_pattern,
8954
+ s(:const, nil, :A),
8955
+ nil,
8956
+ s(:true)),
8957
+ %q{in A then true},
8958
+ %q{ ~ expression (in_pattern.const)
8959
+ | ~ name (in_pattern.const)}
8960
+ )
8961
+
8962
+ assert_parses_pattern_match(
8963
+ s(:in_pattern,
8964
+ s(:const, s(:const, nil, :A), :B),
8965
+ nil,
8966
+ s(:true)),
8967
+ %q{in A::B then true},
8968
+ %q{ ~~~~ expression (in_pattern.const)
8969
+ | ~~ double_colon (in_pattern.const)
8970
+ | ~ name (in_pattern.const)}
8971
+ )
8972
+
8973
+ assert_parses_pattern_match(
8974
+ s(:in_pattern,
8975
+ s(:const, s(:cbase), :A),
8976
+ nil,
8977
+ s(:true)),
8978
+ %q{in ::A then true},
8979
+ %q{ ~~~ expression (in_pattern.const)
8980
+ | ~~ double_colon (in_pattern.const)
8981
+ | ~ name (in_pattern.const)}
8982
+ )
8983
+ end
8984
+
8985
+ def test_pattern_matching_const_pattern
8986
+ assert_parses_pattern_match(
8987
+ s(:in_pattern,
8988
+ s(:const_pattern,
8989
+ s(:const, nil, :A),
8990
+ s(:array_pattern,
8991
+ s(:int, 1),
8992
+ s(:int, 2))),
8993
+ nil,
8994
+ s(:true)),
8995
+ %q{in A(1, 2) then true},
8996
+ %q{ ~~~~~~ expression (in_pattern.const_pattern)
8997
+ | ~ begin (in_pattern.const_pattern)
8998
+ | ~ end (in_pattern.const_pattern)
8999
+ | ~ expression (in_pattern.const_pattern.const)
9000
+ | ~~~~ expression (in_pattern.const_pattern.array_pattern)}
9001
+ )
9002
+
9003
+ assert_parses_pattern_match(
9004
+ s(:in_pattern,
9005
+ s(:const_pattern,
9006
+ s(:const, nil, :A),
9007
+ s(:hash_pattern,
9008
+ s(:match_var, :x))),
9009
+ nil,
9010
+ s(:true)),
9011
+ %q{in A(x:) then true},
9012
+ %q{ ~~~~ expression (in_pattern.const_pattern)
9013
+ | ~ begin (in_pattern.const_pattern)
9014
+ | ~ end (in_pattern.const_pattern)
9015
+ | ~ expression (in_pattern.const_pattern.const)
9016
+ | ~~ expression (in_pattern.const_pattern.hash_pattern)}
9017
+ )
9018
+
9019
+ assert_parses_pattern_match(
9020
+ s(:in_pattern,
9021
+ s(:const_pattern,
9022
+ s(:const, nil, :A),
9023
+ s(:array_pattern)),
9024
+ nil,
9025
+ s(:true)),
9026
+ %q{in A() then true},
9027
+ %q{ ~~ expression (in_pattern.const_pattern)
9028
+ | ~ begin (in_pattern.const_pattern)
9029
+ | ~ end (in_pattern.const_pattern)
9030
+ | ~ expression (in_pattern.const_pattern.const)
9031
+ | ~~ expression (in_pattern.const_pattern.array_pattern)}
9032
+ )
9033
+
9034
+ assert_parses_pattern_match(
9035
+ s(:in_pattern,
9036
+ s(:const_pattern,
9037
+ s(:const, nil, :A),
9038
+ s(:array_pattern,
9039
+ s(:int, 1),
9040
+ s(:int, 2))),
9041
+ nil,
9042
+ s(:true)),
9043
+ %q{in A[1, 2] then true},
9044
+ %q{ ~~~~~~ expression (in_pattern.const_pattern)
9045
+ | ~ begin (in_pattern.const_pattern)
9046
+ | ~ end (in_pattern.const_pattern)
9047
+ | ~ expression (in_pattern.const_pattern.const)
9048
+ | ~~~~ expression (in_pattern.const_pattern.array_pattern)}
9049
+ )
9050
+
9051
+ assert_parses_pattern_match(
9052
+ s(:in_pattern,
9053
+ s(:const_pattern,
9054
+ s(:const, nil, :A),
9055
+ s(:hash_pattern,
9056
+ s(:match_var, :x))),
9057
+ nil,
9058
+ s(:true)),
9059
+ %q{in A[x:] then true},
9060
+ %q{ ~~~~ expression (in_pattern.const_pattern)
9061
+ | ~ begin (in_pattern.const_pattern)
9062
+ | ~ end (in_pattern.const_pattern)
9063
+ | ~ expression (in_pattern.const_pattern.const)
9064
+ | ~~ expression (in_pattern.const_pattern.hash_pattern)}
9065
+ )
9066
+
9067
+ assert_parses_pattern_match(
9068
+ s(:in_pattern,
9069
+ s(:const_pattern,
9070
+ s(:const, nil, :A),
9071
+ s(:array_pattern)),
9072
+ nil,
9073
+ s(:true)),
9074
+ %q{in A[] then true},
9075
+ %q{ ~~ expression (in_pattern.const_pattern)
9076
+ | ~ begin (in_pattern.const_pattern)
9077
+ | ~ end (in_pattern.const_pattern)
9078
+ | ~~ expression (in_pattern.const_pattern.array_pattern)}
9079
+ )
9080
+ end
9081
+
9082
+ def test_pattern_matching_match_alt
9083
+ assert_parses_pattern_match(
9084
+ s(:in_pattern,
9085
+ s(:match_alt, s(:int, 1), s(:int, 2)),
9086
+ nil,
9087
+ s(:true)),
9088
+ %q{in 1 | 2 then true},
9089
+ %q{ ~~~~~ expression (in_pattern.match_alt)
9090
+ | ~ operator (in_pattern.match_alt)}
9091
+ )
9092
+ end
9093
+
9094
+ def test_pattern_matching_match_as
9095
+ assert_parses_pattern_match(
9096
+ s(:in_pattern,
9097
+ s(:match_as,
9098
+ s(:int, 1),
9099
+ s(:match_var, :a)),
9100
+ nil,
9101
+ s(:true)),
9102
+ %q{in 1 => a then true},
9103
+ %q{ ~~~~~~ expression (in_pattern.match_as)
9104
+ | ~~ operator (in_pattern.match_as)}
9105
+ )
9106
+ end
9107
+
9108
+ def test_pattern_matching_else
9109
+ assert_parses(
9110
+ s(:case_match,
9111
+ s(:int, 1),
9112
+ s(:in_pattern,
9113
+ s(:int, 2), nil,
9114
+ s(:int, 3)),
9115
+ s(:int, 4)),
9116
+ %q{case 1; in 2; 3; else; 4; end},
9117
+ %q{ ~~~~ else},
9118
+ SINCE_2_7
9119
+ )
9120
+ end
9121
+
9122
+ def test_pattern_matching_blank_else
9123
+ assert_parses(
9124
+ s(:case_match,
9125
+ s(:int, 1),
9126
+ s(:in_pattern,
9127
+ s(:int, 2), nil,
9128
+ s(:int, 3)),
9129
+ s(:empty_else)),
9130
+ %q{case 1; in 2; 3; else; end},
9131
+ %q{ ~~~~ else},
9132
+ SINCE_2_7
9133
+ )
9134
+ end
9135
+
9136
+ def assert_pattern_matching_defines_local_variables(match_code, lvar_names, versions = SINCE_2_7)
9137
+ code = "case 1; #{match_code}; then [#{lvar_names.join(', ')}]; end"
9138
+
9139
+ with_versions(versions) do |version, parser|
9140
+ source_file = Parser::Source::Buffer.new('(assert_context)')
9141
+ source_file.source = code
9142
+
9143
+ lvar_names.each do |lvar_name|
9144
+ refute parser.static_env.declared?(lvar_name),
9145
+ "(#{version}) local variable #{lvar_name.to_s.inspect} has to be undefined before asserting"
9146
+ end
9147
+
9148
+ before = parser.static_env.instance_variable_get(:@variables).to_a
9149
+
9150
+ begin
9151
+ parsed_ast = parser.parse(source_file)
9152
+ rescue Parser::SyntaxError => exc
9153
+ backtrace = exc.backtrace
9154
+ Exception.instance_method(:initialize).bind(exc).
9155
+ call("(#{version}) #{exc.message}")
9156
+ exc.set_backtrace(backtrace)
9157
+ raise
9158
+ end
9159
+
9160
+ lvar_names.each do |lvar_name|
9161
+ assert parser.static_env.declared?(lvar_name),
9162
+ "(#{version}) expected local variable #{lvar_name.to_s.inspect} to be defined after parsing"
9163
+ end
9164
+
9165
+ after = parser.static_env.instance_variable_get(:@variables).to_a
9166
+ extra = after - before - lvar_names
9167
+
9168
+ assert extra.empty?,
9169
+ "(#{version}) expected only #{lvar_names.inspect} " \
9170
+ "to be defined during parsing, but also got #{extra.inspect}"
9171
+ end
9172
+ end
9173
+
9174
+ def test_pattern_matching_creates_locals
9175
+ assert_pattern_matching_defines_local_variables(
9176
+ %q{in a, *b, c},
9177
+ [:a, :b, :c]
9178
+ )
9179
+
9180
+ assert_pattern_matching_defines_local_variables(
9181
+ %q{in d | e | f},
9182
+ [:d, :e, :f]
9183
+ )
9184
+
9185
+ assert_pattern_matching_defines_local_variables(
9186
+ %q{in { g:, **h }},
9187
+ [:g, :h]
9188
+ )
9189
+
9190
+ assert_pattern_matching_defines_local_variables(
9191
+ %q{in A(i, *j, k)},
9192
+ [:i, :j, :k]
9193
+ )
9194
+
9195
+ assert_pattern_matching_defines_local_variables(
9196
+ %q{in 1 => l},
9197
+ [:l]
9198
+ )
9199
+
9200
+ assert_pattern_matching_defines_local_variables(
9201
+ %q{in "m":},
9202
+ [:m]
9203
+ )
9204
+ end
9205
+
9206
+ def test_pattern_matching__FILE__LINE_literals
9207
+ assert_parses(
9208
+ s(:case_match,
9209
+ s(:array,
9210
+ s(:str, "(assert_parses)"),
9211
+ s(:send,
9212
+ s(:int, 1), :+,
9213
+ s(:int, 1)),
9214
+ s(:__ENCODING__)),
9215
+ s(:in_pattern,
9216
+ s(:array_pattern,
9217
+ s(:str, "(assert_parses)"),
9218
+ s(:int, 2),
9219
+ s(:__ENCODING__)), nil, nil), nil),
9220
+ <<-RUBY,
9221
+ case [__FILE__, __LINE__ + 1, __ENCODING__]
9222
+ in [__FILE__, __LINE__, __ENCODING__]
9223
+ end
9224
+ RUBY
9225
+ %q{},
9226
+ SINCE_2_7)
9227
+ end
9228
+
9229
+ def test_pattern_matching_nil_pattern
9230
+ assert_parses_pattern_match(
9231
+ s(:in_pattern,
9232
+ s(:hash_pattern,
9233
+ s(:match_nil_pattern)),
9234
+ nil,
9235
+ s(:true)),
9236
+ %q{in **nil then true},
9237
+ %q{ ~~~~~ expression (in_pattern.hash_pattern.match_nil_pattern)
9238
+ | ~~~ name (in_pattern.hash_pattern.match_nil_pattern)}
9239
+ )
9240
+ end
9241
+
9242
+ def test_pattern_matching_single_line
9243
+ assert_parses(
9244
+ s(:begin,
9245
+ s(:in_match,
9246
+ s(:int, 1),
9247
+ s(:array_pattern,
9248
+ s(:match_var, :a))),
9249
+ s(:lvar, :a)),
9250
+ %q{1 in [a]; a},
9251
+ %q{~~~~~~~~ expression (in_match)
9252
+ | ~~ operator (in_match)},
9253
+ SINCE_2_7)
9254
+ end
9255
+
9256
+ def test_ruby_bug_pattern_matching_restore_in_kwarg_flag
9257
+ refute_diagnoses(
9258
+ "p(({} in {a:}), a:\n 1)",
9259
+ SINCE_2_7)
9260
+ end
9261
+
9262
+ def test_pattern_matching_duplicate_variable_name
9263
+ assert_diagnoses(
9264
+ [:error, :duplicate_variable_name, { :name => 'a' }],
9265
+ %q{case 0; in a, a; end},
9266
+ %q{ ^ location},
9267
+ SINCE_2_7)
9268
+
9269
+ refute_diagnoses(
9270
+ %q{case [0, 1, 2, 3]; in _, _, _a, _a; end},
9271
+ SINCE_2_7)
9272
+
9273
+ assert_diagnoses(
9274
+ [:error, :duplicate_variable_name, { :name => 'a' }],
9275
+ %q{case 0; in a, {a:}; end},
9276
+ %q{ ^ location},
9277
+ SINCE_2_7)
9278
+
9279
+ assert_diagnoses(
9280
+ [:error, :duplicate_variable_name, { :name => 'a' }],
9281
+ %q{case 0; in a, {"a":}; end},
9282
+ %q{ ^ location},
9283
+ SINCE_2_7)
9284
+
9285
+ assert_diagnoses(
9286
+ [:error, :duplicate_variable_name, { :name => 'a' }],
9287
+ %q{0 in [a, a]},
9288
+ %q{ ^ location},
9289
+ SINCE_2_7)
9290
+ end
9291
+
9292
+ def test_pattern_matching_duplicate_hash_keys
9293
+ assert_diagnoses(
9294
+ [:error, :duplicate_pattern_key, { :name => 'a' }],
9295
+ %q{ case 0; in a: 1, a: 2; end },
9296
+ %q{ ^^ location},
9297
+ SINCE_2_7)
9298
+
9299
+ assert_diagnoses(
9300
+ [:error, :duplicate_pattern_key, { :name => 'a' }],
9301
+ %q{ case 0; in a: 1, "a": 2; end },
9302
+ %q{ ^^^^ location},
9303
+ SINCE_2_7)
9304
+
9305
+ assert_diagnoses(
9306
+ [:error, :duplicate_pattern_key, { :name => 'a' }],
9307
+ %q{ case 0; in "a": 1, "a": 2; end },
9308
+ %q{ ^^^^ location},
9309
+ SINCE_2_7)
9310
+
9311
+ assert_diagnoses(
9312
+ [:error, :duplicate_pattern_key, { :name => "a\0" }],
9313
+ %q{ case 0; in "a\x0":a1, "a\0":a2; end },
9314
+ %q{ ^^^^^^ location},
9315
+ SINCE_2_7)
9316
+
9317
+ assert_diagnoses(
9318
+ [:error, :duplicate_pattern_key, { :name => "abc" }],
9319
+ %q{ case 0; in "abc":a1, "a#{"b"}c":a2; end },
9320
+ %q{ ^^^^^^^^^^^ location},
9321
+ SINCE_2_7)
9322
+ end
9323
+
9324
+ def test_pattern_matching_required_parentheses_for_in_match
9325
+ assert_diagnoses(
9326
+ [:error, :unexpected_token, { :token => 'tCOMMA' }],
9327
+ %{1 in a, b},
9328
+ %{ ^ location},
9329
+ SINCE_2_7)
9330
+
9331
+ assert_diagnoses(
9332
+ [:error, :unexpected_token, { :token => 'tLABEL' }],
9333
+ %{1 in a:},
9334
+ %{ ^^ location},
9335
+ SINCE_2_7)
9336
+ end
9337
+
9338
+ def test_pattern_matching_required_bound_variable_before_pin
9339
+ assert_diagnoses(
9340
+ [:error, :undefined_lvar, { :name => 'a' }],
9341
+ %{case 0; in ^a; true; end},
9342
+ %{ ^ location},
9343
+ SINCE_2_7)
9344
+ end
9345
+
9346
+ def test_parser_bug_645
9347
+ assert_parses(
9348
+ s(:block,
9349
+ s(:lambda),
9350
+ s(:args,
9351
+ s(:optarg, :arg,
9352
+ s(:hash))), nil),
9353
+ '-> (arg={}) {}',
9354
+ %{},
9355
+ SINCE_1_9)
9356
+ end
7644
9357
  end