ruby-next-core 0.10.0 → 0.10.5

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.
@@ -0,0 +1,117 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RubyNext
4
+ module Language
5
+ module Rewriters
6
+ class RightHandAssignment < Base
7
+ NAME = "right-hand-assignment"
8
+ SYNTAX_PROBE = "1 + 2 => a"
9
+ MIN_SUPPORTED_VERSION = Gem::Version.new("3.0.0")
10
+
11
+ def on_rasgn(node)
12
+ context.track! self
13
+
14
+ node = super(node)
15
+
16
+ val_node, asgn_node = *node
17
+
18
+ remove(val_node.loc.expression.end.join(asgn_node.loc.expression))
19
+ insert_before(val_node.loc.expression, "#{asgn_node.loc.expression.source} = ")
20
+
21
+ asgn_node.updated(
22
+ nil,
23
+ asgn_node.children + [val_node]
24
+ )
25
+ end
26
+
27
+ def on_vasgn(node)
28
+ return super(node) unless rightward?(node)
29
+
30
+ context.track! self
31
+
32
+ name, val_node = *node
33
+
34
+ remove(val_node.loc.expression.end.join(node.loc.name))
35
+ insert_before(val_node.loc.expression, "#{name} = ")
36
+
37
+ super(node)
38
+ end
39
+
40
+ def on_casgn(node)
41
+ return super(node) unless rightward?(node)
42
+
43
+ context.track! self
44
+
45
+ scope_node, name, val_node = *node
46
+
47
+ if scope_node
48
+ scope = scope_node.type == :cbase ? scope_node.loc.expression.source : "#{scope_node.loc.expression.source}::"
49
+ name = "#{scope}#{name}"
50
+ end
51
+
52
+ remove(val_node.loc.expression.end.join(node.loc.name))
53
+ insert_before(val_node.loc.expression, "#{name} = ")
54
+
55
+ super(node)
56
+ end
57
+
58
+ def on_mrasgn(node)
59
+ context.track! self
60
+
61
+ node = super(node)
62
+
63
+ lhs, rhs = *node
64
+
65
+ replace(lhs.loc.expression.end.join(rhs.loc.expression), ")")
66
+ insert_before(lhs.loc.expression, "#{rhs.loc.expression.source} = (")
67
+
68
+ node.updated(
69
+ :masgn,
70
+ [rhs, lhs]
71
+ )
72
+ end
73
+
74
+ def on_masgn(node)
75
+ return super(node) unless rightward?(node)
76
+
77
+ context.track! self
78
+
79
+ rhs, lhs = *node
80
+
81
+ replace(lhs.loc.expression.end.join(rhs.loc.expression), ")")
82
+ insert_before(lhs.loc.expression, "#{rhs.loc.expression.source} = (")
83
+
84
+ node = super(node)
85
+
86
+ lhs, rhs = *node
87
+
88
+ node.updated(
89
+ nil,
90
+ [
91
+ lhs,
92
+ s(:begin, rhs)
93
+ ]
94
+ )
95
+ end
96
+
97
+ private
98
+
99
+ def rightward?(node)
100
+ # Location could be empty for node built by rewriters
101
+ return false unless ((!node.loc.nil? || nil) && node.loc.operator)
102
+
103
+ assignee_loc =
104
+ if node.type == :masgn
105
+ node.children[0].loc.expression
106
+ else
107
+ node.loc.name
108
+ end
109
+
110
+ return false unless assignee_loc
111
+
112
+ assignee_loc.begin_pos > node.loc.operator.end_pos
113
+ end
114
+ end
115
+ end
116
+ end
117
+ end
@@ -6,7 +6,7 @@ module RubyNext
6
6
 
7
7
  if $LOAD_PATH.respond_to?(:resolve_feature_path)
8
8
  def resolve_feature_path(feature)
9
- ((!$LOAD_PATH.resolve_feature_path(feature).nil?) || nil) && $LOAD_PATH.resolve_feature_path(feature).last
9
+ ((!$LOAD_PATH.resolve_feature_path(feature).nil? || nil) && $LOAD_PATH.resolve_feature_path(feature).last)
10
10
  rescue LoadError
11
11
  end
12
12
  else
@@ -148,6 +148,9 @@ module RubyNext
148
148
 
149
149
  # Then, generate the source code for the next version
150
150
  transpile path, contents, version: version
151
+ rescue SyntaxError, StandardError => e
152
+ warn "Failed to transpile #{path}: #{e.class} — #{e.message}"
153
+ exit 1
151
154
  end
152
155
 
153
156
  def save(contents, path, version)
@@ -6,7 +6,7 @@ module RubyNext
6
6
  class ArgsForward < Base
7
7
  NAME = "args-forward"
8
8
  SYNTAX_PROBE = "obj = Object.new; def obj.foo(...) super(1, ...); end"
9
- MIN_SUPPORTED_VERSION = Gem::Version.new("2.7.2")
9
+ MIN_SUPPORTED_VERSION = Gem::Version.new("3.0.0")
10
10
 
11
11
  REST = :__rest__
12
12
  BLOCK = :__block__
@@ -112,7 +112,8 @@ module RubyNext
112
112
 
113
113
  def unparse(ast)
114
114
  return ast if ast.is_a?(String)
115
- Unparser.unparse(ast)
115
+
116
+ Unparser.unparse(ast).chomp
116
117
  end
117
118
 
118
119
  attr_reader :context
@@ -16,9 +16,9 @@ module RubyNext
16
16
  proc_or_lambda, num, body = *node.children
17
17
 
18
18
  if proc_or_lambda.type == :lambda
19
- insert_before(node.loc.begin, "(#{unparse(proc_args(num))})")
19
+ insert_before(node.loc.begin, "(#{proc_args_str(num)})")
20
20
  else
21
- insert_after(node.loc.begin, " |#{unparse(proc_args(num))}|")
21
+ insert_after(node.loc.begin, " |#{proc_args_str(num)}|")
22
22
  end
23
23
 
24
24
  node.updated(
@@ -33,6 +33,10 @@ module RubyNext
33
33
 
34
34
  private
35
35
 
36
+ def proc_args_str(n)
37
+ (1..n).map { |numero| "_#{numero}" }.join(", ")
38
+ end
39
+
36
40
  def proc_args(n)
37
41
  return s(:args, s(:procarg0, s(:arg, :_1))) if n == 1
38
42
 
@@ -244,7 +244,7 @@ module RubyNext
244
244
  @predicates = Predicates::CaseIn.new
245
245
 
246
246
  matchee_ast =
247
- s(:lvasgn, MATCHEE, node.children[0])
247
+ s(:begin, s(:lvasgn, MATCHEE, node.children[0]))
248
248
 
249
249
  patterns = locals.with(
250
250
  matchee: MATCHEE,
@@ -273,7 +273,7 @@ module RubyNext
273
273
  @predicates = Predicates::Noop.new
274
274
 
275
275
  matchee =
276
- s(:lvasgn, MATCHEE, node.children[0])
276
+ s(:begin, s(:lvasgn, MATCHEE, node.children[0]))
277
277
 
278
278
  pattern =
279
279
  locals.with(
@@ -285,9 +285,10 @@ module RubyNext
285
285
  :"#{node.children[1].type}_clause",
286
286
  node.children[1]
287
287
  ).then do |node|
288
- s(:or,
289
- node,
290
- no_matching_pattern)
288
+ s(:begin,
289
+ s(:or,
290
+ node,
291
+ no_matching_pattern))
291
292
  end
292
293
  end
293
294
 
@@ -378,9 +379,10 @@ module RubyNext
378
379
  predicates.const(case_eq_clause(const, right), const).then do |node|
379
380
  next node if pattern.nil?
380
381
 
381
- s(:and,
382
- node,
383
- send(:"#{pattern.type}_clause", pattern))
382
+ s(:begin,
383
+ s(:and,
384
+ node,
385
+ send(:"#{pattern.type}_clause", pattern)))
384
386
  end
385
387
  end
386
388
 
@@ -391,13 +393,14 @@ module RubyNext
391
393
  send :"#{child.type}_clause", child
392
394
  end
393
395
  end
394
- s(:or, *children)
396
+ s(:begin, s(:or, *children))
395
397
  end
396
398
 
397
399
  def match_as_clause(node, right = s(:lvar, locals[:matchee]))
398
- s(:and,
399
- send(:"#{node.children[0].type}_clause", node.children[0], right),
400
- match_var_clause(node.children[1], right))
400
+ s(:begin,
401
+ s(:and,
402
+ send(:"#{node.children[0].type}_clause", node.children[0], right),
403
+ match_var_clause(node.children[1], right)))
401
404
  end
402
405
 
403
406
  def match_var_clause(node, left = s(:lvar, locals[:matchee]))
@@ -405,9 +408,10 @@ module RubyNext
405
408
 
406
409
  check_match_var_alternation! node.children[0]
407
410
 
408
- s(:or,
409
- s(:lvasgn, node.children[0], left),
410
- s(:true))
411
+ s(:begin,
412
+ s(:or,
413
+ s(:begin, s(:lvasgn, node.children[0], left)),
414
+ s(:true)))
411
415
  end
412
416
 
413
417
  def pin_clause(node, right = s(:lvar, locals[:matchee]))
@@ -417,8 +421,8 @@ module RubyNext
417
421
 
418
422
  def case_eq_clause(node, right = s(:lvar, locals[:matchee]))
419
423
  predicates.terminate!
420
- s(:send,
421
- process(node), :===, right)
424
+ s(:begin, s(:send,
425
+ process(node), :===, right))
422
426
  end
423
427
 
424
428
  #=========== ARRAY PATTERN (START) ===============
@@ -429,10 +433,11 @@ module RubyNext
429
433
  # if there is no rest or tail, match the size first
430
434
  unless node.type == :array_pattern_with_tail || node.children.any? { |n| n.type == :match_rest }
431
435
  size_check = predicates.array_size(
432
- s(:send,
433
- node.children.size.to_ast_node,
434
- :==,
435
- s(:send, s(:lvar, locals[:arr]), :size)),
436
+ s(:begin,
437
+ s(:send,
438
+ node.children.size.to_ast_node,
439
+ :==,
440
+ s(:send, s(:lvar, locals[:arr]), :size))),
436
441
  node.children.size
437
442
  )
438
443
  end
@@ -448,9 +453,10 @@ module RubyNext
448
453
 
449
454
  right = s(:and, size_check, right) if size_check
450
455
 
451
- s(:and,
452
- dnode,
453
- right)
456
+ s(:begin,
457
+ s(:and,
458
+ dnode,
459
+ right))
454
460
  end
455
461
  end
456
462
 
@@ -468,14 +474,17 @@ module RubyNext
468
474
  predicates.array_deconstructed(
469
475
  s(:and,
470
476
  respond_check,
471
- s(:and,
472
- s(:or,
473
- s(:lvasgn, locals[:arr], right),
474
- s(:true)),
475
- s(:or,
476
- s(:send,
477
- s(:const, nil, :Array), :===, s(:lvar, locals[:arr])),
478
- raise_error(:TypeError, "#deconstruct must return Array"))))
477
+ s(:begin,
478
+ s(:and,
479
+ s(:begin,
480
+ s(:or,
481
+ s(:begin, s(:lvasgn, locals[:arr], right)),
482
+ s(:true))),
483
+ s(:begin,
484
+ s(:or,
485
+ s(:send,
486
+ s(:const, nil, :Array), :===, s(:lvar, locals[:arr])),
487
+ raise_error(:TypeError, "#deconstruct must return Array"))))))
479
488
  )
480
489
  end
481
490
 
@@ -485,9 +494,10 @@ module RubyNext
485
494
  send("#{head.type}_array_element", head, index).then do |node|
486
495
  next node if tail.empty?
487
496
 
488
- s(:and,
489
- node,
490
- array_element(index + 1, *tail))
497
+ s(:begin,
498
+ s(:and,
499
+ node,
500
+ array_element(index + 1, *tail)))
491
501
  end
492
502
  end
493
503
 
@@ -526,15 +536,17 @@ module RubyNext
526
536
 
527
537
  pattern = array_rest_element(*nodes, index).then do |needle|
528
538
  next needle unless head_match
529
- s(:and,
530
- needle,
531
- head_match)
539
+ s(:begin,
540
+ s(:and,
541
+ needle,
542
+ head_match))
532
543
  end.then do |headed_needle|
533
544
  next headed_needle unless tail_match
534
545
 
535
- s(:and,
536
- headed_needle,
537
- tail_match)
546
+ s(:begin,
547
+ s(:and,
548
+ headed_needle,
549
+ tail_match))
538
550
  end
539
551
 
540
552
  s(:block,
@@ -550,13 +562,14 @@ module RubyNext
550
562
  next block if match_vars.empty?
551
563
 
552
564
  # We need to declare match vars outside of `find` block
553
- locals_declare = s(:masgn,
565
+ locals_declare = s(:begin, s(:masgn,
554
566
  s(:mlhs, *match_vars),
555
- s(:nil))
567
+ s(:nil)))
556
568
 
557
- s(:or,
558
- locals_declare,
559
- block)
569
+ s(:begin,
570
+ s(:or,
571
+ locals_declare,
572
+ block))
560
573
  end
561
574
  end
562
575
 
@@ -575,18 +588,20 @@ module RubyNext
575
588
 
576
589
  return rest if tail.empty?
577
590
 
578
- s(:and,
579
- rest,
580
- array_rest_element(*tail, -(size - 1)))
591
+ s(:begin,
592
+ s(:and,
593
+ rest,
594
+ array_rest_element(*tail, -(size - 1))))
581
595
  end
582
596
 
583
597
  def array_rest_element(head, *tail, index)
584
598
  send("#{head.type}_array_element", head, index).then do |node|
585
599
  next node if tail.empty?
586
600
 
587
- s(:and,
588
- node,
589
- array_rest_element(*tail, index + 1))
601
+ s(:begin,
602
+ s(:and,
603
+ node,
604
+ array_rest_element(*tail, index + 1)))
590
605
  end
591
606
  end
592
607
 
@@ -610,7 +625,7 @@ module RubyNext
610
625
  children = node.children.map do |child, i|
611
626
  send :"#{child.type}_array_element", child, index
612
627
  end
613
- s(:or, *children)
628
+ s(:begin, s(:or, *children))
614
629
  end
615
630
 
616
631
  def match_var_array_element(node, index)
@@ -661,18 +676,20 @@ module RubyNext
661
676
  elsif specified_key_names.empty?
662
677
  hash_element(*node.children)
663
678
  else
664
- s(:and,
665
- having_hash_keys(specified_key_names),
666
- hash_element(*node.children))
679
+ s(:begin,
680
+ s(:and,
681
+ having_hash_keys(specified_key_names),
682
+ hash_element(*node.children)))
667
683
  end
668
684
 
669
685
  predicates.pop
670
686
 
671
687
  next dnode if right.nil?
672
688
 
673
- s(:and,
674
- dnode,
675
- right)
689
+ s(:begin,
690
+ s(:and,
691
+ dnode,
692
+ right))
676
693
  end
677
694
  end
678
695
 
@@ -715,7 +732,7 @@ module RubyNext
715
732
  # Duplicate the source hash when matching **rest, 'cause we mutate it
716
733
  hash_dup =
717
734
  if @hash_match_rest
718
- s(:lvasgn, locals[:hash], s(:send, s(:lvar, locals[:hash, :src]), :dup))
735
+ s(:begin, s(:lvasgn, locals[:hash], s(:send, s(:lvar, locals[:hash, :src]), :dup)))
719
736
  else
720
737
  s(:true)
721
738
  end
@@ -728,29 +745,33 @@ module RubyNext
728
745
  key_names = keys.children.map { |node| node.children.last }
729
746
  predicates.push locals[:hash]
730
747
 
731
- s(:lvasgn, deconstruct_name,
748
+ s(:begin, s(:lvasgn, deconstruct_name,
732
749
  s(:send,
733
- matchee, :deconstruct_keys, keys)).then do |dnode|
750
+ matchee, :deconstruct_keys, keys))).then do |dnode|
734
751
  next dnode if respond_to_checked
735
752
 
736
753
  s(:and,
737
754
  respond_check,
738
- s(:and,
739
- s(:or,
740
- dnode,
741
- s(:true)),
742
- s(:or,
743
- s(:send,
744
- s(:const, nil, :Hash), :===, s(:lvar, deconstruct_name)),
745
- raise_error(:TypeError, "#deconstruct_keys must return Hash"))))
755
+ s(:begin,
756
+ s(:and,
757
+ s(:begin,
758
+ s(:or,
759
+ dnode,
760
+ s(:true))),
761
+ s(:begin,
762
+ s(:or,
763
+ s(:send,
764
+ s(:const, nil, :Hash), :===, s(:lvar, deconstruct_name)),
765
+ raise_error(:TypeError, "#deconstruct_keys must return Hash"))))))
746
766
  end.then do |dnode|
747
767
  predicates.hash_deconstructed(dnode, key_names)
748
768
  end.then do |dnode|
749
769
  next dnode unless @hash_match_rest
750
770
 
751
- s(:and,
752
- dnode,
753
- hash_dup)
771
+ s(:begin,
772
+ s(:and,
773
+ dnode,
774
+ hash_dup))
754
775
  end
755
776
  end
756
777
 
@@ -780,9 +801,10 @@ module RubyNext
780
801
 
781
802
  next node if right.nil?
782
803
 
783
- s(:and,
784
- node,
785
- right)
804
+ s(:begin,
805
+ s(:and,
806
+ node,
807
+ right))
786
808
  end
787
809
  end
788
810
 
@@ -792,7 +814,7 @@ module RubyNext
792
814
  end
793
815
 
794
816
  def match_alt_hash_element(node, key)
795
- element_node = s(:lvasgn, locals[:hash, :el], hash_value_at(key))
817
+ element_node = s(:begin, s(:lvasgn, locals[:hash, :el], hash_value_at(key)))
796
818
 
797
819
  children = locals.with(hash_element: locals[:hash, :el]) do
798
820
  node.children.map do |child, i|
@@ -800,11 +822,14 @@ module RubyNext
800
822
  end
801
823
  end
802
824
 
803
- s(:and,
804
- s(:or,
805
- element_node,
806
- s(:true)),
807
- s(:or, *children))
825
+ s(:begin,
826
+ s(:and,
827
+ s(:begin,
828
+ s(:or,
829
+ element_node,
830
+ s(:true))),
831
+ s(:begin,
832
+ s(:or, *children))))
808
833
  end
809
834
 
810
835
  def match_as_hash_element(node, key)
@@ -862,9 +887,10 @@ module RubyNext
862
887
  node = predicates.hash_key(hash_has_key(key, hash), key)
863
888
 
864
889
  keys.reduce(node) do |res, key|
865
- s(:and,
866
- res,
867
- predicates.hash_key(hash_has_key(key, hash), key))
890
+ s(:begin,
891
+ s(:and,
892
+ res,
893
+ predicates.hash_key(hash_has_key(key, hash), key)))
868
894
  end
869
895
  end
870
896
 
@@ -873,9 +899,10 @@ module RubyNext
873
899
  def with_guard(node, guard)
874
900
  return node unless guard
875
901
 
876
- s(:and,
877
- node,
878
- guard.children[0]).then do |expr|
902
+ s(:begin,
903
+ s(:and,
904
+ node,
905
+ guard.children[0])).then do |expr|
879
906
  next expr unless guard.type == :unless_guard
880
907
  s(:send, expr, :!)
881
908
  end
@@ -933,10 +960,10 @@ module RubyNext
933
960
  deconstructed_keys[key] = :"k#{deconstructed_keys.size}"
934
961
  end
935
962
 
936
- # Unparser generates `do .. end` blocks, we want to
963
+ # Unparser generates `do .. end` or `{ ... }` multiline blocks, we want to
937
964
  # have single-line blocks with `{ ... }`.
938
965
  def inline_blocks(source)
939
- source.gsub(/do \|_, __i__\|\n\s*([^\n]+)\n\s*end/, '{ |_, __i__| \1 }')
966
+ source.gsub(/(?:do|{) \|_, __i__\|\n\s*([^\n]+)\n\s*(?:end|})/, '{ |_, __i__| \1 }')
940
967
  end
941
968
  end
942
969
  end