parser 2.6.5.0 → 2.7.0.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.
@@ -67,13 +67,15 @@ module Parser
67
67
  require 'parser/lexer/literal'
68
68
  require 'parser/lexer/stack_state'
69
69
  require 'parser/lexer/dedenter'
70
- require 'parser/lexer/max_numparam_stack'
71
70
 
72
71
  module Builders
73
72
  require 'parser/builders/default'
74
73
  end
75
74
 
76
75
  require 'parser/context'
76
+ require 'parser/max_numparam_stack'
77
+ require 'parser/current_arg_stack'
78
+ require 'parser/variables_stack'
77
79
 
78
80
  require 'parser/base'
79
81
 
@@ -236,6 +236,21 @@ module Parser
236
236
  alias on_preexe process_regular_node
237
237
  alias on_postexe process_regular_node
238
238
 
239
+ alias on_case_match process_regular_node
240
+ alias on_in_match process_regular_node
241
+ alias on_in_pattern process_regular_node
242
+ alias on_if_guard process_regular_node
243
+ alias on_unless_guard process_regular_node
244
+ alias on_match_var process_variable_node
245
+ alias on_match_rest process_regular_node
246
+ alias on_pin process_regular_node
247
+ alias on_match_alt process_regular_node
248
+ alias on_match_as process_regular_node
249
+ alias on_array_pattern process_regular_node
250
+ alias on_array_pattern_with_tail process_regular_node
251
+ alias on_hash_pattern process_regular_node
252
+ alias on_const_pattern process_regular_node
253
+
239
254
  # @private
240
255
  def process_variable_node(node)
241
256
  warn 'Parser::AST::Processor#process_variable_node is deprecated as a' \
@@ -114,6 +114,10 @@ module Parser
114
114
  attr_reader :static_env
115
115
  attr_reader :source_buffer
116
116
  attr_reader :context
117
+ attr_reader :max_numparam_stack
118
+ attr_reader :current_arg_stack
119
+ attr_reader :pattern_variables
120
+ attr_reader :pattern_hash_keys
117
121
 
118
122
  ##
119
123
  # @param [Parser::Builders::Default] builder The AST builder to use.
@@ -126,6 +130,18 @@ module Parser
126
130
  # Stack that holds current parsing context
127
131
  @context = Context.new
128
132
 
133
+ # Maximum numbered parameters stack
134
+ @max_numparam_stack = MaxNumparamStack.new
135
+
136
+ # Current argument names stack
137
+ @current_arg_stack = CurrentArgStack.new
138
+
139
+ # Stack of set of variables used in the current pattern
140
+ @pattern_variables = VariablesStack.new
141
+
142
+ # Stack of set of keys used in the current hash in pattern matchinig
143
+ @pattern_hash_keys = VariablesStack.new
144
+
129
145
  @lexer = Lexer.new(version)
130
146
  @lexer.diagnostics = @diagnostics
131
147
  @lexer.static_env = @static_env
@@ -153,6 +169,9 @@ module Parser
153
169
  @lexer.reset
154
170
  @static_env.reset
155
171
  @context.reset
172
+ @current_arg_stack.reset
173
+ @pattern_variables.reset
174
+ @pattern_hash_keys.reset
156
175
 
157
176
  self
158
177
  end
@@ -453,11 +453,6 @@ module Parser
453
453
  variable_map(token))
454
454
  end
455
455
 
456
- def numparam(token)
457
- n(:numparam, [ value(token).to_i ],
458
- variable_map(token))
459
- end
460
-
461
456
  def back_ref(token)
462
457
  n(:back_ref, [ value(token).to_sym ],
463
458
  token_map(token))
@@ -498,6 +493,11 @@ module Parser
498
493
  name, = *node
499
494
 
500
495
  if @parser.static_env.declared?(name)
496
+ if name.to_s == parser.current_arg_stack.top
497
+ diagnostic :error, :circular_argument_reference,
498
+ { :var_name => name.to_s }, node.loc.expression
499
+ end
500
+
501
501
  node.updated(:lvar)
502
502
  else
503
503
  name, = *node
@@ -556,6 +556,9 @@ module Parser
556
556
 
557
557
  when :ident
558
558
  name, = *node
559
+
560
+ check_assignment_to_numparam(node)
561
+
559
562
  @parser.static_env.declare(name)
560
563
 
561
564
  node.updated(:lvasgn)
@@ -688,6 +691,10 @@ module Parser
688
691
  n(:numargs, [ max_numparam ], nil)
689
692
  end
690
693
 
694
+ def forward_args(begin_t, dots_t, end_t)
695
+ n(:forward_args, [], collection_map(begin_t, token_map(dots_t), end_t))
696
+ end
697
+
691
698
  def arg(name_t)
692
699
  n(:arg, [ value(name_t).to_sym ],
693
700
  variable_map(name_t))
@@ -837,6 +844,10 @@ module Parser
837
844
  end
838
845
  end
839
846
 
847
+ def forwarded_args(dots_t)
848
+ n(:forwarded_args, [], token_map(dots_t))
849
+ end
850
+
840
851
  def call_method(receiver, dot_t, selector_t,
841
852
  lparen_t=nil, args=[], rparen_t=nil)
842
853
  type = call_type_for_dot(dot_t)
@@ -866,11 +877,10 @@ module Parser
866
877
  end
867
878
 
868
879
  last_arg = call_args.last
869
- if last_arg && last_arg.type == :block_pass
880
+ if last_arg && (last_arg.type == :block_pass || last_arg.type == :forwarded_args)
870
881
  diagnostic :error, :block_and_blockarg, nil, last_arg.loc.expression, [loc(begin_t)]
871
882
  end
872
883
 
873
-
874
884
  if args.type == :numargs
875
885
  block_type = :numblock
876
886
  args = args.children[0]
@@ -1006,11 +1016,6 @@ module Parser
1006
1016
  end
1007
1017
  end
1008
1018
 
1009
- def method_ref(receiver, dot_t, selector_t)
1010
- n(:meth_ref, [ receiver, value(selector_t).to_sym ],
1011
- send_map(receiver, dot_t, selector_t, nil, [], nil))
1012
- end
1013
-
1014
1019
  #
1015
1020
  # Control flow
1016
1021
  #
@@ -1203,6 +1208,188 @@ module Parser
1203
1208
  end
1204
1209
  end
1205
1210
 
1211
+ #
1212
+ # PATTERN MATCHING
1213
+ #
1214
+
1215
+ def case_match(case_t, expr, in_bodies, else_t, else_body, end_t)
1216
+ n(:case_match, [ expr, *(in_bodies << else_body)],
1217
+ condition_map(case_t, expr, nil, nil, else_t, else_body, end_t))
1218
+ end
1219
+
1220
+ def in_match(lhs, in_t, rhs)
1221
+ n(:in_match, [lhs, rhs],
1222
+ binary_op_map(lhs, in_t, rhs))
1223
+ end
1224
+
1225
+ def in_pattern(in_t, pattern, guard, then_t, body)
1226
+ children = [pattern, guard, body]
1227
+ n(:in_pattern, children,
1228
+ keyword_map(in_t, then_t, children.compact, nil))
1229
+ end
1230
+
1231
+ def if_guard(if_t, if_body)
1232
+ n(:if_guard, [if_body], guard_map(if_t, if_body))
1233
+ end
1234
+
1235
+ def unless_guard(unless_t, unless_body)
1236
+ n(:unless_guard, [unless_body], guard_map(unless_t, unless_body))
1237
+ end
1238
+
1239
+ def match_var(name_t)
1240
+ name = value(name_t).to_sym
1241
+
1242
+ check_duplicate_pattern_variable(name, loc(name_t))
1243
+ @parser.static_env.declare(name)
1244
+
1245
+ n(:match_var, [ name ],
1246
+ variable_map(name_t))
1247
+ end
1248
+
1249
+ def match_hash_var(name_t)
1250
+ name = value(name_t).to_sym
1251
+
1252
+ expr_l = loc(name_t)
1253
+ name_l = expr_l.adjust(end_pos: -1)
1254
+
1255
+ check_duplicate_pattern_variable(name, name_l)
1256
+ @parser.static_env.declare(name)
1257
+
1258
+ n(:match_var, [ name ],
1259
+ Source::Map::Variable.new(name_l, expr_l))
1260
+ end
1261
+
1262
+ def match_hash_var_from_str(begin_t, strings, end_t)
1263
+ if strings.length > 1
1264
+ diagnostic :error, :pm_interp_in_var_name, nil, loc(begin_t).join(loc(end_t))
1265
+ end
1266
+
1267
+ string = strings[0]
1268
+
1269
+ case string.type
1270
+ when :str
1271
+ # MRI supports plain strings in hash pattern matching
1272
+ name, = *string
1273
+ name_l = string.loc.expression
1274
+
1275
+ check_lvar_name(name, name_l)
1276
+ check_duplicate_pattern_variable(name, name_l)
1277
+
1278
+ @parser.static_env.declare(name)
1279
+
1280
+ if (begin_l = string.loc.begin)
1281
+ # exclude beginning of the string from the location of the variable
1282
+ name_l = name_l.adjust(begin_pos: begin_l.length)
1283
+ end
1284
+
1285
+ if (end_l = string.loc.end)
1286
+ # exclude end of the string from the location of the variable
1287
+ name_l = name_l.adjust(end_pos: -end_l.length)
1288
+ end
1289
+
1290
+ expr_l = loc(begin_t).join(string.loc.expression).join(loc(end_t))
1291
+ n(:match_var, [ name.to_sym ],
1292
+ Source::Map::Variable.new(name_l, expr_l))
1293
+ when :begin
1294
+ match_hash_var_from_str(begin_t, string.children, end_t)
1295
+ end
1296
+ end
1297
+
1298
+ def match_rest(star_t, name_t = nil)
1299
+ if name_t.nil?
1300
+ n0(:match_rest,
1301
+ unary_op_map(star_t))
1302
+ else
1303
+ name = match_var(name_t)
1304
+ n(:match_rest, [ name ],
1305
+ unary_op_map(star_t, name))
1306
+ end
1307
+ end
1308
+
1309
+ def hash_pattern(lbrace_t, kwargs, rbrace_t)
1310
+ args = check_duplicate_args(kwargs)
1311
+ n(:hash_pattern, args,
1312
+ collection_map(lbrace_t, args, rbrace_t))
1313
+ end
1314
+
1315
+ def array_pattern(lbrack_t, elements, rbrack_t)
1316
+ trailing_comma = false
1317
+
1318
+ elements = elements.map do |element|
1319
+ if element.type == :match_with_trailing_comma
1320
+ trailing_comma = true
1321
+ element.children.first
1322
+ else
1323
+ trailing_comma = false
1324
+ element
1325
+ end
1326
+ end
1327
+
1328
+ node_type = trailing_comma ? :array_pattern_with_tail : :array_pattern
1329
+ n(node_type, elements,
1330
+ collection_map(lbrack_t, elements, rbrack_t))
1331
+ end
1332
+
1333
+ def match_with_trailing_comma(match)
1334
+ n(:match_with_trailing_comma, [ match ], nil)
1335
+ end
1336
+
1337
+ def const_pattern(const, ldelim_t, pattern, rdelim_t)
1338
+ n(:const_pattern, [const, pattern],
1339
+ collection_map(ldelim_t, [pattern], rdelim_t))
1340
+ end
1341
+
1342
+ def pin(pin_t, var)
1343
+ n(:pin, [ var ],
1344
+ send_unary_op_map(pin_t, var))
1345
+ end
1346
+
1347
+ def match_alt(left, pipe_t, right)
1348
+ source_map = binary_op_map(left, pipe_t, right)
1349
+
1350
+ n(:match_alt, [ left, right ],
1351
+ source_map)
1352
+ end
1353
+
1354
+ def match_as(value, assoc_t, as)
1355
+ source_map = binary_op_map(value, assoc_t, as)
1356
+
1357
+ n(:match_as, [ value, as ],
1358
+ source_map)
1359
+ end
1360
+
1361
+ def match_nil_pattern(dstar_t, nil_t)
1362
+ n0(:match_nil_pattern,
1363
+ arg_prefix_map(dstar_t, nil_t))
1364
+ end
1365
+
1366
+ def match_pair(label_type, label, value)
1367
+ if label_type == :label
1368
+ check_duplicate_pattern_key(label[0], label[1])
1369
+ pair_keyword(label, value)
1370
+ else
1371
+ begin_t, parts, end_t = label
1372
+
1373
+ # quoted label like "label": value
1374
+ if (var_name = static_string(parts))
1375
+ loc = loc(begin_t).join(loc(end_t))
1376
+ check_duplicate_pattern_key(var_name, loc)
1377
+ end
1378
+
1379
+ pair_quoted(begin_t, parts, end_t, value)
1380
+ end
1381
+ end
1382
+
1383
+ def match_label(label_type, label)
1384
+ if label_type == :label
1385
+ match_hash_var(label)
1386
+ else
1387
+ # quoted label like "label": value
1388
+ begin_t, strings, end_t = label
1389
+ match_hash_var_from_str(begin_t, strings, end_t)
1390
+ end
1391
+ end
1392
+
1206
1393
  private
1207
1394
 
1208
1395
  #
@@ -1292,6 +1479,19 @@ module Parser
1292
1479
  end
1293
1480
  end
1294
1481
 
1482
+ def check_assignment_to_numparam(node)
1483
+ name = node.children[0].to_s
1484
+
1485
+ assigning_to_numparam =
1486
+ @parser.context.in_dynamic_block? &&
1487
+ name =~ /\A_([1-9])\z/ &&
1488
+ @parser.max_numparam_stack.has_numparams?
1489
+
1490
+ if assigning_to_numparam
1491
+ diagnostic :error, :cant_assign_to_numparam, { :name => name }, node.loc.expression
1492
+ end
1493
+ end
1494
+
1295
1495
  def arg_name_collides?(this_name, that_name)
1296
1496
  case @parser.version
1297
1497
  when 18
@@ -1307,6 +1507,32 @@ module Parser
1307
1507
  end
1308
1508
  end
1309
1509
 
1510
+ def check_lvar_name(name, loc)
1511
+ if name =~ /\A[[[:lower:]]|_][[[:alnum:]]_]*\z/
1512
+ # OK
1513
+ else
1514
+ diagnostic :error, :lvar_name, { name: name }, loc
1515
+ end
1516
+ end
1517
+
1518
+ def check_duplicate_pattern_variable(name, loc)
1519
+ return if name.to_s.start_with?('_')
1520
+
1521
+ if @parser.pattern_variables.declared?(name)
1522
+ diagnostic :error, :duplicate_variable_name, { name: name.to_s }, loc
1523
+ end
1524
+
1525
+ @parser.pattern_variables.declare(name)
1526
+ end
1527
+
1528
+ def check_duplicate_pattern_key(name, loc)
1529
+ if @parser.pattern_hash_keys.declared?(name)
1530
+ diagnostic :error, :duplicate_pattern_key, { name: name.to_s }, loc
1531
+ end
1532
+
1533
+ @parser.pattern_hash_keys.declare(name)
1534
+ end
1535
+
1310
1536
  #
1311
1537
  # SOURCE MAPS
1312
1538
  #
@@ -1655,6 +1881,13 @@ module Parser
1655
1881
  begin_l.join(end_l))
1656
1882
  end
1657
1883
 
1884
+ def guard_map(keyword_t, guard_body_e)
1885
+ keyword_l = loc(keyword_t)
1886
+ guard_body_l = guard_body_e.loc.expression
1887
+
1888
+ Source::Map::Keyword.new(keyword_l, nil, nil, keyword_l.join(guard_body_l))
1889
+ end
1890
+
1658
1891
  #
1659
1892
  # HELPERS
1660
1893
  #
@@ -55,5 +55,9 @@ module Parser
55
55
  def in_lambda?
56
56
  @stack.last == :lambda
57
57
  end
58
+
59
+ def in_dynamic_block?
60
+ in_block? || in_lambda?
61
+ end
58
62
  end
59
63
  end
@@ -75,7 +75,7 @@ module Parser
75
75
  CurrentRuby = Ruby26
76
76
 
77
77
  when /^2\.7\./
78
- current_version = '2.7.0-dev'
78
+ current_version = '2.7.0'
79
79
  if RUBY_VERSION != current_version
80
80
  warn_syntax_deviation 'parser/ruby27', current_version
81
81
  end
@@ -85,8 +85,8 @@ module Parser
85
85
 
86
86
  else # :nocov:
87
87
  # Keep this in sync with released Ruby.
88
- warn_syntax_deviation 'parser/ruby26', '2.6.x'
89
- require 'parser/ruby26'
90
- CurrentRuby = Ruby26
88
+ warn_syntax_deviation 'parser/ruby27', '2.7.x'
89
+ require 'parser/ruby27'
90
+ CurrentRuby = Ruby27
91
91
  end
92
92
  end
@@ -0,0 +1,43 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Parser
4
+ # Stack that holds names of current arguments,
5
+ # i.e. while parsing
6
+ # def m1(a = (def m2(b = def m3(c = 1); end); end)); end
7
+ # ^
8
+ # stack is [:a, :b, :c]
9
+ #
10
+ # Emulates `p->cur_arg` in MRI's parse.y
11
+ #
12
+ # @api private
13
+ #
14
+ class CurrentArgStack
15
+ attr_reader :stack
16
+
17
+ def initialize
18
+ @stack = []
19
+ freeze
20
+ end
21
+
22
+ def push(value)
23
+ @stack << value
24
+ end
25
+
26
+ def set(value)
27
+ pop
28
+ push(value)
29
+ end
30
+
31
+ def pop
32
+ @stack.pop
33
+ end
34
+
35
+ def reset
36
+ @stack.clear
37
+ end
38
+
39
+ def top
40
+ @stack.last
41
+ end
42
+ end
43
+ end