ruby-next-core 0.14.0 → 1.0.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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +70 -0
- data/README.md +163 -56
- data/bin/mspec +11 -0
- data/lib/.rbnext/2.1/ruby-next/commands/nextify.rb +295 -0
- data/lib/.rbnext/2.1/ruby-next/core.rb +12 -4
- data/lib/.rbnext/2.1/ruby-next/language.rb +62 -12
- data/lib/.rbnext/2.3/ruby-next/commands/nextify.rb +97 -3
- data/lib/.rbnext/2.3/ruby-next/config.rb +79 -0
- data/lib/.rbnext/2.3/ruby-next/core/data.rb +163 -0
- data/lib/.rbnext/2.3/ruby-next/language/eval.rb +4 -4
- data/lib/.rbnext/2.3/ruby-next/language/rewriters/2.7/args_forward.rb +134 -0
- data/lib/.rbnext/2.3/ruby-next/language/rewriters/2.7/pattern_matching.rb +122 -47
- data/lib/.rbnext/2.3/ruby-next/language/rewriters/base.rb +6 -32
- data/lib/.rbnext/2.3/ruby-next/utils.rb +3 -22
- data/lib/.rbnext/2.6/ruby-next/core/data.rb +163 -0
- data/lib/.rbnext/2.7/ruby-next/core/data.rb +163 -0
- data/lib/.rbnext/2.7/ruby-next/core.rb +12 -4
- data/lib/.rbnext/2.7/ruby-next/language/paco_parsers/string_literals.rb +109 -0
- data/lib/.rbnext/2.7/ruby-next/language/rewriters/2.7/pattern_matching.rb +1095 -0
- data/lib/.rbnext/2.7/ruby-next/language/rewriters/text.rb +132 -0
- data/lib/.rbnext/3.2/ruby-next/commands/base.rb +55 -0
- data/lib/.rbnext/3.2/ruby-next/language/rewriters/2.7/pattern_matching.rb +1095 -0
- data/lib/.rbnext/3.2/ruby-next/rubocop.rb +210 -0
- data/lib/ruby-next/cli.rb +10 -15
- data/lib/ruby-next/commands/nextify.rb +99 -3
- data/lib/ruby-next/config.rb +31 -4
- data/lib/ruby-next/core/data.rb +163 -0
- data/lib/ruby-next/core/matchdata/deconstruct.rb +9 -0
- data/lib/ruby-next/core/matchdata/deconstruct_keys.rb +20 -0
- data/lib/ruby-next/core/matchdata/named_captures.rb +11 -0
- data/lib/ruby-next/core/proc/compose.rb +0 -1
- data/lib/ruby-next/core/refinement/import.rb +44 -36
- data/lib/ruby-next/core/time/deconstruct_keys.rb +30 -0
- data/lib/ruby-next/core.rb +11 -3
- data/lib/ruby-next/irb.rb +24 -0
- data/lib/ruby-next/language/bootsnap.rb +2 -25
- data/lib/ruby-next/language/eval.rb +4 -4
- data/lib/ruby-next/language/paco_parser.rb +7 -0
- data/lib/ruby-next/language/paco_parsers/base.rb +47 -0
- data/lib/ruby-next/language/paco_parsers/comments.rb +26 -0
- data/lib/ruby-next/language/paco_parsers/string_literals.rb +109 -0
- data/lib/ruby-next/language/parser.rb +31 -6
- data/lib/ruby-next/language/rewriters/2.5/rescue_within_block.rb +41 -0
- data/lib/ruby-next/language/rewriters/2.7/args_forward.rb +57 -0
- data/lib/ruby-next/language/rewriters/2.7/pattern_matching.rb +120 -45
- data/lib/ruby-next/language/rewriters/3.0/args_forward_leading.rb +2 -2
- data/lib/ruby-next/language/rewriters/3.1/oneline_pattern_parensless.rb +1 -1
- data/lib/ruby-next/language/rewriters/3.1/shorthand_hash.rb +2 -1
- data/lib/ruby-next/language/rewriters/3.2/anonymous_restargs.rb +104 -0
- data/lib/ruby-next/language/rewriters/abstract.rb +57 -0
- data/lib/ruby-next/language/rewriters/base.rb +6 -32
- data/lib/ruby-next/language/rewriters/edge/it_param.rb +58 -0
- data/lib/ruby-next/language/rewriters/edge.rb +12 -0
- data/lib/ruby-next/language/rewriters/proposed/bind_vars_pattern.rb +3 -0
- data/lib/ruby-next/language/rewriters/proposed/method_reference.rb +9 -20
- data/lib/ruby-next/language/rewriters/text.rb +132 -0
- data/lib/ruby-next/language/runtime.rb +9 -86
- data/lib/ruby-next/language/setup.rb +5 -2
- data/lib/ruby-next/language/unparser.rb +5 -0
- data/lib/ruby-next/language.rb +62 -12
- data/lib/ruby-next/pry.rb +90 -0
- data/lib/ruby-next/rubocop.rb +2 -0
- data/lib/ruby-next/utils.rb +3 -22
- data/lib/ruby-next/version.rb +1 -1
- data/lib/uby-next/irb.rb +3 -0
- data/lib/uby-next/pry.rb +3 -0
- data/lib/uby-next.rb +2 -2
- metadata +70 -10
@@ -182,7 +182,6 @@ module RubyNext
|
|
182
182
|
end
|
183
183
|
end
|
184
184
|
|
185
|
-
# rubocop:disable Style/MethodMissingSuper
|
186
185
|
# rubocop:disable Style/MissingRespondToMissing
|
187
186
|
class Noop < Base
|
188
187
|
# Return node itself, no memoization
|
@@ -243,6 +242,7 @@ module RubyNext
|
|
243
242
|
|
244
243
|
@deconstructed_keys = {}
|
245
244
|
@predicates = Predicates::CaseIn.new
|
245
|
+
@lvars = []
|
246
246
|
|
247
247
|
matchee_ast =
|
248
248
|
s(:begin, s(:lvasgn, MATCHEE, node.children[0]))
|
@@ -272,6 +272,7 @@ module RubyNext
|
|
272
272
|
|
273
273
|
@deconstructed_keys = {}
|
274
274
|
@predicates = Predicates::Noop.new
|
275
|
+
@lvars = []
|
275
276
|
|
276
277
|
matchee =
|
277
278
|
s(:begin, s(:lvasgn, MATCHEE, node.children[0]))
|
@@ -282,10 +283,12 @@ module RubyNext
|
|
282
283
|
arr: MATCHEE_ARR,
|
283
284
|
hash: MATCHEE_HASH
|
284
285
|
) do
|
285
|
-
|
286
|
-
|
287
|
-
|
288
|
-
|
286
|
+
with_declared_locals do
|
287
|
+
send(
|
288
|
+
:"#{node.children[1].type}_clause",
|
289
|
+
node.children[1]
|
290
|
+
)
|
291
|
+
end.then do |node|
|
289
292
|
s(:begin,
|
290
293
|
s(:or,
|
291
294
|
node,
|
@@ -311,6 +314,7 @@ module RubyNext
|
|
311
314
|
|
312
315
|
@deconstructed_keys = {}
|
313
316
|
@predicates = Predicates::Noop.new
|
317
|
+
@lvars = []
|
314
318
|
|
315
319
|
matchee =
|
316
320
|
s(:begin, s(:lvasgn, MATCHEE, node.children[0]))
|
@@ -321,10 +325,12 @@ module RubyNext
|
|
321
325
|
arr: MATCHEE_ARR,
|
322
326
|
hash: MATCHEE_HASH
|
323
327
|
) do
|
324
|
-
|
325
|
-
|
326
|
-
|
327
|
-
|
328
|
+
with_declared_locals do
|
329
|
+
send(
|
330
|
+
:"#{node.children[1].type}_clause",
|
331
|
+
node.children[1]
|
332
|
+
)
|
333
|
+
end
|
328
334
|
end
|
329
335
|
|
330
336
|
node.updated(
|
@@ -395,13 +401,15 @@ module RubyNext
|
|
395
401
|
def build_when_clause(clause)
|
396
402
|
predicates.reset!
|
397
403
|
[
|
398
|
-
|
399
|
-
|
400
|
-
|
401
|
-
|
402
|
-
|
403
|
-
|
404
|
-
|
404
|
+
with_declared_locals do
|
405
|
+
with_guard(
|
406
|
+
send(
|
407
|
+
:"#{clause.children[0].type}_clause",
|
408
|
+
clause.children[0]
|
409
|
+
),
|
410
|
+
clause.children[1] # guard
|
411
|
+
)
|
412
|
+
end,
|
405
413
|
process(clause.children[2] || s(:nil)) # expression
|
406
414
|
].then do |children|
|
407
415
|
s(:when, *children)
|
@@ -417,15 +425,15 @@ module RubyNext
|
|
417
425
|
s(:begin,
|
418
426
|
s(:and,
|
419
427
|
node,
|
420
|
-
send(:"#{pattern.type}_clause", pattern)))
|
428
|
+
send(:"#{pattern.type}_clause", pattern, right)))
|
421
429
|
end
|
422
430
|
end
|
423
431
|
|
424
|
-
def match_alt_clause(node)
|
432
|
+
def match_alt_clause(node, matchee = s(:lvar, locals[:matchee]))
|
425
433
|
children = locals.with(ALTERNATION_MARKER => true) do
|
426
434
|
node.children.map.with_index do |child, i|
|
427
435
|
predicates.terminate! if i == 1
|
428
|
-
send :"#{child.type}_clause", child
|
436
|
+
send :"#{child.type}_clause", child, matchee
|
429
437
|
end
|
430
438
|
end
|
431
439
|
s(:begin, s(:or, *children))
|
@@ -442,7 +450,7 @@ module RubyNext
|
|
442
450
|
var = node.children[0]
|
443
451
|
return s(:true) if var == :_
|
444
452
|
|
445
|
-
check_match_var_alternation!(var)
|
453
|
+
check_match_var_alternation!(var)
|
446
454
|
|
447
455
|
s(:begin,
|
448
456
|
s(:or,
|
@@ -541,11 +549,10 @@ module RubyNext
|
|
541
549
|
def array_find(head, *nodes, tail)
|
542
550
|
index = s(:lvar, :__i__)
|
543
551
|
|
544
|
-
match_vars = []
|
545
|
-
|
546
552
|
head_match =
|
547
553
|
unless head.children.empty?
|
548
|
-
|
554
|
+
# we only need to call this to track the lvar usage
|
555
|
+
build_var_assignment(head.children[0].children[0])
|
549
556
|
|
550
557
|
arr_take = s(:send,
|
551
558
|
s(:lvar, locals[:arr]),
|
@@ -557,16 +564,19 @@ module RubyNext
|
|
557
564
|
|
558
565
|
tail_match =
|
559
566
|
unless tail.children.empty?
|
560
|
-
|
567
|
+
# we only need to call this to track the lvar usage
|
568
|
+
build_var_assignment(tail.children[0].children[0])
|
561
569
|
|
562
570
|
match_var_clause(tail.children[0], arr_slice(index + nodes.size, -1))
|
563
571
|
end
|
564
572
|
|
565
573
|
nodes.each do |node|
|
566
574
|
if node.type == :match_var
|
567
|
-
|
575
|
+
# we only need to call this to track the lvar usage
|
576
|
+
build_var_assignment(node.children[0])
|
568
577
|
elsif node.type == :match_as
|
569
|
-
|
578
|
+
# we only need to call this to track the lvar usage
|
579
|
+
build_var_assignment(node.children[1].children[0])
|
570
580
|
end
|
571
581
|
end
|
572
582
|
|
@@ -594,19 +604,7 @@ module RubyNext
|
|
594
604
|
s(:args,
|
595
605
|
s(:arg, :_),
|
596
606
|
s(:arg, :__i__)),
|
597
|
-
pattern)
|
598
|
-
next block if match_vars.empty?
|
599
|
-
|
600
|
-
# We need to declare match vars outside of `find` block
|
601
|
-
locals_declare = s(:begin, s(:masgn,
|
602
|
-
s(:mlhs, *match_vars),
|
603
|
-
s(:nil)))
|
604
|
-
|
605
|
-
s(:begin,
|
606
|
-
s(:or,
|
607
|
-
locals_declare,
|
608
|
-
block))
|
609
|
-
end
|
607
|
+
pattern)
|
610
608
|
end
|
611
609
|
|
612
610
|
def array_match_rest(index, node, *tail)
|
@@ -649,6 +647,14 @@ module RubyNext
|
|
649
647
|
end
|
650
648
|
end
|
651
649
|
|
650
|
+
def find_pattern_array_element(node, index)
|
651
|
+
element = arr_item_at(index)
|
652
|
+
locals.with(arr: locals[:arr, index]) do
|
653
|
+
predicates.push :"i#{index}"
|
654
|
+
find_pattern_clause(node, element).tap { predicates.pop }
|
655
|
+
end
|
656
|
+
end
|
657
|
+
|
652
658
|
def hash_pattern_array_element(node, index)
|
653
659
|
element = arr_item_at(index)
|
654
660
|
locals.with(hash: locals[:arr, index]) do
|
@@ -657,6 +663,14 @@ module RubyNext
|
|
657
663
|
end
|
658
664
|
end
|
659
665
|
|
666
|
+
def const_pattern_array_element(node, index)
|
667
|
+
element = arr_item_at(index)
|
668
|
+
locals.with(arr: locals[:arr, index]) do
|
669
|
+
predicates.push :"i#{index}"
|
670
|
+
const_pattern_clause(node, element).tap { predicates.pop }
|
671
|
+
end
|
672
|
+
end
|
673
|
+
|
660
674
|
def match_alt_array_element(node, index)
|
661
675
|
children = node.children.map do |child, i|
|
662
676
|
send :"#{child.type}_array_element", child, index
|
@@ -665,11 +679,19 @@ module RubyNext
|
|
665
679
|
end
|
666
680
|
|
667
681
|
def match_var_array_element(node, index)
|
668
|
-
|
682
|
+
element = arr_item_at(index)
|
683
|
+
locals.with(arr: locals[:arr, index]) do
|
684
|
+
predicates.push :"i#{index}"
|
685
|
+
match_var_clause(node, element).tap { predicates.pop }
|
686
|
+
end
|
669
687
|
end
|
670
688
|
|
671
689
|
def match_as_array_element(node, index)
|
672
|
-
|
690
|
+
element = arr_item_at(index)
|
691
|
+
locals.with(arr: locals[:arr, index]) do
|
692
|
+
predicates.push :"i#{index}"
|
693
|
+
match_as_clause(node, element).tap { predicates.pop }
|
694
|
+
end
|
673
695
|
end
|
674
696
|
|
675
697
|
def pin_array_element(node, index)
|
@@ -829,6 +851,24 @@ module RubyNext
|
|
829
851
|
end
|
830
852
|
end
|
831
853
|
|
854
|
+
def find_pattern_hash_element(node, key)
|
855
|
+
element = hash_value_at(key)
|
856
|
+
key_index = deconstructed_key(key)
|
857
|
+
locals.with(arr: locals[:hash, key_index]) do
|
858
|
+
predicates.push :"k#{key_index}"
|
859
|
+
find_pattern_clause(node, element).tap { predicates.pop }
|
860
|
+
end
|
861
|
+
end
|
862
|
+
|
863
|
+
def const_pattern_hash_element(node, key)
|
864
|
+
element = hash_value_at(key)
|
865
|
+
key_index = deconstructed_key(key)
|
866
|
+
locals.with(hash: locals[:hash, key_index]) do
|
867
|
+
predicates.push :"k#{key_index}"
|
868
|
+
const_pattern_clause(node, element).tap { predicates.pop }
|
869
|
+
end
|
870
|
+
end
|
871
|
+
|
832
872
|
def hash_element(head, *tail)
|
833
873
|
send("#{head.type}_hash_element", head).then do |node|
|
834
874
|
next node if tail.empty?
|
@@ -869,12 +909,22 @@ module RubyNext
|
|
869
909
|
end
|
870
910
|
|
871
911
|
def match_as_hash_element(node, key)
|
872
|
-
|
912
|
+
element = hash_value_at(key)
|
913
|
+
key_index = deconstructed_key(key)
|
914
|
+
locals.with(hash: locals[:hash, key_index]) do
|
915
|
+
predicates.push :"k#{key_index}"
|
916
|
+
match_as_clause(node, element).tap { predicates.pop }
|
917
|
+
end
|
873
918
|
end
|
874
919
|
|
875
920
|
def match_var_hash_element(node, key = nil)
|
876
921
|
key ||= node.children[0]
|
877
|
-
|
922
|
+
element = hash_value_at(key)
|
923
|
+
key_index = deconstructed_key(key)
|
924
|
+
locals.with(hash: locals[:hash, key_index]) do
|
925
|
+
predicates.push :"k#{key_index}"
|
926
|
+
match_var_clause(node, element).tap { predicates.pop }
|
927
|
+
end
|
878
928
|
end
|
879
929
|
|
880
930
|
def match_nil_pattern_hash_element(node, _key = nil)
|
@@ -948,6 +998,24 @@ module RubyNext
|
|
948
998
|
end
|
949
999
|
end
|
950
1000
|
|
1001
|
+
def with_declared_locals
|
1002
|
+
lvars.clear
|
1003
|
+
node = yield
|
1004
|
+
|
1005
|
+
return node if lvars.empty?
|
1006
|
+
|
1007
|
+
# We need to declare match lvars outside of the outer `find` block,
|
1008
|
+
# so we do that for that whole pattern
|
1009
|
+
locals_declare = s(:begin, s(:masgn,
|
1010
|
+
s(:mlhs, *lvars.uniq.map { s(:lvasgn, _1) }),
|
1011
|
+
s(:nil)))
|
1012
|
+
|
1013
|
+
s(:begin,
|
1014
|
+
s(:or,
|
1015
|
+
locals_declare,
|
1016
|
+
node))
|
1017
|
+
end
|
1018
|
+
|
951
1019
|
def no_matching_pattern
|
952
1020
|
raise_error(
|
953
1021
|
:NoMatchingPatternError,
|
@@ -982,13 +1050,17 @@ module RubyNext
|
|
982
1050
|
|
983
1051
|
private
|
984
1052
|
|
985
|
-
attr_reader :deconstructed_keys, :predicates
|
1053
|
+
attr_reader :deconstructed_keys, :predicates, :lvars
|
986
1054
|
|
987
1055
|
# Raise SyntaxError if match-var is used within alternation
|
988
1056
|
# https://github.com/ruby/ruby/blob/672213ef1ca2b71312084057e27580b340438796/compile.c#L5900
|
989
1057
|
def check_match_var_alternation!(name)
|
990
1058
|
return unless locals.key?(ALTERNATION_MARKER)
|
991
1059
|
|
1060
|
+
if name.is_a?(::Parser::AST::Node)
|
1061
|
+
raise ::SyntaxError, "illegal variable in alternative pattern (#{name.children.first})"
|
1062
|
+
end
|
1063
|
+
|
992
1064
|
return if name.start_with?("_")
|
993
1065
|
|
994
1066
|
raise ::SyntaxError, "illegal variable in alternative pattern (#{name})"
|
@@ -1008,7 +1080,10 @@ module RubyNext
|
|
1008
1080
|
|
1009
1081
|
# Value could be omitted for mass assignment
|
1010
1082
|
def build_var_assignment(var, value = nil)
|
1011
|
-
|
1083
|
+
unless var.is_a?(::Parser::AST::Node)
|
1084
|
+
lvars << var
|
1085
|
+
return s(:lvasgn, *[var, value].compact)
|
1086
|
+
end
|
1012
1087
|
|
1013
1088
|
asign_type = :"#{var.type.to_s[0]}vasgn"
|
1014
1089
|
|
@@ -50,7 +50,7 @@ module RubyNext
|
|
50
50
|
|
51
51
|
return false unless fargs
|
52
52
|
|
53
|
-
node.children.index(fargs) > (node.type == :send ? 2 : 0)
|
53
|
+
node.children.index(fargs) > ((node.type == :send) ? 2 : 0)
|
54
54
|
end
|
55
55
|
|
56
56
|
def method_with_leading_arg(node)
|
@@ -62,7 +62,7 @@ module RubyNext
|
|
62
62
|
end
|
63
63
|
|
64
64
|
def def_with_leading_farg(node)
|
65
|
-
args = node.type == :defs ? node.children[2] : node.children[1]
|
65
|
+
args = (node.type == :defs) ? node.children[2] : node.children[1]
|
66
66
|
args = args.children
|
67
67
|
|
68
68
|
farg = args.detect { |child| child.type == :forward_arg }
|
@@ -25,7 +25,7 @@ module RubyNext
|
|
25
25
|
|
26
26
|
context.track! self
|
27
27
|
|
28
|
-
left_p, right_p = pattern.type == :array_pattern ? %w([ ]) : %w[{ }]
|
28
|
+
left_p, right_p = (pattern.type == :array_pattern) ? %w([ ]) : %w[{ }]
|
29
29
|
|
30
30
|
insert_before(pattern.loc.expression, left_p)
|
31
31
|
insert_after(pattern.loc.expression, right_p)
|
@@ -9,7 +9,8 @@ module RubyNext
|
|
9
9
|
MIN_SUPPORTED_VERSION = Gem::Version.new("3.1.0")
|
10
10
|
|
11
11
|
def on_pair(node)
|
12
|
-
return super(node) unless node.children[0].loc.last_column == node.children[1].loc.last_column
|
12
|
+
return super(node) unless (node.children[0].loc.last_column == node.children[1].loc.last_column) &&
|
13
|
+
(node.children[1].loc.first_line == node.children[1].loc.last_line)
|
13
14
|
|
14
15
|
context.track! self
|
15
16
|
|
@@ -0,0 +1,104 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RubyNext
|
4
|
+
module Language
|
5
|
+
module Rewriters
|
6
|
+
class AnonymousRestArgs < Base
|
7
|
+
NAME = "anonymous-rest-args"
|
8
|
+
SYNTAX_PROBE = "obj = Object.new; def obj.foo(*) bar(*); end"
|
9
|
+
MIN_SUPPORTED_VERSION = Gem::Version.new("3.2.0")
|
10
|
+
|
11
|
+
REST = :__rest__
|
12
|
+
KWREST = :__kwrest__
|
13
|
+
|
14
|
+
def on_args(node)
|
15
|
+
rest = node.children.find { |child| child.is_a?(::Parser::AST::Node) && child.type == :restarg && child.children.first.nil? }
|
16
|
+
kwrest = node.children.find { |child| child.is_a?(::Parser::AST::Node) && child.type == :kwrestarg && child.children.first.nil? }
|
17
|
+
|
18
|
+
return super unless rest || kwrest
|
19
|
+
|
20
|
+
context.track! self
|
21
|
+
|
22
|
+
replace(rest.loc.expression, "*#{REST}") if rest
|
23
|
+
replace(kwrest.loc.expression, "**#{KWREST}") if kwrest
|
24
|
+
|
25
|
+
new_args = node.children.map do |child|
|
26
|
+
if child == rest
|
27
|
+
s(:restarg, REST)
|
28
|
+
elsif child == kwrest
|
29
|
+
s(:kwrestarg, KWREST)
|
30
|
+
else
|
31
|
+
child
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
node.updated(:args, new_args)
|
36
|
+
end
|
37
|
+
|
38
|
+
def on_send(node)
|
39
|
+
return super unless forwarded_args?(node)
|
40
|
+
|
41
|
+
process_send_args(node)
|
42
|
+
end
|
43
|
+
|
44
|
+
def on_super(node)
|
45
|
+
return super unless forwarded_args?(node)
|
46
|
+
|
47
|
+
process_send_args(node)
|
48
|
+
end
|
49
|
+
|
50
|
+
private
|
51
|
+
|
52
|
+
def forwarded_args?(node)
|
53
|
+
node.children.each do |child|
|
54
|
+
next unless child.is_a?(::Parser::AST::Node)
|
55
|
+
|
56
|
+
if child.type == :forwarded_restarg
|
57
|
+
return true
|
58
|
+
elsif child.type == :kwargs
|
59
|
+
child.children.each do |kwarg|
|
60
|
+
next unless kwarg.is_a?(::Parser::AST::Node)
|
61
|
+
|
62
|
+
return true if kwarg.type == :forwarded_kwrestarg
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
false
|
68
|
+
end
|
69
|
+
|
70
|
+
def process_send_args(node)
|
71
|
+
process(
|
72
|
+
node.updated(
|
73
|
+
nil,
|
74
|
+
node.children.map do |child|
|
75
|
+
next child unless child.is_a?(::Parser::AST::Node)
|
76
|
+
|
77
|
+
if child.type == :forwarded_restarg
|
78
|
+
replace(child.loc.expression, "*#{REST}")
|
79
|
+
s(:ksplat, s(:lvar, REST))
|
80
|
+
elsif child.type == :kwargs
|
81
|
+
child.updated(
|
82
|
+
nil,
|
83
|
+
child.children.map do |kwarg|
|
84
|
+
next kwarg unless kwarg.is_a?(::Parser::AST::Node)
|
85
|
+
|
86
|
+
if kwarg.type == :forwarded_kwrestarg
|
87
|
+
replace(kwarg.loc.expression, "**#{KWREST}")
|
88
|
+
s(:kwsplat, s(:lvar, KWREST))
|
89
|
+
else
|
90
|
+
kwarg
|
91
|
+
end
|
92
|
+
end
|
93
|
+
)
|
94
|
+
else
|
95
|
+
child
|
96
|
+
end
|
97
|
+
end
|
98
|
+
)
|
99
|
+
)
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RubyNext
|
4
|
+
module Language
|
5
|
+
module Rewriters
|
6
|
+
class Abstract < ::Parser::TreeRewriter
|
7
|
+
NAME = "custom-rewriter"
|
8
|
+
SYNTAX_PROBE = "1 = [}"
|
9
|
+
MIN_SUPPORTED_VERSION = Gem::Version.new(RubyNext::NEXT_VERSION)
|
10
|
+
|
11
|
+
class << self
|
12
|
+
# Returns true if the syntax is not supported
|
13
|
+
# by the current Ruby (performs syntax check, not version check)
|
14
|
+
def unsupported_syntax?
|
15
|
+
save_verbose, $VERBOSE = $VERBOSE, nil
|
16
|
+
eval_mid = Kernel.respond_to?(:eval_without_ruby_next) ? :eval_without_ruby_next : :eval
|
17
|
+
Kernel.send eval_mid, self::SYNTAX_PROBE, nil, __FILE__, __LINE__
|
18
|
+
false
|
19
|
+
rescue SyntaxError, StandardError
|
20
|
+
true
|
21
|
+
ensure
|
22
|
+
$VERBOSE = save_verbose
|
23
|
+
end
|
24
|
+
|
25
|
+
# Returns true if the syntax is supported
|
26
|
+
# by the specified version
|
27
|
+
def unsupported_version?(version)
|
28
|
+
version < self::MIN_SUPPORTED_VERSION
|
29
|
+
end
|
30
|
+
|
31
|
+
def text?
|
32
|
+
false
|
33
|
+
end
|
34
|
+
|
35
|
+
def ast?
|
36
|
+
false
|
37
|
+
end
|
38
|
+
|
39
|
+
private
|
40
|
+
|
41
|
+
def transform(source)
|
42
|
+
Language.transform(source, rewriters: [self], using: false)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def initialize(context)
|
47
|
+
@context = context
|
48
|
+
super()
|
49
|
+
end
|
50
|
+
|
51
|
+
private
|
52
|
+
|
53
|
+
attr_reader :context
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
@@ -13,7 +13,7 @@ module RubyNext
|
|
13
13
|
|
14
14
|
MSG
|
15
15
|
|
16
|
-
class Base <
|
16
|
+
class Base < Abstract
|
17
17
|
class LocalsTracker
|
18
18
|
using(Module.new do
|
19
19
|
refine ::Parser::AST::Node do
|
@@ -65,39 +65,15 @@ module RubyNext
|
|
65
65
|
end
|
66
66
|
end
|
67
67
|
|
68
|
-
|
69
|
-
# Returns true if the syntax is supported
|
70
|
-
# by the current Ruby (performs syntax check, not version check)
|
71
|
-
def unsupported_syntax?
|
72
|
-
save_verbose, $VERBOSE = $VERBOSE, nil
|
73
|
-
eval_mid = Kernel.respond_to?(:eval_without_ruby_next) ? :eval_without_ruby_next : :eval
|
74
|
-
Kernel.send eval_mid, self::SYNTAX_PROBE, nil, __FILE__, __LINE__
|
75
|
-
false
|
76
|
-
rescue SyntaxError, StandardError
|
77
|
-
true
|
78
|
-
ensure
|
79
|
-
$VERBOSE = save_verbose
|
80
|
-
end
|
81
|
-
|
82
|
-
# Returns true if the syntax is supported
|
83
|
-
# by the specified version
|
84
|
-
def unsupported_version?(version)
|
85
|
-
self::MIN_SUPPORTED_VERSION > version
|
86
|
-
end
|
87
|
-
|
88
|
-
private
|
68
|
+
attr_reader :locals
|
89
69
|
|
90
|
-
|
91
|
-
|
92
|
-
end
|
70
|
+
def self.ast?
|
71
|
+
true
|
93
72
|
end
|
94
73
|
|
95
|
-
|
96
|
-
|
97
|
-
def initialize(context)
|
98
|
-
@context = context
|
74
|
+
def initialize(*args)
|
99
75
|
@locals = LocalsTracker.new
|
100
|
-
super
|
76
|
+
super
|
101
77
|
end
|
102
78
|
|
103
79
|
def s(type, *children)
|
@@ -145,8 +121,6 @@ module RubyNext
|
|
145
121
|
|
146
122
|
Unparser.unparse(ast).chomp
|
147
123
|
end
|
148
|
-
|
149
|
-
attr_reader :context
|
150
124
|
end
|
151
125
|
end
|
152
126
|
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RubyNext
|
4
|
+
module Language
|
5
|
+
module Rewriters
|
6
|
+
class ItParam < Base
|
7
|
+
using RubyNext
|
8
|
+
|
9
|
+
NAME = "it-param"
|
10
|
+
SYNTAX_PROBE = "proc { it.keys }.call({})"
|
11
|
+
MIN_SUPPORTED_VERSION = Gem::Version.new("3.4.0")
|
12
|
+
|
13
|
+
def on_block(node)
|
14
|
+
proc_or_lambda, args, body = *node.children
|
15
|
+
|
16
|
+
return super unless block_has_it?(body)
|
17
|
+
|
18
|
+
context.track! self
|
19
|
+
|
20
|
+
new_body = s(:begin,
|
21
|
+
s(:lvasgn, :it, s(:lvar, :_1)),
|
22
|
+
body)
|
23
|
+
|
24
|
+
insert_before(body.loc.expression, "it = _1;")
|
25
|
+
|
26
|
+
process(
|
27
|
+
node.updated(:numblock, [
|
28
|
+
proc_or_lambda,
|
29
|
+
args,
|
30
|
+
new_body
|
31
|
+
])
|
32
|
+
)
|
33
|
+
end
|
34
|
+
|
35
|
+
private
|
36
|
+
|
37
|
+
# It's important to check if the current block refers to `it` variable somewhere
|
38
|
+
# (and not within a nested block), so we don't declare numbered params
|
39
|
+
def block_has_it?(node)
|
40
|
+
# traverse node children deeply
|
41
|
+
tree = [node]
|
42
|
+
|
43
|
+
while (child = tree.shift)
|
44
|
+
return true if it?(child)
|
45
|
+
|
46
|
+
if child.is_a?(Parser::AST::Node)
|
47
|
+
tree.unshift(*child.children.select { |c| c.is_a?(Parser::AST::Node) && c.type != :block && c.type != :numblock })
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def it?(node)
|
53
|
+
node.is_a?(Parser::AST::Node) && node.type == :send && node.children[0].nil? && node.children[1] == :it && node.children[2].nil?
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
@@ -1,3 +1,15 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
# Load edge Ruby features
|
4
|
+
|
5
|
+
require "ruby-next/language/rewriters/edge/it_param"
|
6
|
+
|
7
|
+
# We must add this rewriter before nubmered params rewriter to allow it to transform the source code further
|
8
|
+
|
9
|
+
number_params = RubyNext::Language.rewriters.index(RubyNext::Language::Rewriters::NumberedParams)
|
10
|
+
|
11
|
+
if number_params
|
12
|
+
RubyNext::Language.rewriters.insert(number_params, RubyNext::Language::Rewriters::ItParam)
|
13
|
+
else
|
14
|
+
RubyNext::Language.rewriters << RubyNext::Language::Rewriters::ItParam
|
15
|
+
end
|