parser 2.6.3.0 → 2.6.4.0
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 +10 -10
- data/CHANGELOG.md +24 -2
- data/doc/AST_FORMAT.md +45 -3
- data/lib/parser.rb +1 -0
- data/lib/parser/ast/processor.rb +24 -1
- data/lib/parser/builders/default.rb +64 -12
- data/lib/parser/context.rb +8 -0
- data/lib/parser/current.rb +3 -3
- data/lib/parser/lexer.rl +84 -3
- data/lib/parser/lexer/max_numparam_stack.rb +42 -0
- data/lib/parser/messages.rb +26 -20
- data/lib/parser/meta.rb +1 -0
- data/lib/parser/ruby25.y +1 -1
- data/lib/parser/ruby27.y +65 -31
- data/lib/parser/runner/ruby_parse.rb +2 -2
- data/lib/parser/version.rb +1 -1
- data/parser.gemspec +1 -1
- data/test/test_lexer.rb +75 -0
- data/test/test_parser.rb +382 -3
- data/test/test_runner_parse.rb +35 -0
- metadata +7 -4
@@ -0,0 +1,42 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Parser
|
4
|
+
|
5
|
+
class Lexer::MaxNumparamStack
|
6
|
+
def initialize
|
7
|
+
@stack = []
|
8
|
+
end
|
9
|
+
|
10
|
+
def cant_have_numparams!
|
11
|
+
set(-1)
|
12
|
+
end
|
13
|
+
|
14
|
+
def can_have_numparams?
|
15
|
+
top >= 0
|
16
|
+
end
|
17
|
+
|
18
|
+
def register(numparam)
|
19
|
+
set( [top, numparam].max )
|
20
|
+
end
|
21
|
+
|
22
|
+
def top
|
23
|
+
@stack.last
|
24
|
+
end
|
25
|
+
|
26
|
+
def push
|
27
|
+
@stack.push(0)
|
28
|
+
end
|
29
|
+
|
30
|
+
def pop
|
31
|
+
@stack.pop
|
32
|
+
end
|
33
|
+
|
34
|
+
private
|
35
|
+
|
36
|
+
def set(value)
|
37
|
+
@stack.pop
|
38
|
+
@stack.push(value)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
end
|
data/lib/parser/messages.rb
CHANGED
@@ -10,26 +10,31 @@ module Parser
|
|
10
10
|
#
|
11
11
|
MESSAGES = {
|
12
12
|
# Lexer errors
|
13
|
-
:unicode_point_too_large
|
14
|
-
:invalid_escape
|
15
|
-
:incomplete_escape
|
16
|
-
:invalid_hex_escape
|
17
|
-
:invalid_unicode_escape
|
18
|
-
:unterminated_unicode
|
19
|
-
:escape_eof
|
20
|
-
:string_eof
|
21
|
-
:regexp_options
|
22
|
-
:cvar_name
|
23
|
-
:ivar_name
|
24
|
-
:trailing_in_number
|
25
|
-
:empty_numeric
|
26
|
-
:invalid_octal
|
27
|
-
:no_dot_digit_literal
|
28
|
-
:bare_backslash
|
29
|
-
:unexpected
|
30
|
-
:embedded_document
|
31
|
-
:heredoc_id_has_newline
|
32
|
-
:heredoc_id_ends_with_nl
|
13
|
+
:unicode_point_too_large => 'invalid Unicode codepoint (too large)',
|
14
|
+
:invalid_escape => 'invalid escape character syntax',
|
15
|
+
:incomplete_escape => 'incomplete character syntax',
|
16
|
+
:invalid_hex_escape => 'invalid hex escape',
|
17
|
+
:invalid_unicode_escape => 'invalid Unicode escape',
|
18
|
+
:unterminated_unicode => 'unterminated Unicode escape',
|
19
|
+
:escape_eof => 'escape sequence meets end of file',
|
20
|
+
:string_eof => 'unterminated string meets end of file',
|
21
|
+
:regexp_options => 'unknown regexp options: %{options}',
|
22
|
+
:cvar_name => "`%{name}' is not allowed as a class variable name",
|
23
|
+
:ivar_name => "`%{name}' is not allowed as an instance variable name",
|
24
|
+
:trailing_in_number => "trailing `%{character}' in number",
|
25
|
+
:empty_numeric => 'numeric literal without digits',
|
26
|
+
:invalid_octal => 'invalid octal digit',
|
27
|
+
:no_dot_digit_literal => 'no .<digit> floating literal anymore; put 0 before dot',
|
28
|
+
:bare_backslash => 'bare backslash only allowed before newline',
|
29
|
+
:unexpected => "unexpected `%{character}'",
|
30
|
+
:embedded_document => 'embedded document meets end of file (and they embark on a romantic journey)',
|
31
|
+
:heredoc_id_has_newline => 'here document identifier across newlines, never match',
|
32
|
+
:heredoc_id_ends_with_nl => 'here document identifier ends with a newline',
|
33
|
+
:unterminated_heredoc_id => 'unterminated heredoc id',
|
34
|
+
:leading_zero_in_numparam => 'leading zero is not allowed as a numbered parameter',
|
35
|
+
:numparam_outside_block => 'numbered parameter outside block',
|
36
|
+
:too_large_numparam => 'too large numbered parameter',
|
37
|
+
:ordinary_param_defined => 'ordinary parameter is defined',
|
33
38
|
|
34
39
|
# Lexer warnings
|
35
40
|
:invalid_escape_use => 'invalid character syntax; use ?%{escape}',
|
@@ -61,6 +66,7 @@ module Parser
|
|
61
66
|
:block_given_to_yield => 'block given to yield',
|
62
67
|
:invalid_regexp => '%{message}',
|
63
68
|
:invalid_return => 'Invalid return in class/module body',
|
69
|
+
:csend_in_lhs_of_masgn => '&. inside multiple assignment destination',
|
64
70
|
|
65
71
|
# Parser warnings
|
66
72
|
:useless_else => 'else without rescue is useless',
|
data/lib/parser/meta.rb
CHANGED
data/lib/parser/ruby25.y
CHANGED
@@ -1885,7 +1885,7 @@ regexp_contents: # nothing
|
|
1885
1885
|
result = @builder.symbol(val[0])
|
1886
1886
|
}
|
1887
1887
|
|
1888
|
-
dsym: tSYMBEG
|
1888
|
+
dsym: tSYMBEG string_contents tSTRING_END
|
1889
1889
|
{
|
1890
1890
|
@lexer.state = :expr_end
|
1891
1891
|
result = @builder.symbol_compose(val[0], val[1], val[2])
|
data/lib/parser/ruby27.y
CHANGED
@@ -17,7 +17,7 @@ token kCLASS kMODULE kDEF kUNDEF kBEGIN kRESCUE kENSURE kEND kIF kUNLESS
|
|
17
17
|
tWORDS_BEG tQWORDS_BEG tSYMBOLS_BEG tQSYMBOLS_BEG tSTRING_DBEG
|
18
18
|
tSTRING_DVAR tSTRING_END tSTRING_DEND tSTRING tSYMBOL
|
19
19
|
tNL tEH tCOLON tCOMMA tSPACE tSEMI tLAMBDA tLAMBEG tCHARACTER
|
20
|
-
tRATIONAL tIMAGINARY tLABEL_END tANDDOT tMETHREF tBDOT2 tBDOT3
|
20
|
+
tRATIONAL tIMAGINARY tLABEL_END tANDDOT tMETHREF tBDOT2 tBDOT3 tNUMPARAM
|
21
21
|
|
22
22
|
prechigh
|
23
23
|
right tBANG tTILDE tUPLUS
|
@@ -193,6 +193,15 @@ rule
|
|
193
193
|
result = @builder.assign(val[0], val[1],
|
194
194
|
@builder.array(nil, val[2], nil))
|
195
195
|
}
|
196
|
+
| mlhs tEQL mrhs_arg kRESCUE_MOD stmt
|
197
|
+
{
|
198
|
+
rescue_body = @builder.rescue_body(val[3],
|
199
|
+
nil, nil, nil,
|
200
|
+
nil, val[4])
|
201
|
+
begin_body = @builder.begin_body(val[2], [ rescue_body ])
|
202
|
+
|
203
|
+
result = @builder.multi_assign(val[0], val[1], begin_body)
|
204
|
+
}
|
196
205
|
| mlhs tEQL mrhs_arg
|
197
206
|
{
|
198
207
|
result = @builder.multi_assign(val[0], val[1], val[2])
|
@@ -480,6 +489,10 @@ rule
|
|
480
489
|
}
|
481
490
|
| primary_value call_op tIDENTIFIER
|
482
491
|
{
|
492
|
+
if (val[1][0] == :anddot)
|
493
|
+
diagnostic :error, :csend_in_lhs_of_masgn, nil, val[1]
|
494
|
+
end
|
495
|
+
|
483
496
|
result = @builder.attr_asgn(val[0], val[1], val[2])
|
484
497
|
}
|
485
498
|
| primary_value tCOLON2 tIDENTIFIER
|
@@ -488,6 +501,10 @@ rule
|
|
488
501
|
}
|
489
502
|
| primary_value call_op tCONSTANT
|
490
503
|
{
|
504
|
+
if (val[1][0] == :anddot)
|
505
|
+
diagnostic :error, :csend_in_lhs_of_masgn, nil, val[1]
|
506
|
+
end
|
507
|
+
|
491
508
|
result = @builder.attr_asgn(val[0], val[1], val[2])
|
492
509
|
}
|
493
510
|
| primary_value tCOLON2 tCONSTANT
|
@@ -1294,45 +1311,33 @@ rule
|
|
1294
1311
|
}
|
1295
1312
|
|
1296
1313
|
f_margs: f_marg_list
|
1297
|
-
| f_marg_list tCOMMA
|
1314
|
+
| f_marg_list tCOMMA f_rest_marg
|
1298
1315
|
{
|
1299
1316
|
result = val[0].
|
1300
|
-
push(
|
1317
|
+
push(val[2])
|
1301
1318
|
}
|
1302
|
-
| f_marg_list tCOMMA
|
1319
|
+
| f_marg_list tCOMMA f_rest_marg tCOMMA f_marg_list
|
1303
1320
|
{
|
1304
1321
|
result = val[0].
|
1305
|
-
push(
|
1306
|
-
concat(val[5])
|
1307
|
-
}
|
1308
|
-
| f_marg_list tCOMMA tSTAR
|
1309
|
-
{
|
1310
|
-
result = val[0].
|
1311
|
-
push(@builder.restarg(val[2]))
|
1312
|
-
}
|
1313
|
-
| f_marg_list tCOMMA tSTAR tCOMMA f_marg_list
|
1314
|
-
{
|
1315
|
-
result = val[0].
|
1316
|
-
push(@builder.restarg(val[2])).
|
1322
|
+
push(val[2]).
|
1317
1323
|
concat(val[4])
|
1318
1324
|
}
|
1319
|
-
|
|
1325
|
+
| f_rest_marg
|
1320
1326
|
{
|
1321
|
-
result = [
|
1327
|
+
result = [ val[0] ]
|
1322
1328
|
}
|
1323
|
-
|
|
1329
|
+
| f_rest_marg tCOMMA f_marg_list
|
1324
1330
|
{
|
1325
|
-
result = [
|
1326
|
-
*val[3] ]
|
1331
|
+
result = [ val[0], *val[2] ]
|
1327
1332
|
}
|
1328
|
-
|
1333
|
+
|
1334
|
+
f_rest_marg: tSTAR f_norm_arg
|
1329
1335
|
{
|
1330
|
-
result =
|
1336
|
+
result = @builder.restarg(val[0], val[1])
|
1331
1337
|
}
|
1332
|
-
|
|
1338
|
+
| tSTAR
|
1333
1339
|
{
|
1334
|
-
result =
|
1335
|
-
*val[2] ]
|
1340
|
+
result = @builder.restarg(val[0])
|
1336
1341
|
}
|
1337
1342
|
|
1338
1343
|
block_args_tail: f_block_kwarg tCOMMA f_kwrest opt_f_block_arg
|
@@ -1460,14 +1465,17 @@ opt_block_args_tail:
|
|
1460
1465
|
|
1461
1466
|
block_param_def: tPIPE opt_bv_decl tPIPE
|
1462
1467
|
{
|
1468
|
+
@lexer.max_numparam_stack.cant_have_numparams!
|
1463
1469
|
result = @builder.args(val[0], val[1], val[2])
|
1464
1470
|
}
|
1465
1471
|
| tOROP
|
1466
1472
|
{
|
1473
|
+
@lexer.max_numparam_stack.cant_have_numparams!
|
1467
1474
|
result = @builder.args(val[0], [], val[0])
|
1468
1475
|
}
|
1469
1476
|
| tPIPE block_param opt_bv_decl tPIPE
|
1470
1477
|
{
|
1478
|
+
@lexer.max_numparam_stack.cant_have_numparams!
|
1471
1479
|
result = @builder.args(val[0], val[1].concat(val[2]), val[3])
|
1472
1480
|
}
|
1473
1481
|
|
@@ -1498,26 +1506,34 @@ opt_block_args_tail:
|
|
1498
1506
|
|
1499
1507
|
lambda: {
|
1500
1508
|
@static_env.extend_dynamic
|
1509
|
+
@lexer.max_numparam_stack.push
|
1510
|
+
@context.push(:lambda)
|
1501
1511
|
}
|
1502
1512
|
f_larglist
|
1503
1513
|
{
|
1514
|
+
@context.pop
|
1504
1515
|
@lexer.cmdarg.push(false)
|
1505
1516
|
}
|
1506
1517
|
lambda_body
|
1507
1518
|
{
|
1508
|
-
@lexer.
|
1509
|
-
|
1510
|
-
result = [ val[1], val[3] ]
|
1519
|
+
args = @lexer.max_numparam > 0 ? @builder.numargs(@lexer.max_numparam) : val[1]
|
1520
|
+
result = [ args, val[3] ]
|
1511
1521
|
|
1522
|
+
@lexer.max_numparam_stack.pop
|
1512
1523
|
@static_env.unextend
|
1524
|
+
@lexer.cmdarg.pop
|
1513
1525
|
}
|
1514
1526
|
|
1515
1527
|
f_larglist: tLPAREN2 f_args opt_bv_decl tRPAREN
|
1516
1528
|
{
|
1529
|
+
@lexer.max_numparam_stack.cant_have_numparams!
|
1517
1530
|
result = @builder.args(val[0], val[1].concat(val[2]), val[3])
|
1518
1531
|
}
|
1519
1532
|
| f_args
|
1520
1533
|
{
|
1534
|
+
if val[0].any?
|
1535
|
+
@lexer.max_numparam_stack.cant_have_numparams!
|
1536
|
+
end
|
1521
1537
|
result = @builder.args(nil, val[0], nil)
|
1522
1538
|
}
|
1523
1539
|
|
@@ -1652,24 +1668,30 @@ opt_block_args_tail:
|
|
1652
1668
|
|
1653
1669
|
brace_body: {
|
1654
1670
|
@static_env.extend_dynamic
|
1671
|
+
@lexer.max_numparam_stack.push
|
1655
1672
|
}
|
1656
1673
|
opt_block_param compstmt
|
1657
1674
|
{
|
1658
|
-
|
1675
|
+
args = @lexer.max_numparam > 0 ? @builder.numargs(@lexer.max_numparam) : val[1]
|
1676
|
+
result = [ args, val[2] ]
|
1659
1677
|
|
1678
|
+
@lexer.max_numparam_stack.pop
|
1660
1679
|
@static_env.unextend
|
1661
1680
|
}
|
1662
1681
|
|
1663
1682
|
do_body: {
|
1664
1683
|
@static_env.extend_dynamic
|
1684
|
+
@lexer.max_numparam_stack.push
|
1665
1685
|
}
|
1666
1686
|
{
|
1667
1687
|
@lexer.cmdarg.push(false)
|
1668
1688
|
}
|
1669
1689
|
opt_block_param bodystmt
|
1670
1690
|
{
|
1671
|
-
|
1691
|
+
args = @lexer.max_numparam > 0 ? @builder.numargs(@lexer.max_numparam) : val[2]
|
1692
|
+
result = [ args, val[3] ]
|
1672
1693
|
|
1694
|
+
@lexer.max_numparam_stack.pop
|
1673
1695
|
@static_env.unextend
|
1674
1696
|
@lexer.cmdarg.pop
|
1675
1697
|
}
|
@@ -1892,6 +1914,10 @@ regexp_contents: # nothing
|
|
1892
1914
|
{
|
1893
1915
|
result = @builder.cvar(val[0])
|
1894
1916
|
}
|
1917
|
+
| tNUMPARAM
|
1918
|
+
{
|
1919
|
+
result = @builder.numparam(val[0])
|
1920
|
+
}
|
1895
1921
|
| backref
|
1896
1922
|
|
1897
1923
|
symbol: ssym
|
@@ -1964,6 +1990,10 @@ regexp_contents: # nothing
|
|
1964
1990
|
{
|
1965
1991
|
result = @builder.cvar(val[0])
|
1966
1992
|
}
|
1993
|
+
| tNUMPARAM
|
1994
|
+
{
|
1995
|
+
result = @builder.numparam(val[0])
|
1996
|
+
}
|
1967
1997
|
|
1968
1998
|
keyword_variable: kNIL
|
1969
1999
|
{
|
@@ -2188,6 +2218,8 @@ keyword_variable: kNIL
|
|
2188
2218
|
{
|
2189
2219
|
@static_env.declare val[0][0]
|
2190
2220
|
|
2221
|
+
@lexer.max_numparam_stack.cant_have_numparams!
|
2222
|
+
|
2191
2223
|
result = val[0]
|
2192
2224
|
}
|
2193
2225
|
|
@@ -2220,6 +2252,8 @@ keyword_variable: kNIL
|
|
2220
2252
|
|
2221
2253
|
@static_env.declare val[0][0]
|
2222
2254
|
|
2255
|
+
@lexer.max_numparam_stack.cant_have_numparams!
|
2256
|
+
|
2223
2257
|
result = val[0]
|
2224
2258
|
}
|
2225
2259
|
|
@@ -123,7 +123,7 @@ module Parser
|
|
123
123
|
opts.on '--emit-ruby', 'Emit S-expressions as valid Ruby code' do
|
124
124
|
@emit_ruby = true
|
125
125
|
end
|
126
|
-
|
126
|
+
|
127
127
|
opts.on '--emit-json', 'Emit S-expressions as valid JSON' do
|
128
128
|
@emit_json = true
|
129
129
|
end
|
@@ -146,7 +146,7 @@ module Parser
|
|
146
146
|
if @emit_ruby
|
147
147
|
puts ast.inspect
|
148
148
|
elsif @emit_json
|
149
|
-
puts JSON.generate(ast.to_sexp_array)
|
149
|
+
puts(ast ? JSON.generate(ast.to_sexp_array) : nil)
|
150
150
|
else
|
151
151
|
puts ast.to_s
|
152
152
|
end
|
data/lib/parser/version.rb
CHANGED
data/parser.gemspec
CHANGED
@@ -38,7 +38,7 @@ Gem::Specification.new do |spec|
|
|
38
38
|
|
39
39
|
spec.add_development_dependency 'bundler', '>= 1.15', '< 3.0.0'
|
40
40
|
spec.add_development_dependency 'rake', '~> 10.0'
|
41
|
-
spec.add_development_dependency 'racc', '= 1.4.
|
41
|
+
spec.add_development_dependency 'racc', '= 1.4.15'
|
42
42
|
spec.add_development_dependency 'cliver', '~> 0.3.2'
|
43
43
|
|
44
44
|
spec.add_development_dependency 'yard'
|
data/test/test_lexer.rb
CHANGED
@@ -162,6 +162,24 @@ class TestLexer < Minitest::Test
|
|
162
162
|
refute_escape 'u{123 f0'
|
163
163
|
end
|
164
164
|
|
165
|
+
def test_read_escape_whitespaces__27
|
166
|
+
setup_lexer 27
|
167
|
+
|
168
|
+
[ *(0..8), *(14..31) ].each do |code|
|
169
|
+
@lex.reset
|
170
|
+
refute_scanned "\"\\C-" + code.chr + "\""
|
171
|
+
|
172
|
+
@lex.reset
|
173
|
+
refute_scanned "\"\\M-" + code.chr + "\""
|
174
|
+
|
175
|
+
@lex.reset
|
176
|
+
refute_scanned "\"\\C-\\M-" + code.chr + "\""
|
177
|
+
|
178
|
+
@lex.reset
|
179
|
+
refute_scanned "\"\\M-\\C-" + code.chr + "\""
|
180
|
+
end
|
181
|
+
end
|
182
|
+
|
165
183
|
def test_ambiguous_uminus
|
166
184
|
assert_scanned("m -3",
|
167
185
|
:tIDENTIFIER, "m", [0, 1],
|
@@ -3581,4 +3599,61 @@ class TestLexer < Minitest::Test
|
|
3581
3599
|
:tPLUS, '+', [6, 7])
|
3582
3600
|
end
|
3583
3601
|
|
3602
|
+
def lex_numbered_parameter(input)
|
3603
|
+
@lex.max_numparam_stack.push
|
3604
|
+
|
3605
|
+
@lex.context = Parser::Context.new
|
3606
|
+
@lex.context.push(:block)
|
3607
|
+
|
3608
|
+
source_buffer = Parser::Source::Buffer.new('(assert_lex_numbered_parameter)')
|
3609
|
+
source_buffer.source = input
|
3610
|
+
|
3611
|
+
@lex.source_buffer = source_buffer
|
3612
|
+
|
3613
|
+
@lex.advance
|
3614
|
+
end
|
3615
|
+
|
3616
|
+
def assert_scanned_numbered_parameter(input)
|
3617
|
+
lex_token, (lex_value, lex_range) = lex_numbered_parameter(input)
|
3618
|
+
|
3619
|
+
assert_equal(lex_token, :tNUMPARAM)
|
3620
|
+
assert_equal(lex_value, input.tr('@', ''))
|
3621
|
+
assert_equal(lex_range.begin_pos, 0)
|
3622
|
+
assert_equal(lex_range.end_pos, input.length)
|
3623
|
+
end
|
3624
|
+
|
3625
|
+
def refute_scanned_numbered_parameter(input, message = nil)
|
3626
|
+
err = assert_raises Parser::SyntaxError do
|
3627
|
+
lex_token, (lex_value, lex_range) = lex_numbered_parameter(input)
|
3628
|
+
end
|
3629
|
+
|
3630
|
+
if message
|
3631
|
+
assert_equal(err.message, Parser::MESSAGES[message])
|
3632
|
+
|
3633
|
+
assert_equal(err.diagnostic.location.begin_pos, 0)
|
3634
|
+
assert_equal(err.diagnostic.location.end_pos, input.length)
|
3635
|
+
end
|
3636
|
+
end
|
3637
|
+
|
3638
|
+
def test_numbered_args_before_27
|
3639
|
+
setup_lexer(26)
|
3640
|
+
refute_scanned_numbered_parameter('@1')
|
3641
|
+
end
|
3642
|
+
|
3643
|
+
def test_numbered_args_27
|
3644
|
+
setup_lexer(27)
|
3645
|
+
assert_scanned_numbered_parameter('@1')
|
3646
|
+
assert_equal(@lex.max_numparam, 1)
|
3647
|
+
|
3648
|
+
setup_lexer(27)
|
3649
|
+
assert_scanned_numbered_parameter('@100')
|
3650
|
+
assert_equal(@lex.max_numparam, 100)
|
3651
|
+
|
3652
|
+
setup_lexer(27)
|
3653
|
+
refute_scanned_numbered_parameter('@101', :too_large_numparam)
|
3654
|
+
|
3655
|
+
setup_lexer(27)
|
3656
|
+
refute_scanned_numbered_parameter('@01', :leading_zero_in_numparam)
|
3657
|
+
end
|
3658
|
+
|
3584
3659
|
end
|