ParseTree 1.7.1 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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