parser 2.5.1.0 → 3.0.1.1

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.
Files changed (103) hide show
  1. checksums.yaml +4 -4
  2. data/lib/parser.rb +4 -0
  3. data/lib/parser/all.rb +3 -0
  4. data/lib/parser/ast/processor.rb +49 -1
  5. data/lib/parser/base.rb +30 -6
  6. data/lib/parser/builders/default.rb +586 -29
  7. data/lib/parser/context.rb +17 -0
  8. data/lib/parser/current.rb +34 -7
  9. data/lib/parser/current_arg_stack.rb +46 -0
  10. data/lib/parser/diagnostic.rb +1 -1
  11. data/lib/parser/diagnostic/engine.rb +1 -2
  12. data/lib/parser/lexer.rb +23780 -0
  13. data/lib/parser/lexer/dedenter.rb +52 -49
  14. data/lib/parser/lexer/literal.rb +4 -0
  15. data/lib/parser/lexer/stack_state.rb +4 -0
  16. data/lib/parser/macruby.rb +6149 -0
  17. data/lib/parser/max_numparam_stack.rb +56 -0
  18. data/lib/parser/messages.rb +74 -44
  19. data/lib/parser/meta.rb +13 -3
  20. data/lib/parser/ruby18.rb +5667 -0
  21. data/lib/parser/ruby19.rb +6092 -0
  22. data/lib/parser/ruby20.rb +6527 -0
  23. data/lib/parser/ruby21.rb +6578 -0
  24. data/lib/parser/ruby22.rb +6613 -0
  25. data/lib/parser/ruby23.rb +6624 -0
  26. data/lib/parser/ruby24.rb +6694 -0
  27. data/lib/parser/ruby25.rb +6662 -0
  28. data/lib/parser/ruby26.rb +6676 -0
  29. data/lib/parser/ruby27.rb +7862 -0
  30. data/lib/parser/ruby28.rb +8047 -0
  31. data/lib/parser/ruby30.rb +8060 -0
  32. data/lib/parser/ruby31.rb +8075 -0
  33. data/lib/parser/rubymotion.rb +6086 -0
  34. data/lib/parser/runner.rb +36 -2
  35. data/lib/parser/runner/ruby_parse.rb +2 -2
  36. data/lib/parser/runner/ruby_rewrite.rb +2 -2
  37. data/lib/parser/source/buffer.rb +54 -29
  38. data/lib/parser/source/comment.rb +18 -5
  39. data/lib/parser/source/comment/associator.rb +34 -11
  40. data/lib/parser/source/map.rb +1 -1
  41. data/lib/parser/source/map/method_definition.rb +25 -0
  42. data/lib/parser/source/range.rb +20 -4
  43. data/lib/parser/source/tree_rewriter.rb +146 -16
  44. data/lib/parser/source/tree_rewriter/action.rb +137 -28
  45. data/lib/parser/static_environment.rb +14 -0
  46. data/lib/parser/tree_rewriter.rb +3 -3
  47. data/lib/parser/variables_stack.rb +36 -0
  48. data/lib/parser/version.rb +1 -1
  49. data/parser.gemspec +13 -21
  50. metadata +34 -98
  51. data/.gitignore +0 -32
  52. data/.travis.yml +0 -21
  53. data/.yardopts +0 -21
  54. data/CHANGELOG.md +0 -909
  55. data/CONTRIBUTING.md +0 -17
  56. data/Gemfile +0 -10
  57. data/README.md +0 -301
  58. data/Rakefile +0 -165
  59. data/doc/AST_FORMAT.md +0 -1718
  60. data/doc/CUSTOMIZATION.md +0 -37
  61. data/doc/INTERNALS.md +0 -21
  62. data/doc/css/.gitkeep +0 -0
  63. data/doc/css/common.css +0 -68
  64. data/lib/parser/lexer.rl +0 -2376
  65. data/lib/parser/macruby.y +0 -2198
  66. data/lib/parser/ruby18.y +0 -1934
  67. data/lib/parser/ruby19.y +0 -2175
  68. data/lib/parser/ruby20.y +0 -2353
  69. data/lib/parser/ruby21.y +0 -2357
  70. data/lib/parser/ruby22.y +0 -2364
  71. data/lib/parser/ruby23.y +0 -2370
  72. data/lib/parser/ruby24.y +0 -2395
  73. data/lib/parser/ruby25.y +0 -2392
  74. data/lib/parser/ruby26.y +0 -2392
  75. data/lib/parser/rubymotion.y +0 -2182
  76. data/test/bug_163/fixtures/input.rb +0 -5
  77. data/test/bug_163/fixtures/output.rb +0 -5
  78. data/test/bug_163/rewriter.rb +0 -20
  79. data/test/helper.rb +0 -52
  80. data/test/parse_helper.rb +0 -315
  81. data/test/racc_coverage_helper.rb +0 -133
  82. data/test/test_base.rb +0 -31
  83. data/test/test_current.rb +0 -27
  84. data/test/test_diagnostic.rb +0 -96
  85. data/test/test_diagnostic_engine.rb +0 -62
  86. data/test/test_encoding.rb +0 -99
  87. data/test/test_lexer.rb +0 -3537
  88. data/test/test_lexer_stack_state.rb +0 -78
  89. data/test/test_parse_helper.rb +0 -80
  90. data/test/test_parser.rb +0 -6968
  91. data/test/test_runner_rewrite.rb +0 -47
  92. data/test/test_source_buffer.rb +0 -162
  93. data/test/test_source_comment.rb +0 -36
  94. data/test/test_source_comment_associator.rb +0 -367
  95. data/test/test_source_map.rb +0 -15
  96. data/test/test_source_range.rb +0 -172
  97. data/test/test_source_rewriter.rb +0 -541
  98. data/test/test_source_rewriter_action.rb +0 -46
  99. data/test/test_source_tree_rewriter.rb +0 -173
  100. data/test/test_static_environment.rb +0 -45
  101. data/test/using_tree_rewriter/fixtures/input.rb +0 -3
  102. data/test/using_tree_rewriter/fixtures/output.rb +0 -3
  103. data/test/using_tree_rewriter/using_tree_rewriter.rb +0 -9
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 3d4445244332537a2a91b8b6f6a2d35b750ffb1dbc3869c91f1a4de840a89600
4
- data.tar.gz: 800b3adeae6c64459f2b604c3c4b935eb728018bfe4136debae16c96df0384bf
3
+ metadata.gz: 6c85d02ca4bf90dcc1d33424dd323ae54b9e60581a6473012e950f82ce15d28e
4
+ data.tar.gz: ebe2c4eb02779209b8a34e051d717a6af84da81fadfeff79d9eab194ecf95d93
5
5
  SHA512:
6
- metadata.gz: 99138e99f88e016a3da7cac3fe45c492068fe5fa5ecb6df640ade2f6890c05fdc2aff096d255e0fd57f75f4e5c3300c15f16fa9be177e9fdc56711c6e6ea29ac
7
- data.tar.gz: 71504873b9c22a3adfd0d0ee304e69e3317b93d52a7e2506c6225e2c768cea2ddd9bf1a874a04c8b0706047f78dc97f49b7841307f64198678f03a3336ad2675
6
+ metadata.gz: 173d8e1bbbbbf0ef06d06f1ea59dc41ca49c8b39c6931523dc70bac259eee1e9c9263730d560afe106c70f88f01ae14edc77862d20a4924a674131ca90b9807c
7
+ data.tar.gz: 1698922a4ff14bf3e826f10b826a8a8e0c3aaf7fefd20669a4666c0ed6ea8a3ed405acbb28fe90985510dedff6414c0330d5affa4639840178bf20dee561e4a9
data/lib/parser.rb CHANGED
@@ -46,6 +46,7 @@ module Parser
46
46
  require 'parser/source/map/variable'
47
47
  require 'parser/source/map/keyword'
48
48
  require 'parser/source/map/definition'
49
+ require 'parser/source/map/method_definition'
49
50
  require 'parser/source/map/send'
50
51
  require 'parser/source/map/index'
51
52
  require 'parser/source/map/condition'
@@ -73,6 +74,9 @@ module Parser
73
74
  end
74
75
 
75
76
  require 'parser/context'
77
+ require 'parser/max_numparam_stack'
78
+ require 'parser/current_arg_stack'
79
+ require 'parser/variables_stack'
76
80
 
77
81
  require 'parser/base'
78
82
 
data/lib/parser/all.rb CHANGED
@@ -9,3 +9,6 @@ require 'parser/ruby23'
9
9
  require 'parser/ruby24'
10
10
  require 'parser/ruby25'
11
11
  require 'parser/ruby26'
12
+ require 'parser/ruby27'
13
+ require 'parser/ruby30'
14
+ require 'parser/ruby31'
@@ -16,9 +16,11 @@ module Parser
16
16
  alias on_regexp process_regular_node
17
17
  alias on_xstr process_regular_node
18
18
  alias on_splat process_regular_node
19
+ alias on_kwsplat process_regular_node
19
20
  alias on_array process_regular_node
20
21
  alias on_pair process_regular_node
21
22
  alias on_hash process_regular_node
23
+ alias on_kwargs process_regular_node
22
24
  alias on_irange process_regular_node
23
25
  alias on_erange process_regular_node
24
26
 
@@ -123,7 +125,23 @@ module Parser
123
125
  alias on_kwarg process_argument_node
124
126
  alias on_kwoptarg process_argument_node
125
127
  alias on_kwrestarg process_argument_node
126
- alias on_procarg0 process_argument_node
128
+ alias on_forward_arg process_argument_node
129
+
130
+ def on_procarg0(node)
131
+ if node.children[0].is_a?(Symbol)
132
+ # This branch gets executed when the builder
133
+ # is not configured to emit and 'arg' inside 'procarg0', i.e. when
134
+ # Parser::Builders::Default.emit_arg_inside_procarg0
135
+ # is set to false.
136
+ #
137
+ # If this flag is set to true this branch is unreachable.
138
+ # s(:procarg0, :a)
139
+ on_argument(node)
140
+ else
141
+ # s(:procarg0, s(:arg, :a), s(:arg, :b))
142
+ process_regular_node(node)
143
+ end
144
+ end
127
145
 
128
146
  alias on_arg_expr process_regular_node
129
147
  alias on_restarg_expr process_regular_node
@@ -172,6 +190,14 @@ module Parser
172
190
  alias on_block process_regular_node
173
191
  alias on_lambda process_regular_node
174
192
 
193
+ def on_numblock(node)
194
+ method_call, max_numparam, body = *node
195
+
196
+ node.updated(nil, [
197
+ process(method_call), max_numparam, process(body)
198
+ ])
199
+ end
200
+
175
201
  alias on_while process_regular_node
176
202
  alias on_while_post process_regular_node
177
203
  alias on_until process_regular_node
@@ -212,6 +238,24 @@ module Parser
212
238
  alias on_preexe process_regular_node
213
239
  alias on_postexe process_regular_node
214
240
 
241
+ alias on_case_match process_regular_node
242
+ alias on_in_match process_regular_node
243
+ alias on_match_pattern process_regular_node
244
+ alias on_match_pattern_p process_regular_node
245
+ alias on_in_pattern process_regular_node
246
+ alias on_if_guard process_regular_node
247
+ alias on_unless_guard process_regular_node
248
+ alias on_match_var process_variable_node
249
+ alias on_match_rest process_regular_node
250
+ alias on_pin process_regular_node
251
+ alias on_match_alt process_regular_node
252
+ alias on_match_as process_regular_node
253
+ alias on_array_pattern process_regular_node
254
+ alias on_array_pattern_with_tail process_regular_node
255
+ alias on_hash_pattern process_regular_node
256
+ alias on_const_pattern process_regular_node
257
+ alias on_find_pattern process_regular_node
258
+
215
259
  # @private
216
260
  def process_variable_node(node)
217
261
  warn 'Parser::AST::Processor#process_variable_node is deprecated as a' \
@@ -235,6 +279,10 @@ module Parser
235
279
  'Parser::AST::Processor#on_argument instead.'
236
280
  on_argument(node)
237
281
  end
282
+
283
+ def on_empty_else(node)
284
+ node
285
+ end
238
286
  end
239
287
  end
240
288
  end
data/lib/parser/base.rb CHANGED
@@ -109,11 +109,16 @@ module Parser
109
109
  end
110
110
  private_class_method :setup_source_buffer
111
111
 
112
+ attr_reader :lexer
112
113
  attr_reader :diagnostics
113
114
  attr_reader :builder
114
115
  attr_reader :static_env
115
116
  attr_reader :source_buffer
116
117
  attr_reader :context
118
+ attr_reader :max_numparam_stack
119
+ attr_reader :current_arg_stack
120
+ attr_reader :pattern_variables
121
+ attr_reader :pattern_hash_keys
117
122
 
118
123
  ##
119
124
  # @param [Parser::Builders::Default] builder The AST builder to use.
@@ -123,13 +128,28 @@ module Parser
123
128
 
124
129
  @static_env = StaticEnvironment.new
125
130
 
131
+ # Stack that holds current parsing context
132
+ @context = Context.new
133
+
134
+ # Maximum numbered parameters stack
135
+ @max_numparam_stack = MaxNumparamStack.new
136
+
137
+ # Current argument names stack
138
+ @current_arg_stack = CurrentArgStack.new
139
+
140
+ # Stack of set of variables used in the current pattern
141
+ @pattern_variables = VariablesStack.new
142
+
143
+ # Stack of set of keys used in the current hash in pattern matchinig
144
+ @pattern_hash_keys = VariablesStack.new
145
+
126
146
  @lexer = Lexer.new(version)
127
147
  @lexer.diagnostics = @diagnostics
128
148
  @lexer.static_env = @static_env
149
+ @lexer.context = @context
129
150
 
130
151
  @builder = builder
131
152
  @builder.parser = self
132
- @context = Context.new
133
153
 
134
154
  # Last emitted token
135
155
  @last_token = nil
@@ -150,21 +170,24 @@ module Parser
150
170
  @lexer.reset
151
171
  @static_env.reset
152
172
  @context.reset
173
+ @current_arg_stack.reset
174
+ @pattern_variables.reset
175
+ @pattern_hash_keys.reset
153
176
 
154
177
  self
155
178
  end
156
179
 
157
180
  ##
158
- # Parses a source buffer and returns the AST.
181
+ # Parses a source buffer and returns the AST, or `nil` in case of a non fatal error.
159
182
  #
160
183
  # @param [Parser::Source::Buffer] source_buffer The source buffer to parse.
161
- # @return [Parser::AST::Node]
184
+ # @return [Parser::AST::Node, nil]
162
185
  #
163
186
  def parse(source_buffer)
164
187
  @lexer.source_buffer = source_buffer
165
188
  @source_buffer = source_buffer
166
189
 
167
- do_parse
190
+ do_parse || nil # Force `false` to `nil`, see https://github.com/ruby/racc/pull/136
168
191
  ensure
169
192
  # Don't keep references to the source file.
170
193
  @source_buffer = nil
@@ -188,8 +211,9 @@ module Parser
188
211
 
189
212
  ##
190
213
  # Parses a source buffer and returns the AST, the source code comments,
191
- # and the tokens emitted by the lexer. If `recover` is true and a fatal
192
- # {SyntaxError} is encountered, `nil` is returned instead of the AST, and
214
+ # and the tokens emitted by the lexer. In case of a fatal error, a {SyntaxError}
215
+ # is raised, unless `recover` is true. In case of an error
216
+ # (non-fatal or recovered), `nil` is returned instead of the AST, and
193
217
  # comments as well as tokens are only returned up to the location of
194
218
  # the error.
195
219
  #
@@ -82,6 +82,129 @@ module Parser
82
82
 
83
83
  @emit_index = false
84
84
 
85
+ class << self
86
+ ##
87
+ # AST compatibility attribute; causes a single non-mlhs
88
+ # block argument to be wrapped in s(:procarg0).
89
+ #
90
+ # If set to false (the default), block arguments `|a|` are emitted as
91
+ # `s(:args, s(:procarg0, :a))`
92
+ #
93
+ # If set to true, block arguments `|a|` are emitted as
94
+ # `s(:args, s(:procarg0, s(:arg, :a))`
95
+ #
96
+ # @return [Boolean]
97
+ attr_accessor :emit_arg_inside_procarg0
98
+ end
99
+
100
+ @emit_arg_inside_procarg0 = false
101
+
102
+ class << self
103
+ ##
104
+ # AST compatibility attribute; arguments forwarding initially
105
+ # didn't have support for leading arguments
106
+ # (i.e. `def m(a, ...); end` was a syntax error). However, Ruby 3.0
107
+ # added support for any number of arguments in front of the `...`.
108
+ #
109
+ # If set to false (the default):
110
+ # 1. `def m(...) end` is emitted as
111
+ # s(:def, :m, s(:forward_args), nil)
112
+ # 2. `def m(a, b, ...) end` is emitted as
113
+ # s(:def, :m,
114
+ # s(:args, s(:arg, :a), s(:arg, :b), s(:forward_arg)))
115
+ #
116
+ # If set to true it uses a single format:
117
+ # 1. `def m(...) end` is emitted as
118
+ # s(:def, :m, s(:args, s(:forward_arg)))
119
+ # 2. `def m(a, b, ...) end` is emitted as
120
+ # s(:def, :m, s(:args, s(:arg, :a), s(:arg, :b), s(:forward_arg)))
121
+ #
122
+ # It does't matter that much on 2.7 (because there can't be any leading arguments),
123
+ # but on 3.0 it should be better enabled to use a single AST format.
124
+ #
125
+ # @return [Boolean]
126
+ attr_accessor :emit_forward_arg
127
+ end
128
+
129
+ @emit_forward_arg = false
130
+
131
+ class << self
132
+ ##
133
+ # AST compatibility attribute; Starting from Ruby 2.7 keyword arguments
134
+ # of method calls that are passed explicitly as a hash (i.e. with curly braces)
135
+ # are treated as positional arguments and Ruby 2.7 emits a warning on such method
136
+ # call. Ruby 3.0 given an ArgumentError.
137
+ #
138
+ # If set to false (the default) the last hash argument is emitted as `hash`:
139
+ #
140
+ # ```
141
+ # (send nil :foo
142
+ # (hash
143
+ # (pair
144
+ # (sym :bar)
145
+ # (int 42))))
146
+ # ```
147
+ #
148
+ # If set to true it is emitted as `kwargs`:
149
+ #
150
+ # ```
151
+ # (send nil :foo
152
+ # (kwargs
153
+ # (pair
154
+ # (sym :bar)
155
+ # (int 42))))
156
+ # ```
157
+ #
158
+ # Note that `kwargs` node is just a replacement for `hash` argument,
159
+ # so if there's are multiple arguments (or a `kwsplat`) all of them
160
+ # are wrapped into `kwargs` instead of `hash`:
161
+ #
162
+ # ```
163
+ # (send nil :foo
164
+ # (hash
165
+ # (pair
166
+ # (sym :a)
167
+ # (int 42))
168
+ # (kwsplat
169
+ # (send nil :b))
170
+ # (pair
171
+ # (sym :c)
172
+ # (int 10))))
173
+ # ```
174
+ attr_accessor :emit_kwargs
175
+ end
176
+
177
+ @emit_kwargs = false
178
+
179
+ class << self
180
+ ##
181
+ # AST compatibility attribute; Starting from 3.0 Ruby returns
182
+ # true/false from single-line pattern matching with `in` keyword.
183
+ #
184
+ # Before 3.0 there was an exception if given value doesn't match pattern.
185
+ #
186
+ # NOTE: This attribute affects only Ruby 2.7 grammar.
187
+ # 3.0 grammar always emits `match_pattern`/`match_pattern_p`
188
+ #
189
+ # If compatibility attribute set to false `foo in bar` is emitted as `in_match`:
190
+ #
191
+ # ```
192
+ # (in-match
193
+ # (send nil :foo)
194
+ # (match-var :bar))
195
+ # ```
196
+ #
197
+ # If set to true it's emitted as `match_pattern_p`:
198
+ # ```
199
+ # (match-pattern-p
200
+ # (send nil :foo)
201
+ # (match-var :bar))
202
+ # ```
203
+ attr_accessor :emit_match_pattern
204
+ end
205
+
206
+ @emit_match_pattern = false
207
+
85
208
  class << self
86
209
  ##
87
210
  # @api private
@@ -90,6 +213,10 @@ module Parser
90
213
  @emit_procarg0 = true
91
214
  @emit_encoding = true
92
215
  @emit_index = true
216
+ @emit_arg_inside_procarg0 = true
217
+ @emit_forward_arg = true
218
+ @emit_kwargs = true
219
+ @emit_match_pattern = true
93
220
  end
94
221
  end
95
222
 
@@ -262,18 +389,23 @@ module Parser
262
389
  if !dedent_level.nil?
263
390
  dedenter = Lexer::Dedenter.new(dedent_level)
264
391
 
265
- if node.type == :str
392
+ case node.type
393
+ when :str
266
394
  str = node.children.first
267
395
  dedenter.dedent(str)
268
- elsif node.type == :dstr || node.type == :xstr
269
- node.children.each do |str_node|
396
+ when :dstr, :xstr
397
+ children = node.children.map do |str_node|
270
398
  if str_node.type == :str
271
399
  str = str_node.children.first
272
400
  dedenter.dedent(str)
401
+ next nil if str.empty?
273
402
  else
274
403
  dedenter.interrupt
275
404
  end
405
+ str_node
276
406
  end
407
+
408
+ node = node.updated(nil, children.compact)
277
409
  end
278
410
  end
279
411
 
@@ -400,12 +532,12 @@ module Parser
400
532
 
401
533
  def range_inclusive(lhs, dot2_t, rhs)
402
534
  n(:irange, [ lhs, rhs ],
403
- binary_op_map(lhs, dot2_t, rhs))
535
+ range_map(lhs, dot2_t, rhs))
404
536
  end
405
537
 
406
538
  def range_exclusive(lhs, dot3_t, rhs)
407
539
  n(:erange, [ lhs, rhs ],
408
- binary_op_map(lhs, dot3_t, rhs))
540
+ range_map(lhs, dot3_t, rhs))
409
541
  end
410
542
 
411
543
  #
@@ -477,6 +609,11 @@ module Parser
477
609
  name, = *node
478
610
 
479
611
  if @parser.static_env.declared?(name)
612
+ if name.to_s == parser.current_arg_stack.top
613
+ diagnostic :error, :circular_argument_reference,
614
+ { :var_name => name.to_s }, node.loc.expression
615
+ end
616
+
480
617
  node.updated(:lvar)
481
618
  else
482
619
  name, = *node
@@ -535,6 +672,13 @@ module Parser
535
672
 
536
673
  when :ident
537
674
  name, = *node
675
+
676
+ var_name = node.children[0].to_s
677
+ name_loc = node.loc.expression
678
+
679
+ check_assignment_to_numparam(var_name, name_loc)
680
+ check_reserved_for_numparam(var_name, name_loc)
681
+
538
682
  @parser.static_env.declare(name)
539
683
 
540
684
  node.updated(:lvasgn)
@@ -624,23 +768,38 @@ module Parser
624
768
 
625
769
  def def_method(def_t, name_t, args,
626
770
  body, end_t)
771
+ check_reserved_for_numparam(value(name_t), loc(name_t))
772
+
627
773
  n(:def, [ value(name_t).to_sym, args, body ],
628
774
  definition_map(def_t, nil, name_t, end_t))
629
775
  end
630
776
 
777
+ def def_endless_method(def_t, name_t, args,
778
+ assignment_t, body)
779
+ check_reserved_for_numparam(value(name_t), loc(name_t))
780
+
781
+ n(:def, [ value(name_t).to_sym, args, body ],
782
+ endless_definition_map(def_t, nil, name_t, assignment_t, body))
783
+ end
784
+
631
785
  def def_singleton(def_t, definee, dot_t,
632
786
  name_t, args,
633
787
  body, end_t)
634
- case definee.type
635
- when :int, :str, :dstr, :sym, :dsym,
636
- :regexp, :array, :hash
788
+ validate_definee(definee)
789
+ check_reserved_for_numparam(value(name_t), loc(name_t))
637
790
 
638
- diagnostic :error, :singleton_literal, nil, definee.loc.expression
791
+ n(:defs, [ definee, value(name_t).to_sym, args, body ],
792
+ definition_map(def_t, dot_t, name_t, end_t))
793
+ end
639
794
 
640
- else
641
- n(:defs, [ definee, value(name_t).to_sym, args, body ],
642
- definition_map(def_t, dot_t, name_t, end_t))
643
- end
795
+ def def_endless_singleton(def_t, definee, dot_t,
796
+ name_t, args,
797
+ assignment_t, body)
798
+ validate_definee(definee)
799
+ check_reserved_for_numparam(value(name_t), loc(name_t))
800
+
801
+ n(:defs, [ definee, value(name_t).to_sym, args, body ],
802
+ endless_definition_map(def_t, dot_t, name_t, assignment_t, body))
644
803
  end
645
804
 
646
805
  def undef_method(undef_t, names)
@@ -663,12 +822,34 @@ module Parser
663
822
  collection_map(begin_t, args, end_t))
664
823
  end
665
824
 
825
+ def numargs(max_numparam)
826
+ n(:numargs, [ max_numparam ], nil)
827
+ end
828
+
829
+ def forward_only_args(begin_t, dots_t, end_t)
830
+ if self.class.emit_forward_arg
831
+ arg = forward_arg(dots_t)
832
+ n(:args, [ arg ],
833
+ collection_map(begin_t, [ arg ], end_t))
834
+ else
835
+ n(:forward_args, [], collection_map(begin_t, token_map(dots_t), end_t))
836
+ end
837
+ end
838
+
839
+ def forward_arg(dots_t)
840
+ n(:forward_arg, [], token_map(dots_t))
841
+ end
842
+
666
843
  def arg(name_t)
844
+ check_reserved_for_numparam(value(name_t), loc(name_t))
845
+
667
846
  n(:arg, [ value(name_t).to_sym ],
668
847
  variable_map(name_t))
669
848
  end
670
849
 
671
850
  def optarg(name_t, eql_t, value)
851
+ check_reserved_for_numparam(value(name_t), loc(name_t))
852
+
672
853
  n(:optarg, [ value(name_t).to_sym, value ],
673
854
  variable_map(name_t).
674
855
  with_operator(loc(eql_t)).
@@ -677,6 +858,7 @@ module Parser
677
858
 
678
859
  def restarg(star_t, name_t=nil)
679
860
  if name_t
861
+ check_reserved_for_numparam(value(name_t), loc(name_t))
680
862
  n(:restarg, [ value(name_t).to_sym ],
681
863
  arg_prefix_map(star_t, name_t))
682
864
  else
@@ -686,17 +868,23 @@ module Parser
686
868
  end
687
869
 
688
870
  def kwarg(name_t)
871
+ check_reserved_for_numparam(value(name_t), loc(name_t))
872
+
689
873
  n(:kwarg, [ value(name_t).to_sym ],
690
874
  kwarg_map(name_t))
691
875
  end
692
876
 
693
877
  def kwoptarg(name_t, value)
878
+ check_reserved_for_numparam(value(name_t), loc(name_t))
879
+
694
880
  n(:kwoptarg, [ value(name_t).to_sym, value ],
695
881
  kwarg_map(name_t, value))
696
882
  end
697
883
 
698
884
  def kwrestarg(dstar_t, name_t=nil)
699
885
  if name_t
886
+ check_reserved_for_numparam(value(name_t), loc(name_t))
887
+
700
888
  n(:kwrestarg, [ value(name_t).to_sym ],
701
889
  arg_prefix_map(dstar_t, name_t))
702
890
  else
@@ -705,19 +893,33 @@ module Parser
705
893
  end
706
894
  end
707
895
 
896
+ def kwnilarg(dstar_t, nil_t)
897
+ n0(:kwnilarg,
898
+ arg_prefix_map(dstar_t, nil_t))
899
+ end
900
+
708
901
  def shadowarg(name_t)
902
+ check_reserved_for_numparam(value(name_t), loc(name_t))
903
+
709
904
  n(:shadowarg, [ value(name_t).to_sym ],
710
905
  variable_map(name_t))
711
906
  end
712
907
 
713
908
  def blockarg(amper_t, name_t)
909
+ check_reserved_for_numparam(value(name_t), loc(name_t))
910
+
714
911
  n(:blockarg, [ value(name_t).to_sym ],
715
912
  arg_prefix_map(amper_t, name_t))
716
913
  end
717
914
 
718
915
  def procarg0(arg)
719
916
  if self.class.emit_procarg0
720
- arg.updated(:procarg0)
917
+ if arg.type == :arg && self.class.emit_arg_inside_procarg0
918
+ n(:procarg0, [ arg ],
919
+ Source::Map::Collection.new(nil, nil, arg.location.expression))
920
+ else
921
+ arg.updated(:procarg0)
922
+ end
721
923
  else
722
924
  arg
723
925
  end
@@ -802,9 +1004,18 @@ module Parser
802
1004
  end
803
1005
  end
804
1006
 
1007
+ def forwarded_args(dots_t)
1008
+ n(:forwarded_args, [], token_map(dots_t))
1009
+ end
1010
+
805
1011
  def call_method(receiver, dot_t, selector_t,
806
1012
  lparen_t=nil, args=[], rparen_t=nil)
807
1013
  type = call_type_for_dot(dot_t)
1014
+
1015
+ if self.class.emit_kwargs
1016
+ rewrite_hash_args_to_kwargs(args)
1017
+ end
1018
+
808
1019
  if selector_t.nil?
809
1020
  n(type, [ receiver, :call, *args ],
810
1021
  send_map(receiver, dot_t, nil, lparen_t, args, rparen_t))
@@ -831,19 +1042,26 @@ module Parser
831
1042
  end
832
1043
 
833
1044
  last_arg = call_args.last
834
- if last_arg && last_arg.type == :block_pass
1045
+ if last_arg && (last_arg.type == :block_pass || last_arg.type == :forwarded_args)
835
1046
  diagnostic :error, :block_and_blockarg, nil, last_arg.loc.expression, [loc(begin_t)]
836
1047
  end
837
1048
 
1049
+ if args.type == :numargs
1050
+ block_type = :numblock
1051
+ args = args.children[0]
1052
+ else
1053
+ block_type = :block
1054
+ end
1055
+
838
1056
  if [:send, :csend, :index, :super, :zsuper, :lambda].include?(method_call.type)
839
- n(:block, [ method_call, args, body ],
1057
+ n(block_type, [ method_call, args, body ],
840
1058
  block_map(method_call.loc.expression, begin_t, end_t))
841
1059
  else
842
1060
  # Code like "return foo 1 do end" is reduced in a weird sequence.
843
1061
  # Here, method_call is actually (return).
844
1062
  actual_send, = *method_call
845
1063
  block =
846
- n(:block, [ actual_send, args, body ],
1064
+ n(block_type, [ actual_send, args, body ],
847
1065
  block_map(actual_send.loc.expression, begin_t, end_t))
848
1066
 
849
1067
  n(method_call.type, [ block ],
@@ -875,6 +1093,10 @@ module Parser
875
1093
  end
876
1094
 
877
1095
  def index(receiver, lbrack_t, indexes, rbrack_t)
1096
+ if self.class.emit_kwargs
1097
+ rewrite_hash_args_to_kwargs(indexes)
1098
+ end
1099
+
878
1100
  if self.class.emit_index
879
1101
  n(:index, [ receiver, *indexes ],
880
1102
  index_map(receiver, lbrack_t, rbrack_t))
@@ -1037,6 +1259,10 @@ module Parser
1037
1259
  end
1038
1260
  end
1039
1261
 
1262
+ if %i[yield super].include?(type) && self.class.emit_kwargs
1263
+ rewrite_hash_args_to_kwargs(args)
1264
+ end
1265
+
1040
1266
  n(type, args,
1041
1267
  keyword_map(keyword_t, lparen_t, args, rparen_t))
1042
1268
  end
@@ -1155,6 +1381,219 @@ module Parser
1155
1381
  end
1156
1382
  end
1157
1383
 
1384
+ #
1385
+ # PATTERN MATCHING
1386
+ #
1387
+
1388
+ def case_match(case_t, expr, in_bodies, else_t, else_body, end_t)
1389
+ else_body = n(:empty_else, nil, token_map(else_t)) if else_t && !else_body
1390
+ n(:case_match, [ expr, *(in_bodies << else_body)],
1391
+ condition_map(case_t, expr, nil, nil, else_t, else_body, end_t))
1392
+ end
1393
+
1394
+ def in_match(lhs, in_t, rhs)
1395
+ n(:in_match, [lhs, rhs],
1396
+ binary_op_map(lhs, in_t, rhs))
1397
+ end
1398
+
1399
+ def match_pattern(lhs, match_t, rhs)
1400
+ n(:match_pattern, [lhs, rhs],
1401
+ binary_op_map(lhs, match_t, rhs))
1402
+ end
1403
+
1404
+ def match_pattern_p(lhs, match_t, rhs)
1405
+ n(:match_pattern_p, [lhs, rhs],
1406
+ binary_op_map(lhs, match_t, rhs))
1407
+ end
1408
+
1409
+ def in_pattern(in_t, pattern, guard, then_t, body)
1410
+ children = [pattern, guard, body]
1411
+ n(:in_pattern, children,
1412
+ keyword_map(in_t, then_t, children.compact, nil))
1413
+ end
1414
+
1415
+ def if_guard(if_t, if_body)
1416
+ n(:if_guard, [if_body], guard_map(if_t, if_body))
1417
+ end
1418
+
1419
+ def unless_guard(unless_t, unless_body)
1420
+ n(:unless_guard, [unless_body], guard_map(unless_t, unless_body))
1421
+ end
1422
+
1423
+ def match_var(name_t)
1424
+ name = value(name_t).to_sym
1425
+ name_l = loc(name_t)
1426
+
1427
+ check_lvar_name(name, name_l)
1428
+ check_duplicate_pattern_variable(name, name_l)
1429
+ @parser.static_env.declare(name)
1430
+
1431
+ n(:match_var, [ name ],
1432
+ variable_map(name_t))
1433
+ end
1434
+
1435
+ def match_hash_var(name_t)
1436
+ name = value(name_t).to_sym
1437
+
1438
+ expr_l = loc(name_t)
1439
+ name_l = expr_l.adjust(end_pos: -1)
1440
+
1441
+ check_lvar_name(name, name_l)
1442
+ check_duplicate_pattern_variable(name, name_l)
1443
+ @parser.static_env.declare(name)
1444
+
1445
+ n(:match_var, [ name ],
1446
+ Source::Map::Variable.new(name_l, expr_l))
1447
+ end
1448
+
1449
+ def match_hash_var_from_str(begin_t, strings, end_t)
1450
+ if strings.length > 1
1451
+ diagnostic :error, :pm_interp_in_var_name, nil, loc(begin_t).join(loc(end_t))
1452
+ end
1453
+
1454
+ string = strings[0]
1455
+
1456
+ case string.type
1457
+ when :str
1458
+ # MRI supports plain strings in hash pattern matching
1459
+ name, = *string
1460
+ name_l = string.loc.expression
1461
+
1462
+ check_lvar_name(name, name_l)
1463
+ check_duplicate_pattern_variable(name, name_l)
1464
+
1465
+ @parser.static_env.declare(name)
1466
+
1467
+ if (begin_l = string.loc.begin)
1468
+ # exclude beginning of the string from the location of the variable
1469
+ name_l = name_l.adjust(begin_pos: begin_l.length)
1470
+ end
1471
+
1472
+ if (end_l = string.loc.end)
1473
+ # exclude end of the string from the location of the variable
1474
+ name_l = name_l.adjust(end_pos: -end_l.length)
1475
+ end
1476
+
1477
+ expr_l = loc(begin_t).join(string.loc.expression).join(loc(end_t))
1478
+ n(:match_var, [ name.to_sym ],
1479
+ Source::Map::Variable.new(name_l, expr_l))
1480
+ when :begin
1481
+ match_hash_var_from_str(begin_t, string.children, end_t)
1482
+ else
1483
+ # we only can get here if there is an interpolation, e.g., ``in "#{ a }":`
1484
+ diagnostic :error, :pm_interp_in_var_name, nil, loc(begin_t).join(loc(end_t))
1485
+ end
1486
+ end
1487
+
1488
+ def match_rest(star_t, name_t = nil)
1489
+ if name_t.nil?
1490
+ n0(:match_rest,
1491
+ unary_op_map(star_t))
1492
+ else
1493
+ name = match_var(name_t)
1494
+ n(:match_rest, [ name ],
1495
+ unary_op_map(star_t, name))
1496
+ end
1497
+ end
1498
+
1499
+ def hash_pattern(lbrace_t, kwargs, rbrace_t)
1500
+ args = check_duplicate_args(kwargs)
1501
+ n(:hash_pattern, args,
1502
+ collection_map(lbrace_t, args, rbrace_t))
1503
+ end
1504
+
1505
+ def array_pattern(lbrack_t, elements, rbrack_t)
1506
+ return n(:array_pattern, nil, collection_map(lbrack_t, [], rbrack_t)) if elements.nil?
1507
+
1508
+ trailing_comma = false
1509
+
1510
+ node_elements = elements.map do |element|
1511
+ if element.type == :match_with_trailing_comma
1512
+ trailing_comma = true
1513
+ element.children.first
1514
+ else
1515
+ trailing_comma = false
1516
+ element
1517
+ end
1518
+ end
1519
+
1520
+ node_type = trailing_comma ? :array_pattern_with_tail : :array_pattern
1521
+
1522
+ n(node_type, node_elements,
1523
+ collection_map(lbrack_t, elements, rbrack_t))
1524
+ end
1525
+
1526
+ def find_pattern(lbrack_t, elements, rbrack_t)
1527
+ n(:find_pattern, elements,
1528
+ collection_map(lbrack_t, elements, rbrack_t))
1529
+ end
1530
+
1531
+ def match_with_trailing_comma(match, comma_t)
1532
+ n(:match_with_trailing_comma, [ match ], expr_map(match.loc.expression.join(loc(comma_t))))
1533
+ end
1534
+
1535
+ def const_pattern(const, ldelim_t, pattern, rdelim_t)
1536
+ n(:const_pattern, [const, pattern],
1537
+ Source::Map::Collection.new(
1538
+ loc(ldelim_t), loc(rdelim_t),
1539
+ const.loc.expression.join(loc(rdelim_t))
1540
+ )
1541
+ )
1542
+ end
1543
+
1544
+ def pin(pin_t, var)
1545
+ n(:pin, [ var ],
1546
+ send_unary_op_map(pin_t, var))
1547
+ end
1548
+
1549
+ def match_alt(left, pipe_t, right)
1550
+ source_map = binary_op_map(left, pipe_t, right)
1551
+
1552
+ n(:match_alt, [ left, right ],
1553
+ source_map)
1554
+ end
1555
+
1556
+ def match_as(value, assoc_t, as)
1557
+ source_map = binary_op_map(value, assoc_t, as)
1558
+
1559
+ n(:match_as, [ value, as ],
1560
+ source_map)
1561
+ end
1562
+
1563
+ def match_nil_pattern(dstar_t, nil_t)
1564
+ n0(:match_nil_pattern,
1565
+ arg_prefix_map(dstar_t, nil_t))
1566
+ end
1567
+
1568
+ def match_pair(label_type, label, value)
1569
+ if label_type == :label
1570
+ check_duplicate_pattern_key(label[0], label[1])
1571
+ pair_keyword(label, value)
1572
+ else
1573
+ begin_t, parts, end_t = label
1574
+ label_loc = loc(begin_t).join(loc(end_t))
1575
+
1576
+ # quoted label like "label": value
1577
+ if (var_name = static_string(parts))
1578
+ check_duplicate_pattern_key(var_name, label_loc)
1579
+ else
1580
+ diagnostic :error, :pm_interp_in_var_name, nil, label_loc
1581
+ end
1582
+
1583
+ pair_quoted(begin_t, parts, end_t, value)
1584
+ end
1585
+ end
1586
+
1587
+ def match_label(label_type, label)
1588
+ if label_type == :label
1589
+ match_hash_var(label)
1590
+ else
1591
+ # quoted label like "label": value
1592
+ begin_t, strings, end_t = label
1593
+ match_hash_var_from_str(begin_t, strings, end_t)
1594
+ end
1595
+ end
1596
+
1158
1597
  private
1159
1598
 
1160
1599
  #
@@ -1210,18 +1649,18 @@ module Parser
1210
1649
  case this_arg.type
1211
1650
  when :arg, :optarg, :restarg, :blockarg,
1212
1651
  :kwarg, :kwoptarg, :kwrestarg,
1213
- :shadowarg, :procarg0
1652
+ :shadowarg
1214
1653
 
1215
- this_name, = *this_arg
1654
+ check_duplicate_arg(this_arg, map)
1216
1655
 
1217
- that_arg = map[this_name]
1218
- that_name, = *that_arg
1656
+ when :procarg0
1219
1657
 
1220
- if that_arg.nil?
1221
- map[this_name] = this_arg
1222
- elsif arg_name_collides?(this_name, that_name)
1223
- diagnostic :error, :duplicate_argument, nil,
1224
- this_arg.loc.name, [ that_arg.loc.name ]
1658
+ if this_arg.children[0].is_a?(Symbol)
1659
+ # s(:procarg0, :a)
1660
+ check_duplicate_arg(this_arg, map)
1661
+ else
1662
+ # s(:procarg0, s(:arg, :a), ...)
1663
+ check_duplicate_args(this_arg.children, map)
1225
1664
  end
1226
1665
 
1227
1666
  when :mlhs
@@ -1230,6 +1669,45 @@ module Parser
1230
1669
  end
1231
1670
  end
1232
1671
 
1672
+ def check_duplicate_arg(this_arg, map={})
1673
+ this_name, = *this_arg
1674
+
1675
+ that_arg = map[this_name]
1676
+ that_name, = *that_arg
1677
+
1678
+ if that_arg.nil?
1679
+ map[this_name] = this_arg
1680
+ elsif arg_name_collides?(this_name, that_name)
1681
+ diagnostic :error, :duplicate_argument, nil,
1682
+ this_arg.loc.name, [ that_arg.loc.name ]
1683
+ end
1684
+ end
1685
+
1686
+ def check_assignment_to_numparam(name, loc)
1687
+ # MRI < 2.7 treats numbered parameters as regular variables
1688
+ # and so it's allowed to perform assignments like `_1 = 42`.
1689
+ return if @parser.version < 27
1690
+
1691
+ assigning_to_numparam =
1692
+ @parser.context.in_dynamic_block? &&
1693
+ name =~ /\A_([1-9])\z/ &&
1694
+ @parser.max_numparam_stack.has_numparams?
1695
+
1696
+ if assigning_to_numparam
1697
+ diagnostic :error, :cant_assign_to_numparam, { :name => name }, loc
1698
+ end
1699
+ end
1700
+
1701
+ def check_reserved_for_numparam(name, loc)
1702
+ # MRI < 3.0 accepts assignemnt to variables like _1
1703
+ # if it's not a numbered parameter. MRI 3.0 and newer throws an error.
1704
+ return if @parser.version < 30
1705
+
1706
+ if name =~ /\A_([1-9])\z/
1707
+ diagnostic :error, :reserved_for_numparam, { :name => name }, loc
1708
+ end
1709
+ end
1710
+
1233
1711
  def arg_name_collides?(this_name, that_name)
1234
1712
  case @parser.version
1235
1713
  when 18
@@ -1245,6 +1723,32 @@ module Parser
1245
1723
  end
1246
1724
  end
1247
1725
 
1726
+ def check_lvar_name(name, loc)
1727
+ if name =~ /\A[[[:lower:]]_][[[:alnum:]]_]*\z/
1728
+ # OK
1729
+ else
1730
+ diagnostic :error, :lvar_name, { name: name }, loc
1731
+ end
1732
+ end
1733
+
1734
+ def check_duplicate_pattern_variable(name, loc)
1735
+ return if name.to_s.start_with?('_')
1736
+
1737
+ if @parser.pattern_variables.declared?(name)
1738
+ diagnostic :error, :duplicate_variable_name, { name: name.to_s }, loc
1739
+ end
1740
+
1741
+ @parser.pattern_variables.declare(name)
1742
+ end
1743
+
1744
+ def check_duplicate_pattern_key(name, loc)
1745
+ if @parser.pattern_hash_keys.declared?(name)
1746
+ diagnostic :error, :duplicate_pattern_key, { name: name.to_s }, loc
1747
+ end
1748
+
1749
+ @parser.pattern_hash_keys.declare(name)
1750
+ end
1751
+
1248
1752
  #
1249
1753
  # SOURCE MAPS
1250
1754
  #
@@ -1388,6 +1892,18 @@ module Parser
1388
1892
  Source::Map::Operator.new(loc(op_t), expr_l)
1389
1893
  end
1390
1894
 
1895
+ def range_map(start_e, op_t, end_e)
1896
+ if start_e && end_e
1897
+ expr_l = join_exprs(start_e, end_e)
1898
+ elsif start_e
1899
+ expr_l = start_e.loc.expression.join(loc(op_t))
1900
+ elsif end_e
1901
+ expr_l = loc(op_t).join(end_e.loc.expression)
1902
+ end
1903
+
1904
+ Source::Map::Operator.new(loc(op_t), expr_l)
1905
+ end
1906
+
1391
1907
  def arg_prefix_map(op_t, name_t=nil)
1392
1908
  if name_t.nil?
1393
1909
  expr_l = loc(op_t)
@@ -1422,9 +1938,17 @@ module Parser
1422
1938
  end
1423
1939
 
1424
1940
  def definition_map(keyword_t, operator_t, name_t, end_t)
1425
- Source::Map::Definition.new(loc(keyword_t),
1426
- loc(operator_t), loc(name_t),
1427
- loc(end_t))
1941
+ Source::Map::MethodDefinition.new(loc(keyword_t),
1942
+ loc(operator_t), loc(name_t),
1943
+ loc(end_t), nil, nil)
1944
+ end
1945
+
1946
+ def endless_definition_map(keyword_t, operator_t, name_t, assignment_t, body_e)
1947
+ body_l = body_e.loc.expression
1948
+
1949
+ Source::Map::MethodDefinition.new(loc(keyword_t),
1950
+ loc(operator_t), loc(name_t), nil,
1951
+ loc(assignment_t), body_l)
1428
1952
  end
1429
1953
 
1430
1954
  def send_map(receiver_e, dot_t, selector_t, begin_t=nil, args=[], end_t=nil)
@@ -1581,6 +2105,13 @@ module Parser
1581
2105
  begin_l.join(end_l))
1582
2106
  end
1583
2107
 
2108
+ def guard_map(keyword_t, guard_body_e)
2109
+ keyword_l = loc(keyword_t)
2110
+ guard_body_l = guard_body_e.loc.expression
2111
+
2112
+ Source::Map::Keyword.new(keyword_l, nil, nil, keyword_l.join(guard_body_l))
2113
+ end
2114
+
1584
2115
  #
1585
2116
  # HELPERS
1586
2117
  #
@@ -1662,6 +2193,32 @@ module Parser
1662
2193
  @parser.send :yyerror
1663
2194
  end
1664
2195
  end
2196
+
2197
+ def validate_definee(definee)
2198
+ case definee.type
2199
+ when :int, :str, :dstr, :sym, :dsym,
2200
+ :regexp, :array, :hash
2201
+
2202
+ diagnostic :error, :singleton_literal, nil, definee.loc.expression
2203
+ false
2204
+ else
2205
+ true
2206
+ end
2207
+ end
2208
+
2209
+ def rewrite_hash_args_to_kwargs(args)
2210
+ if args.any? && kwargs?(args.last)
2211
+ # foo(..., bar: baz)
2212
+ args[args.length - 1] = args[args.length - 1].updated(:kwargs)
2213
+ elsif args.length > 1 && args.last.type == :block_pass && kwargs?(args[args.length - 2])
2214
+ # foo(..., bar: baz, &blk)
2215
+ args[args.length - 2] = args[args.length - 2].updated(:kwargs)
2216
+ end
2217
+ end
2218
+
2219
+ def kwargs?(node)
2220
+ node.type == :hash && node.loc.begin.nil? && node.loc.end.nil?
2221
+ end
1665
2222
  end
1666
2223
 
1667
2224
  end