ruby2ruby 1.1.6 → 1.1.7
Sign up to get free protection for your applications and to get access to all the features.
- data/History.txt +19 -0
- data/Manifest.txt +1 -0
- data/bin/r2r_show +44 -0
- data/lib/ruby2ruby.rb +142 -176
- data/test/test_ruby2ruby.rb +63 -81
- metadata +6 -5
data/History.txt
CHANGED
@@ -1,3 +1,22 @@
|
|
1
|
+
=== 1.1.7 / 2007-08-21
|
2
|
+
|
3
|
+
* 2 major enhancements:
|
4
|
+
* Switched to ParseTree's UnifiedRuby... much much cleaner now!
|
5
|
+
* Made test_ruby2ruby MUCH more rigorous with circular testing.
|
6
|
+
* 5 minor enhancements:
|
7
|
+
* Add r2r_show command like parse_tree_show.
|
8
|
+
* Add parens for :block nodes as appropriate. May be overzealous.
|
9
|
+
* Make SexpAny work with #==.
|
10
|
+
* Removed calls to processor_stack / caller in favor of self.context.
|
11
|
+
* Some style differences, eschew rescue.
|
12
|
+
* 6 bug fixes:
|
13
|
+
* Fix R2R bug with masgn/argscat.
|
14
|
+
* Fixed a bug with new resbody unification.
|
15
|
+
* Fixes for changes to pt_testcase.
|
16
|
+
* Fixes the rest of the tests under strict sexp checking.
|
17
|
+
* Fixed some circular bugs, mostly by hacking them out, wrt operator precidence.
|
18
|
+
* Fixed trinary operator.
|
19
|
+
|
1
20
|
=== 1.1.6 / 2007-06-05
|
2
21
|
|
3
22
|
* 2 minor enhancements:
|
data/Manifest.txt
CHANGED
data/bin/r2r_show
ADDED
@@ -0,0 +1,44 @@
|
|
1
|
+
#!/usr/local/bin/ruby -ws
|
2
|
+
|
3
|
+
begin require 'rubygems' rescue LoadError end
|
4
|
+
require 'ruby2ruby'
|
5
|
+
|
6
|
+
def discover_new_classes_from
|
7
|
+
old_classes = []
|
8
|
+
ObjectSpace.each_object(Module) do |klass|
|
9
|
+
old_classes << klass
|
10
|
+
end
|
11
|
+
|
12
|
+
yield
|
13
|
+
|
14
|
+
new_classes = []
|
15
|
+
ObjectSpace.each_object(Module) do |klass|
|
16
|
+
new_classes << klass
|
17
|
+
end
|
18
|
+
|
19
|
+
new_classes -= old_classes
|
20
|
+
new_classes = [ eval($c) ] if defined? $c
|
21
|
+
new_classes
|
22
|
+
end
|
23
|
+
|
24
|
+
$f = true unless defined? $f
|
25
|
+
|
26
|
+
new_classes = discover_new_classes_from do
|
27
|
+
ARGV.unshift "-" if ARGV.empty?
|
28
|
+
ARGV.each do |name|
|
29
|
+
if name == "-" then
|
30
|
+
code = $stdin.read
|
31
|
+
code = "class Example; def example; #{code}; end; end" if $f
|
32
|
+
eval code unless code.nil?
|
33
|
+
else
|
34
|
+
require name
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
result = ParseTree.new.parse_tree(*new_classes)
|
40
|
+
|
41
|
+
result = result[0][3][2][1][2..-1] if $f
|
42
|
+
|
43
|
+
puts RubyToRuby.new.process(result.first)
|
44
|
+
|
data/lib/ruby2ruby.rb
CHANGED
@@ -3,6 +3,7 @@
|
|
3
3
|
begin require 'rubygems'; rescue LoadError; end
|
4
4
|
require 'parse_tree'
|
5
5
|
require 'sexp_processor'
|
6
|
+
require 'unified_ruby'
|
6
7
|
|
7
8
|
class NilClass # Objective-C trick
|
8
9
|
def method_missing(msg, *args, &block)
|
@@ -11,9 +12,27 @@ class NilClass # Objective-C trick
|
|
11
12
|
end
|
12
13
|
|
13
14
|
class RubyToRuby < SexpProcessor
|
14
|
-
|
15
|
+
include UnifiedRuby
|
16
|
+
|
17
|
+
VERSION = '1.1.7'
|
15
18
|
LINE_LENGTH = 78
|
16
19
|
|
20
|
+
##
|
21
|
+
# Nodes that represent assignment and probably need () around them.
|
22
|
+
|
23
|
+
ASSIGN_NODES = [
|
24
|
+
:dasgn,
|
25
|
+
:flip2,
|
26
|
+
:flip3,
|
27
|
+
:lasgn,
|
28
|
+
:masgn,
|
29
|
+
:op_asgn1,
|
30
|
+
:op_asgn2,
|
31
|
+
:op_asgn_and,
|
32
|
+
:op_asgn_or,
|
33
|
+
:return,
|
34
|
+
]
|
35
|
+
|
17
36
|
def self.translate(klass_or_str, method = nil)
|
18
37
|
self.new.process(ParseTree.translate(klass_or_str, method))
|
19
38
|
end
|
@@ -24,10 +43,17 @@ class RubyToRuby < SexpProcessor
|
|
24
43
|
self.auto_shift_type = true
|
25
44
|
self.strict = true
|
26
45
|
self.expected = String
|
46
|
+
|
47
|
+
# self.debug[:defn] = /zsuper/
|
48
|
+
end
|
49
|
+
|
50
|
+
def process exp
|
51
|
+
exp = Sexp.from_array(exp) if Array === exp unless Sexp === exp
|
52
|
+
super exp
|
27
53
|
end
|
28
54
|
|
29
55
|
############################################################
|
30
|
-
# Processors
|
56
|
+
# Processors
|
31
57
|
|
32
58
|
def process_alias(exp)
|
33
59
|
"alias_method #{process(exp.shift)}, #{process(exp.shift)}"
|
@@ -120,7 +146,7 @@ class RubyToRuby < SexpProcessor
|
|
120
146
|
def process_attrasgn(exp)
|
121
147
|
receiver = process exp.shift
|
122
148
|
name = exp.shift
|
123
|
-
args = exp.shift
|
149
|
+
args = exp.empty? ? nil : exp.shift
|
124
150
|
|
125
151
|
case name
|
126
152
|
when :[]= then
|
@@ -165,7 +191,16 @@ class RubyToRuby < SexpProcessor
|
|
165
191
|
end
|
166
192
|
end
|
167
193
|
|
168
|
-
|
194
|
+
result = result.join "\n"
|
195
|
+
|
196
|
+
result = case self.context[1]
|
197
|
+
when nil, :scope, :if, :iter, :resbody, :when, :while then
|
198
|
+
result + "\n"
|
199
|
+
else
|
200
|
+
"(#{result})"
|
201
|
+
end
|
202
|
+
|
203
|
+
return result
|
169
204
|
end
|
170
205
|
|
171
206
|
def process_block_arg(exp)
|
@@ -195,18 +230,29 @@ class RubyToRuby < SexpProcessor
|
|
195
230
|
end
|
196
231
|
|
197
232
|
def process_break(exp)
|
198
|
-
val = process(exp.shift)
|
199
|
-
"break" + (val ? " #{val}" : "")
|
233
|
+
val = exp.empty? ? nil : process(exp.shift)
|
234
|
+
# HACK "break" + (val ? " #{val}" : "")
|
235
|
+
if val then
|
236
|
+
"break #{val}"
|
237
|
+
else
|
238
|
+
"break"
|
239
|
+
end
|
200
240
|
end
|
201
241
|
|
202
242
|
def process_call(exp)
|
243
|
+
receiver_node_type = exp.first.first
|
203
244
|
receiver = process exp.shift
|
245
|
+
|
246
|
+
receiver = "(#{receiver})" if
|
247
|
+
RubyToRuby::ASSIGN_NODES.include? receiver_node_type
|
248
|
+
|
204
249
|
name = exp.shift
|
205
250
|
args_exp = exp.shift rescue nil
|
206
|
-
if args_exp && args_exp.first == :array
|
251
|
+
if args_exp && args_exp.first == :array # FIX
|
207
252
|
args = "#{process(args_exp)[1..-2]}"
|
208
253
|
else
|
209
254
|
args = process args_exp
|
255
|
+
args = nil if args.empty?
|
210
256
|
end
|
211
257
|
|
212
258
|
case name
|
@@ -287,7 +333,7 @@ class RubyToRuby < SexpProcessor
|
|
287
333
|
|
288
334
|
def process_dasgn_curr(exp)
|
289
335
|
lhs = exp.shift.to_s
|
290
|
-
rhs = exp.shift
|
336
|
+
rhs = exp.shift rescue nil
|
291
337
|
return lhs if rhs.nil?
|
292
338
|
return "#{lhs} = #{process rhs}" unless rhs.first == :dasgn_curr
|
293
339
|
|
@@ -309,16 +355,19 @@ class RubyToRuby < SexpProcessor
|
|
309
355
|
end
|
310
356
|
|
311
357
|
def process_defs(exp)
|
358
|
+
receiver = process(exp.shift)
|
359
|
+
name = exp.shift
|
360
|
+
exp.unshift "#{receiver}.#{name}"
|
312
361
|
process_defn(exp)
|
313
362
|
end
|
314
363
|
|
315
364
|
def process_defn(exp)
|
316
|
-
|
317
|
-
|
365
|
+
type1 = exp[1].first
|
366
|
+
type2 = exp[2].first rescue nil
|
318
367
|
|
319
|
-
if
|
368
|
+
if type1 == :args and [:ivar, :attrset].include? type2 then
|
320
369
|
name = exp.shift
|
321
|
-
case
|
370
|
+
case type2
|
322
371
|
when :ivar then
|
323
372
|
exp.clear
|
324
373
|
return "attr_reader #{name.inspect}"
|
@@ -330,7 +379,7 @@ class RubyToRuby < SexpProcessor
|
|
330
379
|
end
|
331
380
|
end
|
332
381
|
|
333
|
-
case
|
382
|
+
case type1
|
334
383
|
when :cfunc then
|
335
384
|
s = "# method '#{exp.shift}' defined in a C function"
|
336
385
|
exp.shift
|
@@ -348,7 +397,7 @@ class RubyToRuby < SexpProcessor
|
|
348
397
|
body = process(exp.shift)
|
349
398
|
raise "no"
|
350
399
|
else
|
351
|
-
raise "Unknown defn type: #{
|
400
|
+
raise "Unknown defn type: #{type1} for #{exp.inspect}"
|
352
401
|
end
|
353
402
|
end
|
354
403
|
|
@@ -420,8 +469,9 @@ class RubyToRuby < SexpProcessor
|
|
420
469
|
"false"
|
421
470
|
end
|
422
471
|
|
472
|
+
# TODO: remove for unified
|
423
473
|
def process_fcall(exp)
|
424
|
-
|
474
|
+
recv = exp.shift unless Symbol === exp.first # HACK conditional - some not getting rewritten?
|
425
475
|
name = exp.shift.to_s
|
426
476
|
args = exp.shift
|
427
477
|
code = []
|
@@ -429,7 +479,7 @@ class RubyToRuby < SexpProcessor
|
|
429
479
|
args[0] = :arglist if args.first == :array
|
430
480
|
code << process(args)
|
431
481
|
end
|
432
|
-
return "#{name}(#{code.join(', ')})"
|
482
|
+
return code.empty? ? name : "#{name}(#{code.join(', ')})"
|
433
483
|
end
|
434
484
|
|
435
485
|
def process_flip2(exp)
|
@@ -477,22 +527,34 @@ class RubyToRuby < SexpProcessor
|
|
477
527
|
end
|
478
528
|
|
479
529
|
def process_if(exp)
|
480
|
-
|
481
|
-
|
482
|
-
|
530
|
+
expand = RubyToRuby::ASSIGN_NODES.include? exp.first.first
|
531
|
+
c = process exp.shift
|
532
|
+
t = process exp.shift
|
533
|
+
f = process exp.shift
|
534
|
+
|
535
|
+
c = "(#{c.chomp})" if c =~ /\n/
|
483
536
|
|
484
537
|
if t then
|
485
|
-
unless
|
486
|
-
|
487
|
-
|
538
|
+
unless expand then
|
539
|
+
if f then
|
540
|
+
r = "#{c} ? (#{t}) : (#{f})"
|
541
|
+
r = nil if r =~ /return/ # HACK - need contextual awareness or something
|
542
|
+
else
|
543
|
+
r = "#{t} if #{c}"
|
544
|
+
end
|
545
|
+
return r if r and (@indent+r).size < LINE_LENGTH and r !~ /\n/
|
488
546
|
end
|
547
|
+
|
489
548
|
r = "if #{c} then\n#{indent(t)}\n"
|
490
549
|
r << "else\n#{indent(f)}\n" if f
|
491
550
|
r << "end"
|
551
|
+
|
492
552
|
r
|
493
553
|
else
|
494
|
-
|
495
|
-
|
554
|
+
unless expand then
|
555
|
+
r = "#{f} unless #{c}"
|
556
|
+
return r if (@indent+r).size < LINE_LENGTH and r !~ /\n/
|
557
|
+
end
|
496
558
|
"unless #{c} then\n#{indent(f)}\nend"
|
497
559
|
end
|
498
560
|
end
|
@@ -500,7 +562,7 @@ class RubyToRuby < SexpProcessor
|
|
500
562
|
def process_iter(exp)
|
501
563
|
iter = process exp.shift
|
502
564
|
args = process exp.shift
|
503
|
-
body = process
|
565
|
+
body = exp.empty? ? nil : process(exp.shift)
|
504
566
|
|
505
567
|
b, e = if iter == "END" then
|
506
568
|
[ "{", "}" ]
|
@@ -578,7 +640,14 @@ class RubyToRuby < SexpProcessor
|
|
578
640
|
case lhs.first
|
579
641
|
when :array then
|
580
642
|
lhs.shift
|
581
|
-
lhs = lhs.map
|
643
|
+
lhs = lhs.map do |l|
|
644
|
+
case l.first
|
645
|
+
when :masgn then
|
646
|
+
"(#{process(l)})"
|
647
|
+
else
|
648
|
+
process(l)
|
649
|
+
end
|
650
|
+
end
|
582
651
|
when :dasgn_curr then
|
583
652
|
lhs = [ splat(lhs.last) ]
|
584
653
|
else
|
@@ -587,8 +656,11 @@ class RubyToRuby < SexpProcessor
|
|
587
656
|
|
588
657
|
unless rhs.nil? then
|
589
658
|
# HACK - but seems to work (see to_ary test) assert_type rhs, :array
|
590
|
-
rhs.shift
|
591
|
-
|
659
|
+
rhs = if rhs.shift == :argscat then
|
660
|
+
[process_argscat(rhs)]
|
661
|
+
else
|
662
|
+
rhs.map { |r| process(r) }
|
663
|
+
end
|
592
664
|
return "#{lhs.join(", ")} = #{rhs.join(", ")}"
|
593
665
|
else
|
594
666
|
return lhs.join(", ")
|
@@ -687,18 +759,19 @@ class RubyToRuby < SexpProcessor
|
|
687
759
|
list = sexp.shift
|
688
760
|
body = sexp.shift
|
689
761
|
|
690
|
-
var = if list and list.last.first == :lasgn then
|
762
|
+
var = if list and list.size > 1 and list.last.first == :lasgn then
|
691
763
|
list.pop[1]
|
692
764
|
else
|
693
765
|
nil
|
694
766
|
end
|
695
767
|
|
696
|
-
if list then
|
768
|
+
if list and list.size > 1 then
|
697
769
|
list[0] = :arglist
|
698
770
|
code << "rescue #{process(list)}"
|
699
771
|
else
|
700
772
|
code << "rescue"
|
701
773
|
end
|
774
|
+
|
702
775
|
code.last << " => #{var}" if var
|
703
776
|
|
704
777
|
if body then
|
@@ -707,8 +780,8 @@ class RubyToRuby < SexpProcessor
|
|
707
780
|
code << indent("# do nothing")
|
708
781
|
end
|
709
782
|
|
710
|
-
|
711
|
-
|
783
|
+
unless exp.empty? then
|
784
|
+
sexp = exp.shift
|
712
785
|
assert_type sexp, :resbody
|
713
786
|
sexp.shift
|
714
787
|
end
|
@@ -719,17 +792,16 @@ class RubyToRuby < SexpProcessor
|
|
719
792
|
|
720
793
|
def process_rescue(exp)
|
721
794
|
# TODO: rewrite this
|
722
|
-
# TODO: proper formatting depends on knowing the context
|
723
795
|
#
|
724
796
|
# a = b rescue c => [lasgn a [rescue b c]]
|
725
797
|
# begin; a = b; rescue c => [begin [rescue [lasgn a b] c]]
|
726
|
-
stack = caller.map { |s| s[/process_\w+/] }.compact
|
727
798
|
|
728
|
-
|
729
|
-
|
799
|
+
current = self.context[1]
|
800
|
+
case current
|
801
|
+
when :begin, :ensure, :block then
|
730
802
|
body = process exp.shift
|
731
|
-
resbody = process
|
732
|
-
els = process
|
803
|
+
resbody = exp.empty? ? nil : process(exp.shift)
|
804
|
+
els = exp.empty? ? nil : process(exp.shift)
|
733
805
|
|
734
806
|
code = []
|
735
807
|
code << indent(body)
|
@@ -738,8 +810,7 @@ class RubyToRuby < SexpProcessor
|
|
738
810
|
code << "else"
|
739
811
|
code << indent(els)
|
740
812
|
else
|
741
|
-
unless
|
742
|
-
stack.first == "process_ensure" then
|
813
|
+
unless [:block, :ensure].include? current then
|
743
814
|
code << "end\n"
|
744
815
|
else
|
745
816
|
r = [body, resbody.gsub(/rescue\n\s+/, 'rescue ')].join(' ')
|
@@ -756,7 +827,13 @@ class RubyToRuby < SexpProcessor
|
|
756
827
|
resbody = resbody.shift # actual code
|
757
828
|
|
758
829
|
resbody = process resbody
|
759
|
-
"#{body} rescue #{resbody}"
|
830
|
+
code = "#{body} rescue #{resbody}"
|
831
|
+
case current
|
832
|
+
when :hash then # HACK move to process_hash
|
833
|
+
"(#{code})"
|
834
|
+
else
|
835
|
+
code
|
836
|
+
end
|
760
837
|
end
|
761
838
|
end
|
762
839
|
|
@@ -765,7 +842,13 @@ class RubyToRuby < SexpProcessor
|
|
765
842
|
end
|
766
843
|
|
767
844
|
def process_return(exp)
|
768
|
-
return "return" + (exp.empty? ? "" : " #{process exp.shift}")
|
845
|
+
# HACK return "return" + (exp.empty? ? "" : " #{process exp.shift}")
|
846
|
+
|
847
|
+
if exp.empty? then
|
848
|
+
return "return"
|
849
|
+
else
|
850
|
+
return "return #{process exp.shift}"
|
851
|
+
end
|
769
852
|
end
|
770
853
|
|
771
854
|
def process_sclass(exp)
|
@@ -773,7 +856,7 @@ class RubyToRuby < SexpProcessor
|
|
773
856
|
end
|
774
857
|
|
775
858
|
def process_scope(exp)
|
776
|
-
|
859
|
+
exp.empty? ? "" : process(exp.shift)
|
777
860
|
end
|
778
861
|
|
779
862
|
def process_self(exp)
|
@@ -818,9 +901,12 @@ class RubyToRuby < SexpProcessor
|
|
818
901
|
"alias #{exp.shift} #{exp.shift}"
|
819
902
|
end
|
820
903
|
|
821
|
-
|
822
|
-
|
823
|
-
|
904
|
+
# def process_vcall(exp)
|
905
|
+
# recv = exp.shift # nil
|
906
|
+
# name = exp.shift
|
907
|
+
# args = exp.shift # nil
|
908
|
+
# return name.to_s
|
909
|
+
# end
|
824
910
|
|
825
911
|
def process_when(exp)
|
826
912
|
src = []
|
@@ -843,13 +929,18 @@ class RubyToRuby < SexpProcessor
|
|
843
929
|
end
|
844
930
|
|
845
931
|
def process_yield(exp)
|
846
|
-
args = exp.shift
|
932
|
+
args = exp.empty? ? nil : exp.shift
|
847
933
|
if args then
|
848
934
|
args[0] = :arglist if args.first == :array
|
849
935
|
args = process(args)
|
850
936
|
end
|
851
937
|
|
852
|
-
"yield" + (args ? "(#{args})" : "")
|
938
|
+
# "yield" + (args ? "(#{args})" : "")
|
939
|
+
if args then
|
940
|
+
"yield(#{args})"
|
941
|
+
else
|
942
|
+
"yield"
|
943
|
+
end
|
853
944
|
end
|
854
945
|
|
855
946
|
def process_zarray(exp)
|
@@ -883,135 +974,10 @@ class RubyToRuby < SexpProcessor
|
|
883
974
|
############################################################
|
884
975
|
# Rewriters
|
885
976
|
|
886
|
-
##
|
887
|
-
# defn: [:defn, :name, [:args...], [:scope, [:block, ...]]]
|
888
|
-
|
889
977
|
def rewrite_defs(exp)
|
890
|
-
|
891
|
-
|
892
|
-
|
893
|
-
end
|
894
|
-
|
895
|
-
# s(:defn, :name, s(:scope, s(:block, s(:args, ...), ...)))
|
896
|
-
# s(:defn, :name, s(:bmethod, s(:masgn, s(:dasgn_curr, :args)), s(:block, ...)))
|
897
|
-
# s(:defn, :name, s(:fbody, s(:bmethod, s(:masgn, s(:dasgn_curr, :params)), s(:block, ...))))
|
898
|
-
# =>
|
899
|
-
# s(:defn, :name, s(:args, ...), s(:scope, s:(block, ...)))
|
900
|
-
|
901
|
-
def rewrite_defn(exp)
|
902
|
-
# REFACTOR this needs help now
|
903
|
-
exp.shift # :defn
|
904
|
-
name = exp.shift
|
905
|
-
args = s(:args)
|
906
|
-
body = Sexp.from_array exp.shift
|
907
|
-
|
908
|
-
case body.first
|
909
|
-
when :args then # already normalized
|
910
|
-
args = body
|
911
|
-
body = exp.shift
|
912
|
-
assert_type args, :args
|
913
|
-
assert_type body, :scope
|
914
|
-
assert_type body[1], :block
|
915
|
-
when :scope, :fbody then
|
916
|
-
body = body.pop if body.first == :fbody
|
917
|
-
case body.first
|
918
|
-
when :scope then
|
919
|
-
args = body.block.args(true)
|
920
|
-
assert_type body, :scope
|
921
|
-
assert_type body[1], :block
|
922
|
-
|
923
|
-
if body[1][1].first == :block_arg then
|
924
|
-
block_arg = body[1].delete_at 1
|
925
|
-
args << block_arg
|
926
|
-
end
|
927
|
-
when :bmethod then
|
928
|
-
body[0] = :scope
|
929
|
-
masgn = body.masgn(true)
|
930
|
-
if masgn then
|
931
|
-
splat = self.splat(masgn[-1][-1])
|
932
|
-
args.push(splat)
|
933
|
-
else
|
934
|
-
dasgn_curr = body.dasgn_curr(true)
|
935
|
-
if dasgn_curr then
|
936
|
-
arg = self.splat(dasgn_curr[-1])
|
937
|
-
args.push(arg)
|
938
|
-
end
|
939
|
-
end
|
940
|
-
body.find_and_replace_all(:dvar, :lvar)
|
941
|
-
else
|
942
|
-
raise "no: #{body.first} / #{body.inspect}"
|
943
|
-
end
|
944
|
-
when :bmethod then
|
945
|
-
body.shift # :bmethod
|
946
|
-
case body.first.first
|
947
|
-
when :dasgn_curr then
|
948
|
-
# WARN: there are some implications here of having an empty
|
949
|
-
# :args below namely, "proc { || " does not allow extra args
|
950
|
-
# passed in.
|
951
|
-
dasgn = body.shift
|
952
|
-
assert_type dasgn, :dasgn_curr
|
953
|
-
dasgn.shift # type
|
954
|
-
args.push(*dasgn)
|
955
|
-
body.find_and_replace_all(:dvar, :lvar)
|
956
|
-
when :masgn then
|
957
|
-
dasgn = body.masgn(true)
|
958
|
-
splat = self.splat(dasgn[-1][-1])
|
959
|
-
args.push(splat)
|
960
|
-
body.find_and_replace_all(:dvar, :lvar)
|
961
|
-
end
|
962
|
-
|
963
|
-
if body.first.first == :block then
|
964
|
-
body = s(:scope, body.shift)
|
965
|
-
else
|
966
|
-
body = s(:scope, s(:block, body.shift)) # single statement
|
967
|
-
end
|
968
|
-
when :dmethod
|
969
|
-
# BEFORE: [:defn, :dmethod_added, [:dmethod, :bmethod_maker, ...]]
|
970
|
-
# AFTER: [:defn, :dmethod_added, ...]
|
971
|
-
body[0] = :scope
|
972
|
-
body.delete_at 1 # method name
|
973
|
-
args = body.scope.block.args(true)
|
974
|
-
when :ivar, :attrset then
|
975
|
-
# do nothing
|
976
|
-
else
|
977
|
-
raise "Unknown :defn format: #{name.inspect} #{args.inspect} #{body.inspect}"
|
978
|
-
end
|
979
|
-
|
980
|
-
return s(:defn, name, args, body)
|
981
|
-
end
|
982
|
-
|
983
|
-
def rewrite_resbody(exp)
|
984
|
-
result = []
|
985
|
-
|
986
|
-
code = result
|
987
|
-
while exp and exp.first == :resbody do
|
988
|
-
code << exp.shift
|
989
|
-
list = exp.shift
|
990
|
-
body = exp.shift
|
991
|
-
exp = exp.shift # either another resbody or nil
|
992
|
-
|
993
|
-
# code may be nil, :lasgn, or :block
|
994
|
-
case body.first
|
995
|
-
when nil then
|
996
|
-
# do nothing
|
997
|
-
when :lasgn then
|
998
|
-
# TODO: check that it is assigning $!
|
999
|
-
list << body
|
1000
|
-
body = nil
|
1001
|
-
when :block then
|
1002
|
-
# TODO: check that it is assigning $!
|
1003
|
-
list << body.delete_at(1) if body[1].first == :lasgn
|
1004
|
-
else
|
1005
|
-
# do nothing (expression form)
|
1006
|
-
end
|
1007
|
-
|
1008
|
-
code << list << body
|
1009
|
-
if exp then
|
1010
|
-
code = []
|
1011
|
-
result << code
|
1012
|
-
end
|
1013
|
-
end
|
1014
|
-
|
978
|
+
receiver = exp.shift
|
979
|
+
result = rewrite_defn(exp)
|
980
|
+
result.unshift receiver
|
1015
981
|
result
|
1016
982
|
end
|
1017
983
|
|
data/test/test_ruby2ruby.rb
CHANGED
@@ -1,15 +1,24 @@
|
|
1
1
|
#!/usr/local/bin/ruby -w
|
2
2
|
|
3
|
+
$TESTING = true
|
4
|
+
|
3
5
|
require 'test/unit'
|
4
6
|
begin require 'rubygems'; rescue LoadError; end
|
5
7
|
require 'ruby2ruby'
|
6
8
|
require 'pt_testcase'
|
7
9
|
|
10
|
+
# TODO: rename file so autotest stops bitching
|
11
|
+
|
8
12
|
class TestRubyToRuby < Test::Unit::TestCase
|
9
13
|
def setup
|
10
14
|
@processor = RubyToRuby.new
|
11
15
|
end
|
12
16
|
|
17
|
+
def test_proc_to_ruby
|
18
|
+
block = proc { puts "something" }
|
19
|
+
assert_equal %Q|proc {\n puts("something")\n}|, block.to_ruby
|
20
|
+
end
|
21
|
+
|
13
22
|
def test_lit_regexp_slash
|
14
23
|
inn = s(:lit, /blah\/blah/)
|
15
24
|
out = '/blah\/blah/'
|
@@ -57,75 +66,9 @@ class TestRubyToRuby < Test::Unit::TestCase
|
|
57
66
|
assert_equal :"blah2blah\"blah/blah", r
|
58
67
|
end
|
59
68
|
|
60
|
-
def test_rewrite_defn_define_method
|
61
|
-
inn = s(:defn, :splatted,
|
62
|
-
s(:bmethod,
|
63
|
-
s(:masgn, s(:dasgn_curr, :args)),
|
64
|
-
s(:block,
|
65
|
-
s(:dasgn_curr, :y, s(:call, s(:dvar, :args), :first)),
|
66
|
-
s(:call, s(:dvar, :y), :+, s(:array, s(:lit, 42))))))
|
67
|
-
out = s(:defn, :splatted,
|
68
|
-
s(:args, :"*args"),
|
69
|
-
s(:scope,
|
70
|
-
s(:block,
|
71
|
-
s(:dasgn_curr, :y, s(:call, s(:lvar, :args), :first)),
|
72
|
-
s(:call, s(:lvar, :y), :+, s(:array, s(:lit, 42))))))
|
73
|
-
|
74
|
-
assert_equal out, @processor.rewrite_defn(inn)
|
75
|
-
end
|
76
|
-
|
77
|
-
def test_rewrite_defn_bmethod
|
78
|
-
inn = s(:defn, :group,
|
79
|
-
s(:fbody,
|
80
|
-
s(:bmethod,
|
81
|
-
s(:masgn, s(:dasgn_curr, :params)),
|
82
|
-
s(:block,
|
83
|
-
s(:lit, 42)))))
|
84
|
-
out = s(:defn, :group,
|
85
|
-
s(:args, :"*params"),
|
86
|
-
s(:scope,
|
87
|
-
s(:block, s(:lit, 42))))
|
88
|
-
|
89
|
-
assert_equal out, @processor.rewrite_defn(inn)
|
90
|
-
end
|
91
|
-
|
92
|
-
def test_rewrite_resbody
|
93
|
-
inn = [:resbody,
|
94
|
-
[:array, [:const, :SyntaxError]],
|
95
|
-
[:block, [:lasgn, :e1, [:gvar, :$!]], [:lit, 2]],
|
96
|
-
[:resbody,
|
97
|
-
[:array, [:const, :Exception]],
|
98
|
-
[:block, [:lasgn, :e2, [:gvar, :$!]], [:lit, 3]]]]
|
99
|
-
|
100
|
-
out = [:resbody,
|
101
|
-
[:array, [:const, :SyntaxError], [:lasgn, :e1, [:gvar, :$!]]],
|
102
|
-
[:block, [:lit, 2]],
|
103
|
-
[:resbody,
|
104
|
-
[:array, [:const, :Exception], [:lasgn, :e2, [:gvar, :$!]]],
|
105
|
-
[:block, [:lit, 3]]]]
|
106
|
-
|
107
|
-
assert_equal out, @processor.rewrite_resbody(inn)
|
108
|
-
end
|
109
|
-
|
110
|
-
def test_rewrite_resbody_lasgn
|
111
|
-
inn = [:resbody,
|
112
|
-
[:array, [:const, :SyntaxError]],
|
113
|
-
[:lasgn, :e1, [:gvar, :$!]],
|
114
|
-
[:resbody,
|
115
|
-
[:array, [:const, :Exception]],
|
116
|
-
[:block, [:lasgn, :e2, [:gvar, :$!]], [:lit, 3]]]]
|
117
|
-
|
118
|
-
out = [:resbody,
|
119
|
-
[:array, [:const, :SyntaxError], [:lasgn, :e1, [:gvar, :$!]]],
|
120
|
-
nil,
|
121
|
-
[:resbody,
|
122
|
-
[:array, [:const, :Exception], [:lasgn, :e2, [:gvar, :$!]]],
|
123
|
-
[:block, [:lit, 3]]]]
|
124
|
-
|
125
|
-
assert_equal out, @processor.rewrite_resbody(inn)
|
126
|
-
end
|
127
|
-
|
128
69
|
eval ParseTreeTestCase.testcases.map { |node, data|
|
70
|
+
next if node == "vcall" # HACK
|
71
|
+
|
129
72
|
"def test_#{node}
|
130
73
|
pt = #{data['ParseTree'].inspect}
|
131
74
|
rb = #{(data['Ruby2Ruby'] || data['Ruby']).inspect}
|
@@ -138,24 +81,63 @@ class TestRubyToRuby < Test::Unit::TestCase
|
|
138
81
|
}.join("\n")
|
139
82
|
end
|
140
83
|
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
84
|
+
##
|
85
|
+
# Converts a +target+ using a +processor+ and converts +target+ name
|
86
|
+
# in the source adding +gen+ to allow easy renaming.
|
87
|
+
|
88
|
+
def morph_and_eval(processor, target, gen)
|
89
|
+
begin
|
90
|
+
old_name = target.name
|
91
|
+
new_name = target.name.sub(/\d*$/, gen.to_s)
|
92
|
+
ruby = processor.translate(target).sub(old_name, new_name)
|
93
|
+
eval ruby
|
94
|
+
target.constants.each do |constant|
|
95
|
+
eval "#{new_name}::#{constant} = #{old_name}::#{constant}"
|
96
|
+
end
|
97
|
+
rescue SyntaxError => e
|
98
|
+
puts
|
99
|
+
puts ruby
|
100
|
+
puts
|
101
|
+
raise e
|
102
|
+
rescue => e
|
103
|
+
puts
|
104
|
+
puts ruby
|
105
|
+
puts
|
106
|
+
raise e
|
107
|
+
end
|
150
108
|
end
|
151
109
|
|
152
|
-
|
110
|
+
####################
|
111
|
+
# impl
|
112
|
+
# old new
|
113
|
+
#
|
114
|
+
# t old 0 1
|
115
|
+
# e
|
116
|
+
# s
|
117
|
+
# t new 2 3
|
118
|
+
|
119
|
+
# Self-Translation: 1st Generation - morph RubyToRuby using RubyToRuby
|
120
|
+
morph_and_eval RubyToRuby, RubyToRuby, 2
|
121
|
+
class TestRubyToRuby1 < TestRubyToRuby
|
122
|
+
def setup
|
123
|
+
@processor = RubyToRuby2.new
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
# Self-Translation: 2nd Generation - morph TestRubyToRuby using RubyToRuby
|
128
|
+
morph_and_eval RubyToRuby, TestRubyToRuby, 2
|
153
129
|
|
154
|
-
|
130
|
+
# Self-Translation: 3rd Generation - test RubyToRuby2 with TestRubyToRuby1
|
131
|
+
class TestRubyToRuby3 < TestRubyToRuby2
|
155
132
|
def setup
|
156
133
|
@processor = RubyToRuby2.new
|
157
134
|
end
|
158
135
|
end
|
159
136
|
|
160
|
-
# Self-Translation:
|
161
|
-
|
137
|
+
# Self-Translation: 4th (and final) Generation - fully circular
|
138
|
+
morph_and_eval RubyToRuby2, RubyToRuby2, 3
|
139
|
+
class TestRubyToRuby4 < TestRubyToRuby3
|
140
|
+
def setup
|
141
|
+
@processor = RubyToRuby3.new
|
142
|
+
end
|
143
|
+
end
|
metadata
CHANGED
@@ -3,8 +3,8 @@ rubygems_version: 0.9.4
|
|
3
3
|
specification_version: 1
|
4
4
|
name: ruby2ruby
|
5
5
|
version: !ruby/object:Gem::Version
|
6
|
-
version: 1.1.
|
7
|
-
date: 2007-
|
6
|
+
version: 1.1.7
|
7
|
+
date: 2007-08-21 00:00:00 -07:00
|
8
8
|
summary: ruby2ruby provides a means of generating pure ruby code easily from ParseTree's Sexps.
|
9
9
|
require_paths:
|
10
10
|
- lib
|
@@ -33,6 +33,7 @@ files:
|
|
33
33
|
- Manifest.txt
|
34
34
|
- README.txt
|
35
35
|
- Rakefile
|
36
|
+
- bin/r2r_show
|
36
37
|
- lib/ruby2ruby.rb
|
37
38
|
- test/test_ruby2ruby.rb
|
38
39
|
test_files:
|
@@ -44,8 +45,8 @@ extra_rdoc_files:
|
|
44
45
|
- History.txt
|
45
46
|
- Manifest.txt
|
46
47
|
- README.txt
|
47
|
-
executables:
|
48
|
-
|
48
|
+
executables:
|
49
|
+
- r2r_show
|
49
50
|
extensions: []
|
50
51
|
|
51
52
|
requirements: []
|
@@ -67,5 +68,5 @@ dependencies:
|
|
67
68
|
requirements:
|
68
69
|
- - ">="
|
69
70
|
- !ruby/object:Gem::Version
|
70
|
-
version: 1.
|
71
|
+
version: 1.3.0
|
71
72
|
version:
|