ParseTree 1.7.1 → 2.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.
@@ -0,0 +1,147 @@
1
+
2
+ module UnifiedRuby
3
+ def rewrite_bmethod(exp)
4
+ exp[0] = :scope
5
+
6
+ args =
7
+ if exp.masgn and exp.masgn.dasgn_curr then
8
+ arg = exp.masgn(true).dasgn_curr(true).sexp_body
9
+ raise "nope: #{arg.size}" unless arg.size == 1
10
+ s(:args, :"*#{arg.last}")
11
+ else
12
+ args = exp.dasgn_curr(true)
13
+ if args then
14
+ s(:args, *args.sexp_body)
15
+ else
16
+ exp.delete_at 1 # nil
17
+ s(:args)
18
+ end
19
+ end
20
+
21
+ exp = s(:scope, s(:block, *exp.sexp_body)) unless exp.block
22
+ exp.block.insert 1, args
23
+ exp.find_and_replace_all(:dvar, :lvar)
24
+
25
+ exp
26
+ end
27
+
28
+ ##
29
+ # :defn is one of the most complex of all the ASTs in ruby. We do
30
+ # one of 3 different translations:
31
+ #
32
+ # 1) From:
33
+ #
34
+ # s(:defn, :name, s(:scope, s(:block, s(:args, ...), ...)))
35
+ # s(:defn, :name, s(:bmethod, s(:masgn, s(:dasgn_curr, :args)), s(:block, ...)))
36
+ # s(:defn, :name, s(:fbody, s(:bmethod, s(:masgn, s(:dasgn_curr, :splat)), s(:block, ...))))
37
+ #
38
+ # to:
39
+ #
40
+ # s(:defn, :name, s(:args, ...), s(:scope, s:(block, ...)))
41
+ #
42
+ # 2) From:
43
+ #
44
+ # s(:defn, :writer=, s(:attrset, :@name))
45
+ #
46
+ # to:
47
+ #
48
+ # s(:defn, :writer=, s(:args), s(:attrset, :@name))
49
+ #
50
+ # 3) From:
51
+ #
52
+ # s(:defn, :reader, s(:ivar, :@name))
53
+ #
54
+ # to:
55
+ #
56
+ # s(:defn, :reader, s(:args), s(:ivar, :@name))
57
+ #
58
+ #
59
+
60
+ def rewrite_defn(exp)
61
+ weirdo = exp.ivar || exp.attrset
62
+
63
+ # move args up
64
+ args = exp.scope.block.args(true) unless weirdo
65
+ exp.insert 2, args if args
66
+
67
+ # move block_arg up and in
68
+ block_arg = exp.scope.block.block_arg(true) rescue nil
69
+ exp.args << block_arg if block_arg
70
+
71
+ # patch up attr_accessor methods
72
+ exp.insert 2, s(:args) if weirdo
73
+
74
+ exp
75
+ end
76
+
77
+ def rewrite_dmethod(exp)
78
+ exp.shift # type
79
+ exp.shift # dmethod name
80
+ exp.shift # scope / block / body
81
+ end
82
+
83
+ def rewrite_fbody(exp)
84
+ return *exp.sexp_body
85
+ end
86
+
87
+ def rewrite_fcall(exp)
88
+ exp[0] = :call
89
+ exp.insert 1, nil
90
+ exp.push nil if exp.size <= 3
91
+
92
+ args = exp[-1]
93
+ if Array === args and args.first == :array then
94
+ args[0] = :arglist
95
+ elsif args.nil? then
96
+ exp[-1] = s(:arglist)
97
+ else
98
+ exp[-1] = s(:arglist, args) unless args.nil?
99
+ end
100
+
101
+ exp
102
+ end
103
+
104
+ def rewrite_resbody(exp) # TODO: clean up and move to unified
105
+ result = s()
106
+
107
+ code = result
108
+ while exp and exp.first == :resbody do
109
+ code << exp.shift
110
+ list = exp.shift || s(:array)
111
+ body = exp.shift rescue nil
112
+ exp = exp.shift rescue nil
113
+
114
+ # code may be nil, :lasgn, or :block
115
+ case body.first
116
+ when nil then
117
+ # do nothing
118
+ when :lasgn then
119
+ # TODO: check that it is assigning $!
120
+ list << body
121
+ body = nil
122
+ when :block then
123
+ # TODO: check that it is assigning $!
124
+ list << body.delete_at(1) if body[1].first == :lasgn
125
+ else
126
+ # do nothing (expression form)
127
+ end if body
128
+
129
+ code << list << body
130
+ if exp then
131
+ code = s()
132
+ result << code
133
+ end
134
+ end
135
+
136
+ raise unless result.first == :resbody
137
+ raise unless Sexp === result[1] and result[1].first == :array
138
+ raise unless result[2].nil? or (Sexp === result[2] and ! result[2].empty?)
139
+
140
+ result
141
+ end
142
+
143
+ def rewrite_vcall(exp)
144
+ exp.push nil
145
+ rewrite_fcall(exp)
146
+ end
147
+ end
@@ -1,3 +1,5 @@
1
+ $TESTING = true
2
+
1
3
  require 'test/unit/testcase'
2
4
  require 'sexp_processor' # for deep_clone
3
5
  require 'unique'
@@ -9,6 +11,10 @@ class Examples
9
11
  def a_method(x); x+1; end
10
12
  alias an_alias a_method
11
13
 
14
+ define_method(:bmethod_noargs) do
15
+ x + 1
16
+ end
17
+
12
18
  define_method(:unsplatted) do |x|
13
19
  x + 1
14
20
  end
@@ -133,11 +139,32 @@ class ParseTreeTestCase < Test::Unit::TestCase
133
139
  [:nil]]]
134
140
  },
135
141
 
142
+ "block_lasgn" => {
143
+ "Ruby" => "x = (y = 1\n(y + 2))",
144
+ "ParseTree" => [:lasgn, :x,
145
+ [:block,
146
+ [:lasgn, :y, [:lit, 1]],
147
+ [:call, [:lvar, :y], :+, [:array, [:lit, 2]]]]],
148
+ },
149
+
136
150
  "block_pass" => {
137
151
  "Ruby" => "a(&b)",
138
152
  "ParseTree" => [:block_pass, [:vcall, :b], [:fcall, :a]],
139
153
  },
140
154
 
155
+ "block_pass_args_and_splat" => {
156
+ "Ruby" => "def blah(*args, &block)\n other(42, *args, &block)\nend",
157
+ "ParseTree" => [:defn, :blah,
158
+ [:scope,
159
+ [:block,
160
+ [:args, "*args".intern],
161
+ [:block_arg, :block],
162
+ [:block_pass,
163
+ [:lvar, :block],
164
+ [:fcall, :other,
165
+ [:argscat, [:array, [:lit, 42]], [:lvar, :args]]]]]]],
166
+ },
167
+
141
168
  "block_pass_omgwtf" => {
142
169
  "Ruby" => "define_attr_method(:x, :sequence_name, &Proc.new { |*args| nil })",
143
170
  "ParseTree" => [:block_pass,
@@ -161,29 +188,26 @@ class ParseTreeTestCase < Test::Unit::TestCase
161
188
  [:fcall, :other, [:splat, [:lvar, :args]]]]]]],
162
189
  },
163
190
 
164
- "block_pass_args_and_splat" => {
165
- "Ruby" => "def blah(*args, &block)\n other(42, *args, &block)\nend",
166
- "ParseTree" => [:defn, :blah,
167
- [:scope,
168
- [:block,
169
- [:args, "*args".intern],
170
- [:block_arg, :block],
171
- [:block_pass,
172
- [:lvar, :block],
173
- [:fcall, :other,
174
- [:argscat, [:array, [:lit, 42]], [:lvar, :args]]]]]]],
175
- },
176
-
177
191
  "bmethod" => {
178
192
  "Ruby" => [Examples, :unsplatted],
179
193
  "ParseTree" => [:defn,
180
194
  :unsplatted,
181
195
  [:bmethod,
182
196
  [:dasgn_curr, :x],
183
- [:call, [:dvar, :x], "+".intern, [:array, [:lit, 1]]]]],
197
+ [:call, [:dvar, :x], :+, [:array, [:lit, 1]]]]],
184
198
  "Ruby2Ruby" => "def unsplatted(x)\n (x + 1)\nend"
185
199
  },
186
200
 
201
+ "bmethod_noargs" => {
202
+ "Ruby" => [Examples, :bmethod_noargs],
203
+ "ParseTree" => [:defn,
204
+ :bmethod_noargs,
205
+ [:bmethod,
206
+ nil,
207
+ [:call, [:vcall, :x], "+".intern, [:array, [:lit, 1]]]]],
208
+ "Ruby2Ruby" => "def bmethod_noargs\n (x + 1)\nend"
209
+ },
210
+
187
211
  "bmethod_splat" => {
188
212
  "Ruby" => [Examples, :splatted],
189
213
  "ParseTree" => [:defn, :splatted,
@@ -218,6 +242,14 @@ class ParseTreeTestCase < Test::Unit::TestCase
218
242
  "ParseTree" => [:fcall, :puts, [:array, [:lit, 42]]],
219
243
  },
220
244
 
245
+ "call_expr" => {
246
+ "Ruby" => "(v = (1 + 1)).zero?",
247
+ "ParseTree" => [:call,
248
+ [:lasgn, :v,
249
+ [:call, [:lit, 1], :+, [:array, [:lit, 1]]]],
250
+ :zero?],
251
+ },
252
+
221
253
  "call_index" => { # see attrasgn_index_equals for opposite
222
254
  "Ruby" => "a[42]",
223
255
  "ParseTree" => [:call, [:vcall, :a], :[], [:array, [:lit, 42]]],
@@ -310,14 +342,6 @@ class ParseTreeTestCase < Test::Unit::TestCase
310
342
  [:fcall, :puts, [:array, [:str, "hello"]]]]]]]]],
311
343
  },
312
344
 
313
- "class_super_object" => {
314
- "Ruby" => "class X < Object\nend",
315
- "ParseTree" => [:class,
316
- :X,
317
- [:const, :Object],
318
- [:scope]],
319
- },
320
-
321
345
  "class_super_array" => {
322
346
  "Ruby" => "class X < Array\nend",
323
347
  "ParseTree" => [:class,
@@ -334,6 +358,14 @@ class ParseTreeTestCase < Test::Unit::TestCase
334
358
  [:scope]],
335
359
  },
336
360
 
361
+ "class_super_object" => {
362
+ "Ruby" => "class X < Object\nend",
363
+ "ParseTree" => [:class,
364
+ :X,
365
+ [:const, :Object],
366
+ [:scope]],
367
+ },
368
+
337
369
  "colon2" => {
338
370
  "Ruby" => "X::Y",
339
371
  "ParseTree" => [:colon2, [:const, :X], :Y],
@@ -458,14 +490,15 @@ class ParseTreeTestCase < Test::Unit::TestCase
458
490
  "ParseTree" => [:defn, :something?, [:scope, [:block, [:args], [:nil]]]],
459
491
  },
460
492
 
461
- # TODO:
462
- # add_test("defn_optargs",
463
- # s(:defn, :x,
464
- # s(:args, :a, "*args".intern),
465
- # s(:scope,
466
- # s(:block,
467
- # s(:call, nil, :p,
468
- # s(:arglist, s(:lvar, :a), s(:lvar, :args)))))))
493
+ "defn_optargs" => {
494
+ "Ruby" => "def x(a, *args)\n p(a, args)\nend",
495
+ "ParseTree" => [:defn, :x,
496
+ [:scope,
497
+ [:block,
498
+ [:args, :a, "*args".intern],
499
+ [:fcall, :p,
500
+ [:array, [:lvar, :a], [:lvar, :args]]]]]],
501
+ },
469
502
 
470
503
  "defn_or" => {
471
504
  "Ruby" => "def |(o)\n # do nothing\nend",
@@ -475,15 +508,25 @@ class ParseTreeTestCase < Test::Unit::TestCase
475
508
  "defn_rescue" => {
476
509
  "Ruby" => "def eql?(resource)\n (self.uuid == resource.uuid) rescue false\nend",
477
510
  "ParseTree" => [:defn, :eql?,
478
- [:scope,
479
- [:block,
480
- [:args, :resource],
481
- [:rescue,
482
- [:call,
483
- [:call, [:self], :uuid],
484
- :==,
485
- [:array, [:call, [:lvar, :resource], :uuid]]],
486
- [:resbody, nil, [:false]]]]]],
511
+ [:scope,
512
+ [:block,
513
+ [:args, :resource],
514
+ [:rescue,
515
+ [:call,
516
+ [:call, [:self], :uuid],
517
+ :==,
518
+ [:array, [:call, [:lvar, :resource], :uuid]]],
519
+ [:resbody, nil, [:false]]]]]],
520
+ },
521
+
522
+ "defn_splat_no_name" => {
523
+ "Ruby" => "def x(a, *)\n p(a)\nend",
524
+ "ParseTree" => [:defn, :x,
525
+ [:scope,
526
+ [:block,
527
+ [:args, :a, "*".intern],
528
+ [:fcall, :p,
529
+ [:array, [:lvar, :a]]]]]],
487
530
  },
488
531
 
489
532
  "defn_zarray" => { # tests memory allocation for returns
@@ -668,11 +711,41 @@ end",
668
711
  "ParseTree" => [:hash, [:lit, 1], [:lit, 2], [:lit, 3], [:lit, 4]],
669
712
  },
670
713
 
714
+ "hash_rescue" => {
715
+ "Ruby" => "{ 1 => (2 rescue 3) }",
716
+ "ParseTree" => [:hash,
717
+ [:lit, 1],
718
+ [:rescue, [:lit, 2], [:resbody, nil, [:lit, 3]]]],
719
+ },
720
+
671
721
  "iasgn" => {
672
722
  "Ruby" => "@a = 4",
673
723
  "ParseTree" => [:iasgn, :@a, [:lit, 4]],
674
724
  },
675
725
 
726
+ "if_block_condition" => {
727
+ "Ruby" => "if (x = 5\n(x + 1)) then\n nil\nend",
728
+ "ParseTree" => [:if,
729
+ [:block,
730
+ [:lasgn, :x, [:lit, 5]],
731
+ [:call,
732
+ [:lvar, :x],
733
+ :+,
734
+ [:array, [:lit, 1]]]],
735
+ [:nil],
736
+ nil],
737
+ },
738
+
739
+ "if_lasgn_short" => {
740
+ "Ruby" => "if x = obj.x then\n x.do_it\nend",
741
+ "ParseTree" => [:if,
742
+ [:lasgn, :x,
743
+ [:call, [:vcall, :obj], :x]],
744
+ [:call,
745
+ [:lvar, :x], :do_it],
746
+ nil],
747
+ },
748
+
676
749
  "iteration1" => {
677
750
  "Ruby" => "loop { }",
678
751
  "ParseTree" => [:iter, [:fcall, :loop], nil],
@@ -811,11 +884,14 @@ end",
811
884
  [:array, [:vcall, :c], [:vcall, :d]]],
812
885
  },
813
886
 
814
- "masgn_iasgn" => {
815
- "Ruby" => "a, @b = c, d",
887
+ "masgn_argscat" => {
888
+ "Ruby" => "a, b, *c = 1, 2, *[3, 4]",
816
889
  "ParseTree" => [:masgn,
817
- [:array, [:lasgn, :a], [:iasgn, "@b".intern]],
818
- [:array, [:vcall, :c], [:vcall, :d]]],
890
+ [:array, [:lasgn, :a], [:lasgn, :b]],
891
+ [:lasgn, :c],
892
+ [:argscat,
893
+ [:array, [:lit, 1], [:lit, 2]],
894
+ [:array, [:lit, 3], [:lit, 4]]]]
819
895
  },
820
896
 
821
897
  "masgn_attrasgn" => {
@@ -825,6 +901,31 @@ end",
825
901
  [:array, [:vcall, :d], [:vcall, :e]]],
826
902
  },
827
903
 
904
+ "masgn_iasgn" => {
905
+ "Ruby" => "a, @b = c, d",
906
+ "ParseTree" => [:masgn,
907
+ [:array, [:lasgn, :a], [:iasgn, "@b".intern]],
908
+ [:array, [:vcall, :c], [:vcall, :d]]],
909
+ },
910
+
911
+ "masgn_masgn" => {
912
+ "Ruby" => "a, (b, c) = [1, [2, 3]]",
913
+ "ParseTree" => [:masgn,
914
+ [:array,
915
+ [:lasgn, :a],
916
+ [:masgn,
917
+ [:array,
918
+ [:lasgn, :b],
919
+ [:lasgn, :c]]]],
920
+ [:to_ary,
921
+ [:array,
922
+ [:lit, 1],
923
+ [:array,
924
+ [:lit, 2],
925
+ [:lit, 3]]]]]
926
+
927
+ },
928
+
828
929
  "masgn_splat" => {
829
930
  "Ruby" => "a, b, *c = d, e, f, g",
830
931
  "ParseTree" => [:masgn,
@@ -835,7 +936,6 @@ end",
835
936
  [:vcall, :f], [:vcall, :g]]]
836
937
  },
837
938
 
838
-
839
939
  "match" => {
840
940
  "Ruby" => "1 if /x/",
841
941
  "ParseTree" => [:if, [:match, [:lit, /x/]], [:lit, 1], nil],
@@ -994,8 +1094,12 @@ end",
994
1094
  },
995
1095
 
996
1096
  "splat" => {
997
- "Ruby" => "a(*b)",
998
- "ParseTree" => [:fcall, :a, [:splat, [:vcall, :b]]],
1097
+ "Ruby" => "def x(*b)\n a(*b)\nend",
1098
+ "ParseTree" => [:defn, :x,
1099
+ [:scope,
1100
+ [:block,
1101
+ [:args, :"*b"],
1102
+ [:fcall, :a, [:splat, [:lvar, :b]]]]]],
999
1103
  },
1000
1104
 
1001
1105
  # TODO: all supers need to pass args
@@ -1070,6 +1174,12 @@ end",
1070
1174
  "ParseTree" => [:vcall, :method],
1071
1175
  },
1072
1176
 
1177
+ "while_post" => {
1178
+ "Ruby" => "begin\n (1 + 1)\nend while false",
1179
+ "ParseTree" => [:while, [:false],
1180
+ [:call, [:lit, 1], :+, [:array, [:lit, 1]]], false],
1181
+ },
1182
+
1073
1183
  "while_pre" => {
1074
1184
  "Ruby" => "while false do\n (1 + 1)\nend",
1075
1185
  "ParseTree" => [:while, [:false],
@@ -1081,12 +1191,6 @@ end",
1081
1191
  "ParseTree" => [:while, [:false], nil, true],
1082
1192
  },
1083
1193
 
1084
- "while_post" => {
1085
- "Ruby" => "begin\n (1 + 1)\nend while false",
1086
- "ParseTree" => [:while, [:false],
1087
- [:call, [:lit, 1], :+, [:array, [:lit, 1]]], false],
1088
- },
1089
-
1090
1194
  "xstr" => {
1091
1195
  "Ruby" => "`touch 5`",
1092
1196
  "ParseTree" => [:xstr, 'touch 5'],
@@ -1170,7 +1274,8 @@ end",
1170
1274
 
1171
1275
  def self.inherited(c)
1172
1276
  output_name = c.name.to_s.sub(/^Test/, '')
1173
- raise "Unknown class #{c}" unless @@testcase_order.include? output_name
1277
+ raise "Unknown class #{c} in @@testcase_order" unless
1278
+ @@testcase_order.include? output_name
1174
1279
 
1175
1280
  input_name = self.previous(output_name)
1176
1281