parser 2.6.0.0 → 3.1.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.
- checksums.yaml +4 -4
- data/lib/parser/all.rb +3 -0
- data/lib/parser/ast/processor.rb +48 -1
- data/lib/parser/base.rb +30 -6
- data/lib/parser/builders/default.rb +670 -38
- data/lib/parser/context.rb +24 -26
- data/lib/parser/current.rb +36 -9
- data/lib/parser/current_arg_stack.rb +46 -0
- data/lib/parser/diagnostic/engine.rb +1 -2
- data/lib/parser/diagnostic.rb +1 -1
- data/lib/parser/lexer/dedenter.rb +58 -49
- data/lib/parser/lexer/explanation.rb +1 -1
- data/lib/parser/lexer.rb +13837 -11893
- data/lib/parser/macruby.rb +2544 -2489
- data/lib/parser/max_numparam_stack.rb +56 -0
- data/lib/parser/messages.rb +78 -44
- data/lib/parser/meta.rb +13 -3
- data/lib/parser/ruby18.rb +2313 -2259
- data/lib/parser/ruby19.rb +2537 -2488
- data/lib/parser/ruby20.rb +2724 -2673
- data/lib/parser/ruby21.rb +2766 -2727
- data/lib/parser/ruby22.rb +2683 -2628
- data/lib/parser/ruby23.rb +2796 -2755
- data/lib/parser/ruby24.rb +2812 -2771
- data/lib/parser/ruby25.rb +2703 -2670
- data/lib/parser/ruby26.rb +2794 -2747
- data/lib/parser/ruby27.rb +7914 -0
- data/lib/parser/ruby28.rb +8047 -0
- data/lib/parser/ruby30.rb +8096 -0
- data/lib/parser/ruby31.rb +8354 -0
- data/lib/parser/rubymotion.rb +2527 -2485
- data/lib/parser/runner/ruby_parse.rb +2 -2
- data/lib/parser/runner/ruby_rewrite.rb +2 -2
- data/lib/parser/runner.rb +36 -2
- data/lib/parser/source/buffer.rb +53 -28
- data/lib/parser/source/comment/associator.rb +31 -8
- data/lib/parser/source/comment.rb +14 -1
- data/lib/parser/source/map/method_definition.rb +25 -0
- data/lib/parser/source/range.rb +19 -3
- data/lib/parser/source/tree_rewriter/action.rb +137 -28
- data/lib/parser/source/tree_rewriter.rb +144 -14
- data/lib/parser/static_environment.rb +23 -0
- data/lib/parser/tree_rewriter.rb +3 -3
- data/lib/parser/variables_stack.rb +36 -0
- data/lib/parser/version.rb +1 -1
- data/lib/parser.rb +4 -0
- data/parser.gemspec +12 -19
- metadata +34 -99
- data/.gitignore +0 -32
- data/.travis.yml +0 -45
- data/.yardopts +0 -21
- data/CHANGELOG.md +0 -943
- data/CONTRIBUTING.md +0 -17
- data/Gemfile +0 -10
- data/README.md +0 -301
- data/Rakefile +0 -165
- data/ci/run_rubocop_specs +0 -14
- data/doc/AST_FORMAT.md +0 -1735
- data/doc/CUSTOMIZATION.md +0 -37
- data/doc/INTERNALS.md +0 -21
- data/doc/css/.gitkeep +0 -0
- data/doc/css/common.css +0 -68
- data/lib/parser/lexer.rl +0 -2383
- data/lib/parser/macruby.y +0 -2198
- data/lib/parser/ruby18.y +0 -1934
- data/lib/parser/ruby19.y +0 -2175
- data/lib/parser/ruby20.y +0 -2353
- data/lib/parser/ruby21.y +0 -2357
- data/lib/parser/ruby22.y +0 -2364
- data/lib/parser/ruby23.y +0 -2370
- data/lib/parser/ruby24.y +0 -2408
- data/lib/parser/ruby25.y +0 -2405
- data/lib/parser/ruby26.y +0 -2413
- data/lib/parser/rubymotion.y +0 -2182
- data/test/bug_163/fixtures/input.rb +0 -5
- data/test/bug_163/fixtures/output.rb +0 -5
- data/test/bug_163/rewriter.rb +0 -20
- data/test/helper.rb +0 -52
- data/test/parse_helper.rb +0 -315
- data/test/racc_coverage_helper.rb +0 -133
- data/test/test_base.rb +0 -31
- data/test/test_current.rb +0 -27
- data/test/test_diagnostic.rb +0 -96
- data/test/test_diagnostic_engine.rb +0 -62
- data/test/test_encoding.rb +0 -99
- data/test/test_lexer.rb +0 -3543
- data/test/test_lexer_stack_state.rb +0 -78
- data/test/test_parse_helper.rb +0 -80
- data/test/test_parser.rb +0 -7087
- data/test/test_runner_rewrite.rb +0 -47
- data/test/test_source_buffer.rb +0 -162
- data/test/test_source_comment.rb +0 -36
- data/test/test_source_comment_associator.rb +0 -367
- data/test/test_source_map.rb +0 -15
- data/test/test_source_range.rb +0 -172
- data/test/test_source_rewriter.rb +0 -541
- data/test/test_source_rewriter_action.rb +0 -46
- data/test/test_source_tree_rewriter.rb +0 -173
- data/test/test_static_environment.rb +0 -45
- data/test/using_tree_rewriter/fixtures/input.rb +0 -3
- data/test/using_tree_rewriter/fixtures/output.rb +0 -3
- data/test/using_tree_rewriter/using_tree_rewriter.rb +0 -9
@@ -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
|
+
# (kwargs
|
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
|
-
|
392
|
+
case node.type
|
393
|
+
when :str
|
266
394
|
str = node.children.first
|
267
395
|
dedenter.dedent(str)
|
268
|
-
|
269
|
-
node.children.
|
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
|
|
@@ -386,12 +518,52 @@ module Parser
|
|
386
518
|
n(:pair, [ key, value ], pair_map)
|
387
519
|
end
|
388
520
|
|
521
|
+
def pair_label(key_t)
|
522
|
+
key_l = loc(key_t)
|
523
|
+
value_l = key_l.adjust(end_pos: -1)
|
524
|
+
|
525
|
+
label = value(key_t)
|
526
|
+
value =
|
527
|
+
if label =~ /\A[[:lower:]]/
|
528
|
+
n(:ident, [ label.to_sym ], Source::Map::Variable.new(value_l))
|
529
|
+
else
|
530
|
+
n(:const, [ nil, label.to_sym ], Source::Map::Constant.new(nil, value_l, value_l))
|
531
|
+
end
|
532
|
+
pair_keyword(key_t, accessible(value))
|
533
|
+
end
|
534
|
+
|
389
535
|
def kwsplat(dstar_t, arg)
|
390
536
|
n(:kwsplat, [ arg ],
|
391
537
|
unary_op_map(dstar_t, arg))
|
392
538
|
end
|
393
539
|
|
394
540
|
def associate(begin_t, pairs, end_t)
|
541
|
+
0.upto(pairs.length - 1) do |i|
|
542
|
+
(i + 1).upto(pairs.length - 1) do |j|
|
543
|
+
key1, = *pairs[i]
|
544
|
+
key2, = *pairs[j]
|
545
|
+
|
546
|
+
do_warn = false
|
547
|
+
|
548
|
+
# keys have to be simple nodes, MRI ignores equal composite keys like
|
549
|
+
# `{ a(1) => 1, a(1) => 1 }`
|
550
|
+
case key1.type
|
551
|
+
when :sym, :str, :int, :float
|
552
|
+
if key1 == key2
|
553
|
+
do_warn = true
|
554
|
+
end
|
555
|
+
when :rational, :complex, :regexp
|
556
|
+
if @parser.version >= 31 && key1 == key2
|
557
|
+
do_warn = true
|
558
|
+
end
|
559
|
+
end
|
560
|
+
|
561
|
+
if do_warn
|
562
|
+
diagnostic :warning, :duplicate_hash_key, nil, key2.loc.expression
|
563
|
+
end
|
564
|
+
end
|
565
|
+
end
|
566
|
+
|
395
567
|
n(:hash, [ *pairs ],
|
396
568
|
collection_map(begin_t, pairs, end_t))
|
397
569
|
end
|
@@ -476,14 +648,29 @@ module Parser
|
|
476
648
|
when :ident
|
477
649
|
name, = *node
|
478
650
|
|
479
|
-
if
|
480
|
-
|
481
|
-
|
482
|
-
|
483
|
-
|
651
|
+
if %w[? !].any? { |c| name.to_s.end_with?(c) }
|
652
|
+
diagnostic :error, :invalid_id_to_get,
|
653
|
+
{ :identifier => name.to_s }, node.loc.expression
|
654
|
+
end
|
655
|
+
|
656
|
+
# Numbered parameters are not declared anywhere,
|
657
|
+
# so they take precedence over method calls in numblock contexts
|
658
|
+
if @parser.version >= 27 && @parser.try_declare_numparam(node)
|
659
|
+
return node.updated(:lvar)
|
660
|
+
end
|
661
|
+
|
662
|
+
unless @parser.static_env.declared?(name)
|
663
|
+
return n(:send, [ nil, name ],
|
484
664
|
var_send_map(node))
|
485
665
|
end
|
486
666
|
|
667
|
+
if name.to_s == parser.current_arg_stack.top
|
668
|
+
diagnostic :error, :circular_argument_reference,
|
669
|
+
{ :var_name => name.to_s }, node.loc.expression
|
670
|
+
end
|
671
|
+
|
672
|
+
node.updated(:lvar)
|
673
|
+
|
487
674
|
else
|
488
675
|
node
|
489
676
|
end
|
@@ -527,7 +714,7 @@ module Parser
|
|
527
714
|
node.updated(:gvasgn)
|
528
715
|
|
529
716
|
when :const
|
530
|
-
|
717
|
+
if @parser.context.in_def
|
531
718
|
diagnostic :error, :dynamic_const, nil, node.loc.expression
|
532
719
|
end
|
533
720
|
|
@@ -535,10 +722,28 @@ module Parser
|
|
535
722
|
|
536
723
|
when :ident
|
537
724
|
name, = *node
|
725
|
+
|
726
|
+
var_name = node.children[0].to_s
|
727
|
+
name_loc = node.loc.expression
|
728
|
+
|
729
|
+
check_assignment_to_numparam(var_name, name_loc)
|
730
|
+
check_reserved_for_numparam(var_name, name_loc)
|
731
|
+
|
538
732
|
@parser.static_env.declare(name)
|
539
733
|
|
540
734
|
node.updated(:lvasgn)
|
541
735
|
|
736
|
+
when :match_var
|
737
|
+
name, = *node
|
738
|
+
|
739
|
+
var_name = node.children[0].to_s
|
740
|
+
name_loc = node.loc.expression
|
741
|
+
|
742
|
+
check_assignment_to_numparam(var_name, name_loc)
|
743
|
+
check_reserved_for_numparam(var_name, name_loc)
|
744
|
+
|
745
|
+
node
|
746
|
+
|
542
747
|
when :nil, :self, :true, :false,
|
543
748
|
:__FILE__, :__LINE__, :__ENCODING__
|
544
749
|
diagnostic :error, :invalid_assignment, nil, node.loc.expression
|
@@ -624,23 +829,38 @@ module Parser
|
|
624
829
|
|
625
830
|
def def_method(def_t, name_t, args,
|
626
831
|
body, end_t)
|
832
|
+
check_reserved_for_numparam(value(name_t), loc(name_t))
|
833
|
+
|
627
834
|
n(:def, [ value(name_t).to_sym, args, body ],
|
628
835
|
definition_map(def_t, nil, name_t, end_t))
|
629
836
|
end
|
630
837
|
|
838
|
+
def def_endless_method(def_t, name_t, args,
|
839
|
+
assignment_t, body)
|
840
|
+
check_reserved_for_numparam(value(name_t), loc(name_t))
|
841
|
+
|
842
|
+
n(:def, [ value(name_t).to_sym, args, body ],
|
843
|
+
endless_definition_map(def_t, nil, name_t, assignment_t, body))
|
844
|
+
end
|
845
|
+
|
631
846
|
def def_singleton(def_t, definee, dot_t,
|
632
847
|
name_t, args,
|
633
848
|
body, end_t)
|
634
|
-
|
635
|
-
|
636
|
-
:regexp, :array, :hash
|
849
|
+
validate_definee(definee)
|
850
|
+
check_reserved_for_numparam(value(name_t), loc(name_t))
|
637
851
|
|
638
|
-
|
852
|
+
n(:defs, [ definee, value(name_t).to_sym, args, body ],
|
853
|
+
definition_map(def_t, dot_t, name_t, end_t))
|
854
|
+
end
|
639
855
|
|
640
|
-
|
641
|
-
|
642
|
-
|
643
|
-
|
856
|
+
def def_endless_singleton(def_t, definee, dot_t,
|
857
|
+
name_t, args,
|
858
|
+
assignment_t, body)
|
859
|
+
validate_definee(definee)
|
860
|
+
check_reserved_for_numparam(value(name_t), loc(name_t))
|
861
|
+
|
862
|
+
n(:defs, [ definee, value(name_t).to_sym, args, body ],
|
863
|
+
endless_definition_map(def_t, dot_t, name_t, assignment_t, body))
|
644
864
|
end
|
645
865
|
|
646
866
|
def undef_method(undef_t, names)
|
@@ -659,16 +879,44 @@ module Parser
|
|
659
879
|
|
660
880
|
def args(begin_t, args, end_t, check_args=true)
|
661
881
|
args = check_duplicate_args(args) if check_args
|
662
|
-
|
663
|
-
|
882
|
+
validate_no_forward_arg_after_restarg(args)
|
883
|
+
|
884
|
+
map = collection_map(begin_t, args, end_t)
|
885
|
+
if !self.class.emit_forward_arg && args.length == 1 && args[0].type == :forward_arg
|
886
|
+
n(:forward_args, [], map)
|
887
|
+
else
|
888
|
+
n(:args, args, map)
|
889
|
+
end
|
890
|
+
end
|
891
|
+
|
892
|
+
def numargs(max_numparam)
|
893
|
+
n(:numargs, [ max_numparam ], nil)
|
894
|
+
end
|
895
|
+
|
896
|
+
def forward_only_args(begin_t, dots_t, end_t)
|
897
|
+
if self.class.emit_forward_arg
|
898
|
+
arg = forward_arg(dots_t)
|
899
|
+
n(:args, [ arg ],
|
900
|
+
collection_map(begin_t, [ arg ], end_t))
|
901
|
+
else
|
902
|
+
n(:forward_args, [], collection_map(begin_t, token_map(dots_t), end_t))
|
903
|
+
end
|
904
|
+
end
|
905
|
+
|
906
|
+
def forward_arg(dots_t)
|
907
|
+
n(:forward_arg, [], token_map(dots_t))
|
664
908
|
end
|
665
909
|
|
666
910
|
def arg(name_t)
|
911
|
+
check_reserved_for_numparam(value(name_t), loc(name_t))
|
912
|
+
|
667
913
|
n(:arg, [ value(name_t).to_sym ],
|
668
914
|
variable_map(name_t))
|
669
915
|
end
|
670
916
|
|
671
917
|
def optarg(name_t, eql_t, value)
|
918
|
+
check_reserved_for_numparam(value(name_t), loc(name_t))
|
919
|
+
|
672
920
|
n(:optarg, [ value(name_t).to_sym, value ],
|
673
921
|
variable_map(name_t).
|
674
922
|
with_operator(loc(eql_t)).
|
@@ -677,6 +925,7 @@ module Parser
|
|
677
925
|
|
678
926
|
def restarg(star_t, name_t=nil)
|
679
927
|
if name_t
|
928
|
+
check_reserved_for_numparam(value(name_t), loc(name_t))
|
680
929
|
n(:restarg, [ value(name_t).to_sym ],
|
681
930
|
arg_prefix_map(star_t, name_t))
|
682
931
|
else
|
@@ -686,17 +935,23 @@ module Parser
|
|
686
935
|
end
|
687
936
|
|
688
937
|
def kwarg(name_t)
|
938
|
+
check_reserved_for_numparam(value(name_t), loc(name_t))
|
939
|
+
|
689
940
|
n(:kwarg, [ value(name_t).to_sym ],
|
690
941
|
kwarg_map(name_t))
|
691
942
|
end
|
692
943
|
|
693
944
|
def kwoptarg(name_t, value)
|
945
|
+
check_reserved_for_numparam(value(name_t), loc(name_t))
|
946
|
+
|
694
947
|
n(:kwoptarg, [ value(name_t).to_sym, value ],
|
695
948
|
kwarg_map(name_t, value))
|
696
949
|
end
|
697
950
|
|
698
951
|
def kwrestarg(dstar_t, name_t=nil)
|
699
952
|
if name_t
|
953
|
+
check_reserved_for_numparam(value(name_t), loc(name_t))
|
954
|
+
|
700
955
|
n(:kwrestarg, [ value(name_t).to_sym ],
|
701
956
|
arg_prefix_map(dstar_t, name_t))
|
702
957
|
else
|
@@ -705,19 +960,36 @@ module Parser
|
|
705
960
|
end
|
706
961
|
end
|
707
962
|
|
963
|
+
def kwnilarg(dstar_t, nil_t)
|
964
|
+
n0(:kwnilarg,
|
965
|
+
arg_prefix_map(dstar_t, nil_t))
|
966
|
+
end
|
967
|
+
|
708
968
|
def shadowarg(name_t)
|
969
|
+
check_reserved_for_numparam(value(name_t), loc(name_t))
|
970
|
+
|
709
971
|
n(:shadowarg, [ value(name_t).to_sym ],
|
710
972
|
variable_map(name_t))
|
711
973
|
end
|
712
974
|
|
713
975
|
def blockarg(amper_t, name_t)
|
714
|
-
|
976
|
+
if !name_t.nil?
|
977
|
+
check_reserved_for_numparam(value(name_t), loc(name_t))
|
978
|
+
end
|
979
|
+
|
980
|
+
arg_name = name_t ? value(name_t).to_sym : nil
|
981
|
+
n(:blockarg, [ arg_name ],
|
715
982
|
arg_prefix_map(amper_t, name_t))
|
716
983
|
end
|
717
984
|
|
718
985
|
def procarg0(arg)
|
719
986
|
if self.class.emit_procarg0
|
720
|
-
arg.
|
987
|
+
if arg.type == :arg && self.class.emit_arg_inside_procarg0
|
988
|
+
n(:procarg0, [ arg ],
|
989
|
+
Source::Map::Collection.new(nil, nil, arg.location.expression))
|
990
|
+
else
|
991
|
+
arg.updated(:procarg0)
|
992
|
+
end
|
721
993
|
else
|
722
994
|
arg
|
723
995
|
end
|
@@ -802,9 +1074,18 @@ module Parser
|
|
802
1074
|
end
|
803
1075
|
end
|
804
1076
|
|
1077
|
+
def forwarded_args(dots_t)
|
1078
|
+
n(:forwarded_args, [], token_map(dots_t))
|
1079
|
+
end
|
1080
|
+
|
805
1081
|
def call_method(receiver, dot_t, selector_t,
|
806
1082
|
lparen_t=nil, args=[], rparen_t=nil)
|
807
1083
|
type = call_type_for_dot(dot_t)
|
1084
|
+
|
1085
|
+
if self.class.emit_kwargs
|
1086
|
+
rewrite_hash_args_to_kwargs(args)
|
1087
|
+
end
|
1088
|
+
|
808
1089
|
if selector_t.nil?
|
809
1090
|
n(type, [ receiver, :call, *args ],
|
810
1091
|
send_map(receiver, dot_t, nil, lparen_t, args, rparen_t))
|
@@ -831,19 +1112,26 @@ module Parser
|
|
831
1112
|
end
|
832
1113
|
|
833
1114
|
last_arg = call_args.last
|
834
|
-
if last_arg && last_arg.type == :block_pass
|
1115
|
+
if last_arg && (last_arg.type == :block_pass || last_arg.type == :forwarded_args)
|
835
1116
|
diagnostic :error, :block_and_blockarg, nil, last_arg.loc.expression, [loc(begin_t)]
|
836
1117
|
end
|
837
1118
|
|
1119
|
+
if args.type == :numargs
|
1120
|
+
block_type = :numblock
|
1121
|
+
args = args.children[0]
|
1122
|
+
else
|
1123
|
+
block_type = :block
|
1124
|
+
end
|
1125
|
+
|
838
1126
|
if [:send, :csend, :index, :super, :zsuper, :lambda].include?(method_call.type)
|
839
|
-
n(
|
1127
|
+
n(block_type, [ method_call, args, body ],
|
840
1128
|
block_map(method_call.loc.expression, begin_t, end_t))
|
841
1129
|
else
|
842
1130
|
# Code like "return foo 1 do end" is reduced in a weird sequence.
|
843
1131
|
# Here, method_call is actually (return).
|
844
1132
|
actual_send, = *method_call
|
845
1133
|
block =
|
846
|
-
n(
|
1134
|
+
n(block_type, [ actual_send, args, body ],
|
847
1135
|
block_map(actual_send.loc.expression, begin_t, end_t))
|
848
1136
|
|
849
1137
|
n(method_call.type, [ block ],
|
@@ -875,6 +1163,10 @@ module Parser
|
|
875
1163
|
end
|
876
1164
|
|
877
1165
|
def index(receiver, lbrack_t, indexes, rbrack_t)
|
1166
|
+
if self.class.emit_kwargs
|
1167
|
+
rewrite_hash_args_to_kwargs(indexes)
|
1168
|
+
end
|
1169
|
+
|
878
1170
|
if self.class.emit_index
|
879
1171
|
n(:index, [ receiver, *indexes ],
|
880
1172
|
index_map(receiver, lbrack_t, rbrack_t))
|
@@ -1037,6 +1329,10 @@ module Parser
|
|
1037
1329
|
end
|
1038
1330
|
end
|
1039
1331
|
|
1332
|
+
if %i[yield super].include?(type) && self.class.emit_kwargs
|
1333
|
+
rewrite_hash_args_to_kwargs(args)
|
1334
|
+
end
|
1335
|
+
|
1040
1336
|
n(type, args,
|
1041
1337
|
keyword_map(keyword_t, lparen_t, args, rparen_t))
|
1042
1338
|
end
|
@@ -1155,6 +1451,219 @@ module Parser
|
|
1155
1451
|
end
|
1156
1452
|
end
|
1157
1453
|
|
1454
|
+
#
|
1455
|
+
# PATTERN MATCHING
|
1456
|
+
#
|
1457
|
+
|
1458
|
+
def case_match(case_t, expr, in_bodies, else_t, else_body, end_t)
|
1459
|
+
else_body = n(:empty_else, nil, token_map(else_t)) if else_t && !else_body
|
1460
|
+
n(:case_match, [ expr, *(in_bodies << else_body)],
|
1461
|
+
condition_map(case_t, expr, nil, nil, else_t, else_body, end_t))
|
1462
|
+
end
|
1463
|
+
|
1464
|
+
def in_match(lhs, in_t, rhs)
|
1465
|
+
n(:in_match, [lhs, rhs],
|
1466
|
+
binary_op_map(lhs, in_t, rhs))
|
1467
|
+
end
|
1468
|
+
|
1469
|
+
def match_pattern(lhs, match_t, rhs)
|
1470
|
+
n(:match_pattern, [lhs, rhs],
|
1471
|
+
binary_op_map(lhs, match_t, rhs))
|
1472
|
+
end
|
1473
|
+
|
1474
|
+
def match_pattern_p(lhs, match_t, rhs)
|
1475
|
+
n(:match_pattern_p, [lhs, rhs],
|
1476
|
+
binary_op_map(lhs, match_t, rhs))
|
1477
|
+
end
|
1478
|
+
|
1479
|
+
def in_pattern(in_t, pattern, guard, then_t, body)
|
1480
|
+
children = [pattern, guard, body]
|
1481
|
+
n(:in_pattern, children,
|
1482
|
+
keyword_map(in_t, then_t, children.compact, nil))
|
1483
|
+
end
|
1484
|
+
|
1485
|
+
def if_guard(if_t, if_body)
|
1486
|
+
n(:if_guard, [if_body], guard_map(if_t, if_body))
|
1487
|
+
end
|
1488
|
+
|
1489
|
+
def unless_guard(unless_t, unless_body)
|
1490
|
+
n(:unless_guard, [unless_body], guard_map(unless_t, unless_body))
|
1491
|
+
end
|
1492
|
+
|
1493
|
+
def match_var(name_t)
|
1494
|
+
name = value(name_t).to_sym
|
1495
|
+
name_l = loc(name_t)
|
1496
|
+
|
1497
|
+
check_lvar_name(name, name_l)
|
1498
|
+
check_duplicate_pattern_variable(name, name_l)
|
1499
|
+
@parser.static_env.declare(name)
|
1500
|
+
|
1501
|
+
n(:match_var, [ name ],
|
1502
|
+
variable_map(name_t))
|
1503
|
+
end
|
1504
|
+
|
1505
|
+
def match_hash_var(name_t)
|
1506
|
+
name = value(name_t).to_sym
|
1507
|
+
|
1508
|
+
expr_l = loc(name_t)
|
1509
|
+
name_l = expr_l.adjust(end_pos: -1)
|
1510
|
+
|
1511
|
+
check_lvar_name(name, name_l)
|
1512
|
+
check_duplicate_pattern_variable(name, name_l)
|
1513
|
+
@parser.static_env.declare(name)
|
1514
|
+
|
1515
|
+
n(:match_var, [ name ],
|
1516
|
+
Source::Map::Variable.new(name_l, expr_l))
|
1517
|
+
end
|
1518
|
+
|
1519
|
+
def match_hash_var_from_str(begin_t, strings, end_t)
|
1520
|
+
if strings.length > 1
|
1521
|
+
diagnostic :error, :pm_interp_in_var_name, nil, loc(begin_t).join(loc(end_t))
|
1522
|
+
end
|
1523
|
+
|
1524
|
+
string = strings[0]
|
1525
|
+
|
1526
|
+
case string.type
|
1527
|
+
when :str
|
1528
|
+
# MRI supports plain strings in hash pattern matching
|
1529
|
+
name, = *string
|
1530
|
+
name_l = string.loc.expression
|
1531
|
+
|
1532
|
+
check_lvar_name(name, name_l)
|
1533
|
+
check_duplicate_pattern_variable(name, name_l)
|
1534
|
+
|
1535
|
+
@parser.static_env.declare(name)
|
1536
|
+
|
1537
|
+
if (begin_l = string.loc.begin)
|
1538
|
+
# exclude beginning of the string from the location of the variable
|
1539
|
+
name_l = name_l.adjust(begin_pos: begin_l.length)
|
1540
|
+
end
|
1541
|
+
|
1542
|
+
if (end_l = string.loc.end)
|
1543
|
+
# exclude end of the string from the location of the variable
|
1544
|
+
name_l = name_l.adjust(end_pos: -end_l.length)
|
1545
|
+
end
|
1546
|
+
|
1547
|
+
expr_l = loc(begin_t).join(string.loc.expression).join(loc(end_t))
|
1548
|
+
n(:match_var, [ name.to_sym ],
|
1549
|
+
Source::Map::Variable.new(name_l, expr_l))
|
1550
|
+
when :begin
|
1551
|
+
match_hash_var_from_str(begin_t, string.children, end_t)
|
1552
|
+
else
|
1553
|
+
# we only can get here if there is an interpolation, e.g., ``in "#{ a }":`
|
1554
|
+
diagnostic :error, :pm_interp_in_var_name, nil, loc(begin_t).join(loc(end_t))
|
1555
|
+
end
|
1556
|
+
end
|
1557
|
+
|
1558
|
+
def match_rest(star_t, name_t = nil)
|
1559
|
+
if name_t.nil?
|
1560
|
+
n0(:match_rest,
|
1561
|
+
unary_op_map(star_t))
|
1562
|
+
else
|
1563
|
+
name = match_var(name_t)
|
1564
|
+
n(:match_rest, [ name ],
|
1565
|
+
unary_op_map(star_t, name))
|
1566
|
+
end
|
1567
|
+
end
|
1568
|
+
|
1569
|
+
def hash_pattern(lbrace_t, kwargs, rbrace_t)
|
1570
|
+
args = check_duplicate_args(kwargs)
|
1571
|
+
n(:hash_pattern, args,
|
1572
|
+
collection_map(lbrace_t, args, rbrace_t))
|
1573
|
+
end
|
1574
|
+
|
1575
|
+
def array_pattern(lbrack_t, elements, rbrack_t)
|
1576
|
+
return n(:array_pattern, nil, collection_map(lbrack_t, [], rbrack_t)) if elements.nil?
|
1577
|
+
|
1578
|
+
trailing_comma = false
|
1579
|
+
|
1580
|
+
node_elements = elements.map do |element|
|
1581
|
+
if element.type == :match_with_trailing_comma
|
1582
|
+
trailing_comma = true
|
1583
|
+
element.children.first
|
1584
|
+
else
|
1585
|
+
trailing_comma = false
|
1586
|
+
element
|
1587
|
+
end
|
1588
|
+
end
|
1589
|
+
|
1590
|
+
node_type = trailing_comma ? :array_pattern_with_tail : :array_pattern
|
1591
|
+
|
1592
|
+
n(node_type, node_elements,
|
1593
|
+
collection_map(lbrack_t, elements, rbrack_t))
|
1594
|
+
end
|
1595
|
+
|
1596
|
+
def find_pattern(lbrack_t, elements, rbrack_t)
|
1597
|
+
n(:find_pattern, elements,
|
1598
|
+
collection_map(lbrack_t, elements, rbrack_t))
|
1599
|
+
end
|
1600
|
+
|
1601
|
+
def match_with_trailing_comma(match, comma_t)
|
1602
|
+
n(:match_with_trailing_comma, [ match ], expr_map(match.loc.expression.join(loc(comma_t))))
|
1603
|
+
end
|
1604
|
+
|
1605
|
+
def const_pattern(const, ldelim_t, pattern, rdelim_t)
|
1606
|
+
n(:const_pattern, [const, pattern],
|
1607
|
+
Source::Map::Collection.new(
|
1608
|
+
loc(ldelim_t), loc(rdelim_t),
|
1609
|
+
const.loc.expression.join(loc(rdelim_t))
|
1610
|
+
)
|
1611
|
+
)
|
1612
|
+
end
|
1613
|
+
|
1614
|
+
def pin(pin_t, var)
|
1615
|
+
n(:pin, [ var ],
|
1616
|
+
send_unary_op_map(pin_t, var))
|
1617
|
+
end
|
1618
|
+
|
1619
|
+
def match_alt(left, pipe_t, right)
|
1620
|
+
source_map = binary_op_map(left, pipe_t, right)
|
1621
|
+
|
1622
|
+
n(:match_alt, [ left, right ],
|
1623
|
+
source_map)
|
1624
|
+
end
|
1625
|
+
|
1626
|
+
def match_as(value, assoc_t, as)
|
1627
|
+
source_map = binary_op_map(value, assoc_t, as)
|
1628
|
+
|
1629
|
+
n(:match_as, [ value, as ],
|
1630
|
+
source_map)
|
1631
|
+
end
|
1632
|
+
|
1633
|
+
def match_nil_pattern(dstar_t, nil_t)
|
1634
|
+
n0(:match_nil_pattern,
|
1635
|
+
arg_prefix_map(dstar_t, nil_t))
|
1636
|
+
end
|
1637
|
+
|
1638
|
+
def match_pair(label_type, label, value)
|
1639
|
+
if label_type == :label
|
1640
|
+
check_duplicate_pattern_key(label[0], label[1])
|
1641
|
+
pair_keyword(label, value)
|
1642
|
+
else
|
1643
|
+
begin_t, parts, end_t = label
|
1644
|
+
label_loc = loc(begin_t).join(loc(end_t))
|
1645
|
+
|
1646
|
+
# quoted label like "label": value
|
1647
|
+
if (var_name = static_string(parts))
|
1648
|
+
check_duplicate_pattern_key(var_name, label_loc)
|
1649
|
+
else
|
1650
|
+
diagnostic :error, :pm_interp_in_var_name, nil, label_loc
|
1651
|
+
end
|
1652
|
+
|
1653
|
+
pair_quoted(begin_t, parts, end_t, value)
|
1654
|
+
end
|
1655
|
+
end
|
1656
|
+
|
1657
|
+
def match_label(label_type, label)
|
1658
|
+
if label_type == :label
|
1659
|
+
match_hash_var(label)
|
1660
|
+
else
|
1661
|
+
# quoted label like "label": value
|
1662
|
+
begin_t, strings, end_t = label
|
1663
|
+
match_hash_var_from_str(begin_t, strings, end_t)
|
1664
|
+
end
|
1665
|
+
end
|
1666
|
+
|
1158
1667
|
private
|
1159
1668
|
|
1160
1669
|
#
|
@@ -1210,18 +1719,18 @@ module Parser
|
|
1210
1719
|
case this_arg.type
|
1211
1720
|
when :arg, :optarg, :restarg, :blockarg,
|
1212
1721
|
:kwarg, :kwoptarg, :kwrestarg,
|
1213
|
-
:shadowarg
|
1722
|
+
:shadowarg
|
1214
1723
|
|
1215
|
-
|
1724
|
+
check_duplicate_arg(this_arg, map)
|
1216
1725
|
|
1217
|
-
|
1218
|
-
that_name, = *that_arg
|
1726
|
+
when :procarg0
|
1219
1727
|
|
1220
|
-
if
|
1221
|
-
|
1222
|
-
|
1223
|
-
|
1224
|
-
|
1728
|
+
if this_arg.children[0].is_a?(Symbol)
|
1729
|
+
# s(:procarg0, :a)
|
1730
|
+
check_duplicate_arg(this_arg, map)
|
1731
|
+
else
|
1732
|
+
# s(:procarg0, s(:arg, :a), ...)
|
1733
|
+
check_duplicate_args(this_arg.children, map)
|
1225
1734
|
end
|
1226
1735
|
|
1227
1736
|
when :mlhs
|
@@ -1230,6 +1739,60 @@ module Parser
|
|
1230
1739
|
end
|
1231
1740
|
end
|
1232
1741
|
|
1742
|
+
def check_duplicate_arg(this_arg, map={})
|
1743
|
+
this_name, = *this_arg
|
1744
|
+
|
1745
|
+
that_arg = map[this_name]
|
1746
|
+
that_name, = *that_arg
|
1747
|
+
|
1748
|
+
if that_arg.nil?
|
1749
|
+
map[this_name] = this_arg
|
1750
|
+
elsif arg_name_collides?(this_name, that_name)
|
1751
|
+
diagnostic :error, :duplicate_argument, nil,
|
1752
|
+
this_arg.loc.name, [ that_arg.loc.name ]
|
1753
|
+
end
|
1754
|
+
end
|
1755
|
+
|
1756
|
+
def validate_no_forward_arg_after_restarg(args)
|
1757
|
+
restarg = nil
|
1758
|
+
forward_arg = nil
|
1759
|
+
args.each do |arg|
|
1760
|
+
case arg.type
|
1761
|
+
when :restarg then restarg = arg
|
1762
|
+
when :forward_arg then forward_arg = arg
|
1763
|
+
end
|
1764
|
+
end
|
1765
|
+
|
1766
|
+
if !forward_arg.nil? && !restarg.nil?
|
1767
|
+
diagnostic :error, :forward_arg_after_restarg, nil, forward_arg.loc.expression, [restarg.loc.expression]
|
1768
|
+
end
|
1769
|
+
end
|
1770
|
+
|
1771
|
+
def check_assignment_to_numparam(name, loc)
|
1772
|
+
# MRI < 2.7 treats numbered parameters as regular variables
|
1773
|
+
# and so it's allowed to perform assignments like `_1 = 42`.
|
1774
|
+
return if @parser.version < 27
|
1775
|
+
|
1776
|
+
assigning_to_numparam =
|
1777
|
+
@parser.context.in_dynamic_block? &&
|
1778
|
+
name =~ /\A_([1-9])\z/ &&
|
1779
|
+
@parser.max_numparam_stack.has_numparams?
|
1780
|
+
|
1781
|
+
if assigning_to_numparam
|
1782
|
+
diagnostic :error, :cant_assign_to_numparam, { :name => name }, loc
|
1783
|
+
end
|
1784
|
+
end
|
1785
|
+
|
1786
|
+
def check_reserved_for_numparam(name, loc)
|
1787
|
+
# MRI < 3.0 accepts assignemnt to variables like _1
|
1788
|
+
# if it's not a numbered parameter. MRI 3.0 and newer throws an error.
|
1789
|
+
return if @parser.version < 30
|
1790
|
+
|
1791
|
+
if name =~ /\A_([1-9])\z/
|
1792
|
+
diagnostic :error, :reserved_for_numparam, { :name => name }, loc
|
1793
|
+
end
|
1794
|
+
end
|
1795
|
+
|
1233
1796
|
def arg_name_collides?(this_name, that_name)
|
1234
1797
|
case @parser.version
|
1235
1798
|
when 18
|
@@ -1245,6 +1808,32 @@ module Parser
|
|
1245
1808
|
end
|
1246
1809
|
end
|
1247
1810
|
|
1811
|
+
def check_lvar_name(name, loc)
|
1812
|
+
if name =~ /\A[[[:lower:]]_][[[:alnum:]]_]*\z/
|
1813
|
+
# OK
|
1814
|
+
else
|
1815
|
+
diagnostic :error, :lvar_name, { name: name }, loc
|
1816
|
+
end
|
1817
|
+
end
|
1818
|
+
|
1819
|
+
def check_duplicate_pattern_variable(name, loc)
|
1820
|
+
return if name.to_s.start_with?('_')
|
1821
|
+
|
1822
|
+
if @parser.pattern_variables.declared?(name)
|
1823
|
+
diagnostic :error, :duplicate_variable_name, { name: name.to_s }, loc
|
1824
|
+
end
|
1825
|
+
|
1826
|
+
@parser.pattern_variables.declare(name)
|
1827
|
+
end
|
1828
|
+
|
1829
|
+
def check_duplicate_pattern_key(name, loc)
|
1830
|
+
if @parser.pattern_hash_keys.declared?(name)
|
1831
|
+
diagnostic :error, :duplicate_pattern_key, { name: name.to_s }, loc
|
1832
|
+
end
|
1833
|
+
|
1834
|
+
@parser.pattern_hash_keys.declare(name)
|
1835
|
+
end
|
1836
|
+
|
1248
1837
|
#
|
1249
1838
|
# SOURCE MAPS
|
1250
1839
|
#
|
@@ -1389,10 +1978,12 @@ module Parser
|
|
1389
1978
|
end
|
1390
1979
|
|
1391
1980
|
def range_map(start_e, op_t, end_e)
|
1392
|
-
if end_e
|
1981
|
+
if start_e && end_e
|
1393
1982
|
expr_l = join_exprs(start_e, end_e)
|
1394
|
-
|
1983
|
+
elsif start_e
|
1395
1984
|
expr_l = start_e.loc.expression.join(loc(op_t))
|
1985
|
+
elsif end_e
|
1986
|
+
expr_l = loc(op_t).join(end_e.loc.expression)
|
1396
1987
|
end
|
1397
1988
|
|
1398
1989
|
Source::Map::Operator.new(loc(op_t), expr_l)
|
@@ -1432,9 +2023,17 @@ module Parser
|
|
1432
2023
|
end
|
1433
2024
|
|
1434
2025
|
def definition_map(keyword_t, operator_t, name_t, end_t)
|
1435
|
-
Source::Map::
|
1436
|
-
|
1437
|
-
|
2026
|
+
Source::Map::MethodDefinition.new(loc(keyword_t),
|
2027
|
+
loc(operator_t), loc(name_t),
|
2028
|
+
loc(end_t), nil, nil)
|
2029
|
+
end
|
2030
|
+
|
2031
|
+
def endless_definition_map(keyword_t, operator_t, name_t, assignment_t, body_e)
|
2032
|
+
body_l = body_e.loc.expression
|
2033
|
+
|
2034
|
+
Source::Map::MethodDefinition.new(loc(keyword_t),
|
2035
|
+
loc(operator_t), loc(name_t), nil,
|
2036
|
+
loc(assignment_t), body_l)
|
1438
2037
|
end
|
1439
2038
|
|
1440
2039
|
def send_map(receiver_e, dot_t, selector_t, begin_t=nil, args=[], end_t=nil)
|
@@ -1591,6 +2190,13 @@ module Parser
|
|
1591
2190
|
begin_l.join(end_l))
|
1592
2191
|
end
|
1593
2192
|
|
2193
|
+
def guard_map(keyword_t, guard_body_e)
|
2194
|
+
keyword_l = loc(keyword_t)
|
2195
|
+
guard_body_l = guard_body_e.loc.expression
|
2196
|
+
|
2197
|
+
Source::Map::Keyword.new(keyword_l, nil, nil, keyword_l.join(guard_body_l))
|
2198
|
+
end
|
2199
|
+
|
1594
2200
|
#
|
1595
2201
|
# HELPERS
|
1596
2202
|
#
|
@@ -1672,6 +2278,32 @@ module Parser
|
|
1672
2278
|
@parser.send :yyerror
|
1673
2279
|
end
|
1674
2280
|
end
|
2281
|
+
|
2282
|
+
def validate_definee(definee)
|
2283
|
+
case definee.type
|
2284
|
+
when :int, :str, :dstr, :sym, :dsym,
|
2285
|
+
:regexp, :array, :hash
|
2286
|
+
|
2287
|
+
diagnostic :error, :singleton_literal, nil, definee.loc.expression
|
2288
|
+
false
|
2289
|
+
else
|
2290
|
+
true
|
2291
|
+
end
|
2292
|
+
end
|
2293
|
+
|
2294
|
+
def rewrite_hash_args_to_kwargs(args)
|
2295
|
+
if args.any? && kwargs?(args.last)
|
2296
|
+
# foo(..., bar: baz)
|
2297
|
+
args[args.length - 1] = args[args.length - 1].updated(:kwargs)
|
2298
|
+
elsif args.length > 1 && args.last.type == :block_pass && kwargs?(args[args.length - 2])
|
2299
|
+
# foo(..., bar: baz, &blk)
|
2300
|
+
args[args.length - 2] = args[args.length - 2].updated(:kwargs)
|
2301
|
+
end
|
2302
|
+
end
|
2303
|
+
|
2304
|
+
def kwargs?(node)
|
2305
|
+
node.type == :hash && node.loc.begin.nil? && node.loc.end.nil?
|
2306
|
+
end
|
1675
2307
|
end
|
1676
2308
|
|
1677
2309
|
end
|