ruby2ruby 1.1.9 → 1.2.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.autotest +8 -2
- data/History.txt +7 -0
- data/Rakefile +24 -9
- data/lib/ruby2ruby.rb +146 -321
- data/test/test_ruby2ruby.rb +48 -55
- metadata +8 -6
data/.autotest
CHANGED
@@ -1,15 +1,21 @@
|
|
1
1
|
# -*- ruby -*-
|
2
2
|
|
3
|
+
require 'autotest/restart'
|
4
|
+
|
3
5
|
Autotest.add_hook :initialize do |at|
|
4
6
|
at.extra_files << "../../ParseTree/dev/test/pt_testcase.rb"
|
5
7
|
at.extra_files << "../../ParseTree/dev/lib/unified_ruby.rb"
|
6
|
-
at.libs << ":../../ParseTree/dev/lib:../../ParseTree/dev/test"
|
8
|
+
at.libs << ":../../sexp_processor/dev/lib:../../ParseTree/dev/lib:../../ParseTree/dev/test"
|
7
9
|
|
8
10
|
(1..4).each do |n|
|
9
11
|
at.extra_class_map["TestRuby2Ruby#{n}"] = "test/test_ruby2ruby.rb"
|
10
12
|
end
|
11
13
|
|
12
14
|
at.add_mapping(/unified|pt_testcase/) do |f, _|
|
13
|
-
at.files_matching(
|
15
|
+
at.files_matching(/test.*rb$/)
|
14
16
|
end
|
15
17
|
end
|
18
|
+
|
19
|
+
require 'autotest/rcov'
|
20
|
+
Autotest::RCov.command = 'rcov_info'
|
21
|
+
Autotest::RCov.pattern = 'test/test_ruby2ruby.rb'
|
data/History.txt
CHANGED
@@ -1,3 +1,10 @@
|
|
1
|
+
=== 1.2.0 / 2008-10-22
|
2
|
+
|
3
|
+
* 2 minor enhancements:
|
4
|
+
|
5
|
+
* Removed all PT dependent code to PT project (see parse_tree_extensions.rb).
|
6
|
+
* Revamped. Got working with new unified ruby output. Much much cleaner.
|
7
|
+
|
1
8
|
=== 1.1.9 / 2008-06-09
|
2
9
|
|
3
10
|
* 5 minor enhancements:
|
data/Rakefile
CHANGED
@@ -1,24 +1,39 @@
|
|
1
1
|
# -*- ruby -*-
|
2
2
|
|
3
|
-
dirs = (%w(lib ../../ParseTree/dev/test) +
|
4
|
-
%w(ParseTree RubyInline ruby_parser).map { |p| "../../#{p}/dev/lib" })
|
5
|
-
$:.push(*dirs)
|
6
|
-
ENV['RUBY_FLAGS'] = "-I" + dirs.join(":")
|
7
|
-
|
8
3
|
require 'rubygems'
|
9
4
|
require 'hoe'
|
5
|
+
|
6
|
+
Hoe.add_include_dirs("lib",
|
7
|
+
"../../ZenTest/dev/lib",
|
8
|
+
"../../ParseTree/dev/test",
|
9
|
+
"../../ParseTree/dev/lib",
|
10
|
+
"../../RubyInline/dev/lib",
|
11
|
+
"../../ruby_parser/dev/lib",
|
12
|
+
"../../sexp_processor/dev/lib")
|
13
|
+
|
10
14
|
require './lib/ruby2ruby.rb'
|
11
15
|
|
12
|
-
Hoe.new('ruby2ruby',
|
16
|
+
Hoe.new('ruby2ruby', Ruby2Ruby::VERSION) do |r2r|
|
13
17
|
r2r.rubyforge_name = 'seattlerb'
|
14
18
|
r2r.developer('Ryan Davis', 'ryand-ruby@zenspider.com')
|
15
19
|
|
16
20
|
r2r.clean_globs << File.expand_path("~/.ruby_inline")
|
17
|
-
r2r.extra_deps << "ParseTree"
|
18
|
-
|
19
|
-
r2r.multiruby_skip << "rubinius"
|
21
|
+
r2r.extra_deps << ["ParseTree", "~> 3.0"]
|
20
22
|
end
|
21
23
|
|
22
24
|
task :test => :clean
|
23
25
|
|
26
|
+
task :rcov_info do
|
27
|
+
pat = ENV['PATTERN'] || "test/test_*.rb"
|
28
|
+
ruby "#{Hoe::RUBY_FLAGS} -S rcov --text-report --save coverage.info #{pat}"
|
29
|
+
end
|
30
|
+
|
31
|
+
task :rcov_overlay do
|
32
|
+
rcov, eol = Marshal.load(File.read("coverage.info")).last[ENV["FILE"]], 1
|
33
|
+
puts rcov[:lines].zip(rcov[:coverage]).map { |line, coverage|
|
34
|
+
bol, eol = eol, eol + line.length
|
35
|
+
[bol, eol, "#ffcccc"] unless coverage
|
36
|
+
}.compact.inspect
|
37
|
+
end
|
38
|
+
|
24
39
|
# vim: syntax=Ruby
|
data/lib/ruby2ruby.rb
CHANGED
@@ -5,9 +5,7 @@ require 'sexp_processor'
|
|
5
5
|
require 'unified_ruby'
|
6
6
|
|
7
7
|
class Ruby2Ruby < SexpProcessor
|
8
|
-
|
9
|
-
|
10
|
-
VERSION = '1.1.9'
|
8
|
+
VERSION = '1.2.0'
|
11
9
|
LINE_LENGTH = 78
|
12
10
|
|
13
11
|
##
|
@@ -19,6 +17,7 @@ class Ruby2Ruby < SexpProcessor
|
|
19
17
|
:flip3,
|
20
18
|
:lasgn,
|
21
19
|
:masgn,
|
20
|
+
:attrasgn,
|
22
21
|
:op_asgn1,
|
23
22
|
:op_asgn2,
|
24
23
|
:op_asgn_and,
|
@@ -28,7 +27,9 @@ class Ruby2Ruby < SexpProcessor
|
|
28
27
|
|
29
28
|
def self.translate(klass_or_str, method = nil)
|
30
29
|
require 'parse_tree'
|
31
|
-
|
30
|
+
sexp = ParseTree.translate(klass_or_str, method)
|
31
|
+
sexp = Unifier.new.process(sexp)
|
32
|
+
self.new.process(sexp)
|
32
33
|
end
|
33
34
|
|
34
35
|
def initialize
|
@@ -41,11 +42,6 @@ class Ruby2Ruby < SexpProcessor
|
|
41
42
|
# self.debug[:defn] = /zsuper/
|
42
43
|
end
|
43
44
|
|
44
|
-
def process exp
|
45
|
-
exp = Sexp.from_array(exp) if Array === exp unless Sexp === exp
|
46
|
-
super exp
|
47
|
-
end
|
48
|
-
|
49
45
|
############################################################
|
50
46
|
# Processors
|
51
47
|
|
@@ -57,6 +53,14 @@ class Ruby2Ruby < SexpProcessor
|
|
57
53
|
"(#{process exp.shift} and #{process exp.shift})"
|
58
54
|
end
|
59
55
|
|
56
|
+
def process_arglist(exp) # custom made node
|
57
|
+
code = []
|
58
|
+
until exp.empty? do
|
59
|
+
code << process(exp.shift)
|
60
|
+
end
|
61
|
+
code.join ', '
|
62
|
+
end
|
63
|
+
|
60
64
|
def process_args(exp)
|
61
65
|
args = []
|
62
66
|
|
@@ -76,8 +80,6 @@ class Ruby2Ruby < SexpProcessor
|
|
76
80
|
args.each_with_index do |name, index|
|
77
81
|
args[index] = asgns[name] if asgns.has_key? name
|
78
82
|
end
|
79
|
-
when :block_arg then
|
80
|
-
args << "&#{arg.last}"
|
81
83
|
else
|
82
84
|
raise "unknown arg type #{arg.first.inspect}"
|
83
85
|
end
|
@@ -89,33 +91,6 @@ class Ruby2Ruby < SexpProcessor
|
|
89
91
|
return "(#{args.join ', '})"
|
90
92
|
end
|
91
93
|
|
92
|
-
def process_arglist(exp) # custom made node
|
93
|
-
code = []
|
94
|
-
until exp.empty? do
|
95
|
-
code << process(exp.shift)
|
96
|
-
end
|
97
|
-
code.join ', '
|
98
|
-
end
|
99
|
-
|
100
|
-
def process_argscat(exp)
|
101
|
-
args = []
|
102
|
-
|
103
|
-
ary = exp.shift
|
104
|
-
ary.shift # :array
|
105
|
-
until ary.empty? do
|
106
|
-
args << process(ary.shift)
|
107
|
-
end
|
108
|
-
|
109
|
-
args << "*#{process(exp.shift)}"
|
110
|
-
args << process(exp.shift) unless exp.empty? # optional block arg
|
111
|
-
|
112
|
-
args.join ', '
|
113
|
-
end
|
114
|
-
|
115
|
-
def process_argspush(exp)
|
116
|
-
process_arglist(exp)
|
117
|
-
end
|
118
|
-
|
119
94
|
def process_array(exp)
|
120
95
|
"[#{process_arglist(exp)}]"
|
121
96
|
end
|
@@ -128,13 +103,11 @@ class Ruby2Ruby < SexpProcessor
|
|
128
103
|
case name
|
129
104
|
when :[]= then
|
130
105
|
rhs = process args.pop
|
131
|
-
args[0] = :arglist if args[0] == :array
|
132
106
|
"#{receiver}[#{process(args)}] = #{rhs}"
|
133
107
|
else
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
"#{receiver}.#{name.to_s[0..-2]}"
|
108
|
+
name = name.to_s.sub(/=$/, '')
|
109
|
+
if args && args != s(:arglist) then
|
110
|
+
"#{receiver}.#{name} = #{process(args)}"
|
138
111
|
end
|
139
112
|
end
|
140
113
|
end
|
@@ -143,16 +116,16 @@ class Ruby2Ruby < SexpProcessor
|
|
143
116
|
"$#{exp.shift}"
|
144
117
|
end
|
145
118
|
|
119
|
+
# TODO: figure out how to do rescue and ensure ENTIRELY w/o begin
|
146
120
|
def process_begin(exp)
|
147
|
-
is_rescue = exp.first.first == :rescue rescue false
|
148
121
|
code = []
|
149
122
|
code << "begin"
|
150
123
|
until exp.empty?
|
151
124
|
src = process(exp.shift)
|
152
|
-
src = indent(src) unless src =~ /(^|\n)rescue/ #
|
125
|
+
src = indent(src) unless src =~ /(^|\n)rescue/ # ensure no level 0 rescues
|
153
126
|
code << src
|
154
127
|
end
|
155
|
-
code << "end"
|
128
|
+
code << "end"
|
156
129
|
return code.join("\n")
|
157
130
|
end
|
158
131
|
|
@@ -181,30 +154,10 @@ class Ruby2Ruby < SexpProcessor
|
|
181
154
|
return result
|
182
155
|
end
|
183
156
|
|
184
|
-
def
|
185
|
-
"
|
186
|
-
end
|
187
|
-
|
188
|
-
def process_block_pass(exp)
|
189
|
-
bname = s(:block_arg, process(exp.shift)) # FIX
|
190
|
-
call = exp.shift
|
191
|
-
|
192
|
-
if Array === call.last then # HACK - I _really_ need rewrites to happen first
|
193
|
-
case call.last.first
|
194
|
-
when :splat then
|
195
|
-
call << [:array, call.pop]
|
196
|
-
when :array then
|
197
|
-
# do nothing
|
198
|
-
else
|
199
|
-
has_args = Array === call.last and call.last.first == :array
|
200
|
-
call << [:array] unless has_args
|
201
|
-
end
|
202
|
-
call.last << bname
|
203
|
-
else
|
204
|
-
call << [:array, bname]
|
205
|
-
end
|
157
|
+
def process_block_pass exp
|
158
|
+
raise "huh?: #{exp.inspect}" if exp.size > 1
|
206
159
|
|
207
|
-
process
|
160
|
+
"&#{process exp.shift}"
|
208
161
|
end
|
209
162
|
|
210
163
|
def process_break(exp)
|
@@ -276,8 +229,12 @@ class Ruby2Ruby < SexpProcessor
|
|
276
229
|
def process_cdecl(exp)
|
277
230
|
lhs = exp.shift
|
278
231
|
lhs = process lhs if Sexp === lhs
|
279
|
-
|
280
|
-
|
232
|
+
unless exp.empty? then
|
233
|
+
rhs = process(exp.shift)
|
234
|
+
"#{lhs} = #{rhs}"
|
235
|
+
else
|
236
|
+
lhs.to_s
|
237
|
+
end
|
281
238
|
end
|
282
239
|
|
283
240
|
def process_class(exp)
|
@@ -308,34 +265,6 @@ class Ruby2Ruby < SexpProcessor
|
|
308
265
|
"#{exp.shift} = #{process(exp.shift)}"
|
309
266
|
end
|
310
267
|
|
311
|
-
# (a, lit1) => "a = 1"
|
312
|
-
# (a, (b, lit2)) => "a = b = 2"
|
313
|
-
# (a, (b)) => ""
|
314
|
-
|
315
|
-
def process_dasgn_curr(exp)
|
316
|
-
lhs = exp.shift.to_s
|
317
|
-
rhs = (exp.empty? ? nil : exp.shift)
|
318
|
-
if rhs.nil? then
|
319
|
-
if self.context[1] == :block then
|
320
|
-
return ''
|
321
|
-
end
|
322
|
-
|
323
|
-
return lhs
|
324
|
-
end
|
325
|
-
return "#{lhs} = #{process rhs}" unless rhs.first == :dasgn_curr
|
326
|
-
|
327
|
-
# keep recursing. ensure that the leaf node assigns to _something_
|
328
|
-
"#{lhs} = #{process rhs}"
|
329
|
-
end
|
330
|
-
|
331
|
-
def process_dasgn(exp)
|
332
|
-
if exp.size == 1 then
|
333
|
-
exp.shift.to_s
|
334
|
-
else
|
335
|
-
"#{exp.shift} = #{process(exp.shift)}"
|
336
|
-
end
|
337
|
-
end
|
338
|
-
|
339
268
|
def process_defined(exp)
|
340
269
|
"defined? #{process(exp.shift)}"
|
341
270
|
end
|
@@ -371,7 +300,14 @@ class Ruby2Ruby < SexpProcessor
|
|
371
300
|
end
|
372
301
|
|
373
302
|
def process_defs(exp)
|
374
|
-
|
303
|
+
lhs = exp.shift
|
304
|
+
var = [:self, :cvar, :dvar, :ivar, :gvar, :lvar].include? lhs.first
|
305
|
+
name = exp.shift
|
306
|
+
|
307
|
+
lhs = process(lhs)
|
308
|
+
lhs = "(#{lhs})" unless var
|
309
|
+
|
310
|
+
exp.unshift "#{lhs}.#{name}"
|
375
311
|
process_defn(exp)
|
376
312
|
end
|
377
313
|
|
@@ -399,41 +335,29 @@ class Ruby2Ruby < SexpProcessor
|
|
399
335
|
":#{process_dstr(exp)}"
|
400
336
|
end
|
401
337
|
|
402
|
-
def process_dvar(exp)
|
403
|
-
exp.shift.to_s
|
404
|
-
end
|
405
|
-
|
406
338
|
def process_dxstr(exp)
|
407
339
|
"`#{process_dstr(exp)[1..-2]}`"
|
408
340
|
end
|
409
341
|
|
410
342
|
def process_ensure(exp)
|
411
343
|
body = process exp.shift
|
412
|
-
ens =
|
344
|
+
ens = exp.shift
|
345
|
+
ens = nil if ens == s(:nil)
|
346
|
+
ens = process(ens) || "# do nothing"
|
347
|
+
|
348
|
+
body.sub!(/\n\s*end\z/, '')
|
349
|
+
|
413
350
|
return "#{body}\nensure\n#{indent ens}"
|
414
351
|
end
|
415
352
|
|
416
353
|
def process_evstr(exp)
|
417
|
-
process
|
354
|
+
exp.empty? ? '' : process(exp.shift)
|
418
355
|
end
|
419
356
|
|
420
357
|
def process_false(exp)
|
421
358
|
"false"
|
422
359
|
end
|
423
360
|
|
424
|
-
# TODO: remove for unified
|
425
|
-
def process_fcall(exp)
|
426
|
-
recv = exp.shift unless Symbol === exp.first # HACK conditional - some not getting rewritten?
|
427
|
-
name = exp.shift.to_s
|
428
|
-
args = exp.shift
|
429
|
-
code = []
|
430
|
-
unless args.nil? then
|
431
|
-
args[0] = :arglist if args.first == :array
|
432
|
-
code << process(args)
|
433
|
-
end
|
434
|
-
return code.empty? ? name : "#{name}(#{code.join(', ')})"
|
435
|
-
end
|
436
|
-
|
437
361
|
def process_flip2(exp)
|
438
362
|
"#{process(exp.shift)}..#{process(exp.shift)}"
|
439
363
|
end
|
@@ -465,7 +389,13 @@ class Ruby2Ruby < SexpProcessor
|
|
465
389
|
def process_hash(exp)
|
466
390
|
result = []
|
467
391
|
until exp.empty?
|
468
|
-
|
392
|
+
lhs = process(exp.shift)
|
393
|
+
rhs = exp.shift
|
394
|
+
t = rhs.first
|
395
|
+
rhs = process rhs
|
396
|
+
rhs = "(#{rhs})" unless [:lit, :str].include? t # TODO: verify better!
|
397
|
+
|
398
|
+
result << "#{lhs} => #{rhs}"
|
469
399
|
end
|
470
400
|
|
471
401
|
case self.context[1]
|
@@ -588,7 +518,7 @@ class Ruby2Ruby < SexpProcessor
|
|
588
518
|
rhs = exp.empty? ? nil : exp.shift
|
589
519
|
|
590
520
|
unless exp.empty? then
|
591
|
-
rhs[
|
521
|
+
rhs[1] = splat(rhs[1]) unless rhs == s(:splat)
|
592
522
|
lhs << rhs
|
593
523
|
rhs = exp.shift
|
594
524
|
end
|
@@ -604,7 +534,7 @@ class Ruby2Ruby < SexpProcessor
|
|
604
534
|
process(l)
|
605
535
|
end
|
606
536
|
end
|
607
|
-
when :
|
537
|
+
when :lasgn then
|
608
538
|
lhs = [ splat(lhs.last) ]
|
609
539
|
when :splat then
|
610
540
|
lhs = [ :"*" ]
|
@@ -613,20 +543,14 @@ class Ruby2Ruby < SexpProcessor
|
|
613
543
|
end
|
614
544
|
|
615
545
|
if context[1] == :iter and rhs then
|
616
|
-
lhs << splat(rhs
|
546
|
+
lhs << splat(rhs[1])
|
617
547
|
rhs = nil
|
618
548
|
end
|
619
549
|
|
620
550
|
unless rhs.nil? then
|
621
551
|
t = rhs.first
|
622
|
-
rhs =
|
623
|
-
|
624
|
-
process_argscat(rhs)
|
625
|
-
else
|
626
|
-
r = process(rhs)
|
627
|
-
r = r[1..-2] if t != :to_ary
|
628
|
-
r
|
629
|
-
end
|
552
|
+
rhs = process rhs
|
553
|
+
rhs = rhs[1..-2] if t != :to_ary
|
630
554
|
return "#{lhs.join(", ")} = #{rhs}"
|
631
555
|
else
|
632
556
|
return lhs.join(", ")
|
@@ -676,13 +600,13 @@ class Ruby2Ruby < SexpProcessor
|
|
676
600
|
end
|
677
601
|
|
678
602
|
def process_op_asgn1(exp)
|
679
|
-
# [[:lvar, :b], [:
|
603
|
+
# [[:lvar, :b], [:arglist, [:lit, 1]], :"||", [:lit, 10]]
|
680
604
|
lhs = process(exp.shift)
|
681
605
|
index = process(exp.shift)
|
682
606
|
msg = exp.shift
|
683
607
|
rhs = process(exp.shift)
|
684
608
|
|
685
|
-
"#{lhs}#{index} #{msg}= #{rhs}"
|
609
|
+
"#{lhs}[#{index}] #{msg}= #{rhs}"
|
686
610
|
end
|
687
611
|
|
688
612
|
def process_op_asgn2(exp)
|
@@ -696,18 +620,18 @@ class Ruby2Ruby < SexpProcessor
|
|
696
620
|
"#{lhs}.#{index} #{msg}= #{rhs}"
|
697
621
|
end
|
698
622
|
|
699
|
-
def
|
700
|
-
# a
|
623
|
+
def process_op_asgn_and(exp)
|
624
|
+
# a &&= 1
|
701
625
|
# [[:lvar, :a], [:lasgn, :a, [:lit, 1]]]
|
702
626
|
exp.shift
|
703
|
-
process(exp.shift).sub(
|
627
|
+
process(exp.shift).sub(/\=/, '&&=')
|
704
628
|
end
|
705
629
|
|
706
|
-
def
|
707
|
-
# a
|
630
|
+
def process_op_asgn_or(exp)
|
631
|
+
# a ||= 1
|
708
632
|
# [[:lvar, :a], [:lasgn, :a, [:lit, 1]]]
|
709
633
|
exp.shift
|
710
|
-
process(exp.shift).sub(
|
634
|
+
process(exp.shift).sub(/\=/, '||=')
|
711
635
|
end
|
712
636
|
|
713
637
|
def process_or(exp)
|
@@ -722,97 +646,40 @@ class Ruby2Ruby < SexpProcessor
|
|
722
646
|
"redo"
|
723
647
|
end
|
724
648
|
|
725
|
-
def process_resbody
|
726
|
-
|
727
|
-
|
728
|
-
sexp = exp
|
729
|
-
until exp.empty? and (sexp.nil? or sexp.empty?)
|
730
|
-
list = sexp.shift
|
731
|
-
body = sexp.shift
|
732
|
-
|
733
|
-
var = if list and
|
734
|
-
list.size > 1 and
|
735
|
-
[:lasgn, :dasgn, :dasgn_curr].include? list.last.first then
|
736
|
-
list.pop[1]
|
737
|
-
else
|
738
|
-
nil
|
739
|
-
end
|
740
|
-
|
741
|
-
# FIX: omg this is horrid. I should be punished
|
742
|
-
var = body.delete_at(1)[1] if
|
743
|
-
[:dasgn_curr, :dasgn].include? body[1][0] unless
|
744
|
-
var or body.nil? rescue nil
|
745
|
-
|
746
|
-
if list and list.size > 1 then
|
747
|
-
list[0] = :arglist
|
748
|
-
code << "rescue #{process(list)}"
|
749
|
-
else
|
750
|
-
code << "rescue"
|
751
|
-
end
|
752
|
-
|
753
|
-
code.last << " => #{var}" if var
|
754
|
-
|
755
|
-
if body then
|
756
|
-
code << indent(process(body)).chomp
|
757
|
-
else
|
758
|
-
code << indent("# do nothing")
|
759
|
-
end
|
649
|
+
def process_resbody exp
|
650
|
+
args = exp.shift
|
651
|
+
body = process(exp.shift) || "# do nothing"
|
760
652
|
|
761
|
-
|
762
|
-
|
763
|
-
|
764
|
-
|
765
|
-
|
766
|
-
end
|
653
|
+
name = args.lasgn true
|
654
|
+
name ||= args.iasgn true
|
655
|
+
args = process(args)[1..-2]
|
656
|
+
args = " #{args}" unless args.empty?
|
657
|
+
args += " => #{name[1]}" if name
|
767
658
|
|
768
|
-
|
659
|
+
"rescue#{args}\n#{indent body}"
|
769
660
|
end
|
770
661
|
|
771
|
-
def process_rescue
|
772
|
-
|
773
|
-
|
774
|
-
|
775
|
-
|
776
|
-
|
777
|
-
current = self.context[1]
|
778
|
-
case current
|
779
|
-
when :begin, :ensure, :block then
|
780
|
-
body = (exp.first.first == :resbody) ? nil : process(exp.shift)
|
781
|
-
resbody = exp.empty? ? '' : process(exp.shift)
|
782
|
-
els = exp.empty? ? nil : process(exp.shift)
|
783
|
-
|
784
|
-
code = []
|
785
|
-
code << indent(body) if body
|
786
|
-
code << resbody
|
787
|
-
if els then
|
788
|
-
code << "else"
|
789
|
-
code << indent(els)
|
790
|
-
else
|
791
|
-
unless [:block].include? current then
|
792
|
-
code << "end\n" unless current == :ensure
|
793
|
-
else
|
794
|
-
r = [body, resbody.gsub(/rescue\n\s+/, 'rescue ')].compact.join(' ')
|
795
|
-
code = [r] if (@indent+r).size < LINE_LENGTH and r !~ /\n/
|
796
|
-
end
|
797
|
-
end
|
662
|
+
def process_rescue exp
|
663
|
+
body = process(exp.shift) unless exp.first.first == :resbody
|
664
|
+
els = process(exp.pop) unless exp.last.first == :resbody
|
665
|
+
|
666
|
+
body ||= "# do nothing"
|
667
|
+
simple = exp.size == 1
|
798
668
|
|
799
|
-
|
800
|
-
|
801
|
-
body = process exp.shift
|
802
|
-
assert_type exp.first, :resbody
|
669
|
+
resbodies = []
|
670
|
+
until exp.empty? do
|
803
671
|
resbody = exp.shift
|
804
|
-
resbody
|
805
|
-
|
806
|
-
|
807
|
-
|
808
|
-
|
809
|
-
|
810
|
-
|
811
|
-
|
812
|
-
|
813
|
-
|
814
|
-
|
815
|
-
end
|
672
|
+
simple &&= resbody[1] == s(:array) && resbody[2] != nil
|
673
|
+
resbodies << process(resbody)
|
674
|
+
end
|
675
|
+
|
676
|
+
if els then
|
677
|
+
"#{indent body}\n#{resbodies.join("\n")}\nelse\n#{indent els}"
|
678
|
+
elsif simple then
|
679
|
+
resbody = resbodies.first.sub(/\n\s*/, ' ')
|
680
|
+
"#{body} #{resbody}"
|
681
|
+
else
|
682
|
+
"#{indent body}\n#{resbodies.join("\n")}"
|
816
683
|
end
|
817
684
|
end
|
818
685
|
|
@@ -855,13 +722,20 @@ class Ruby2Ruby < SexpProcessor
|
|
855
722
|
end
|
856
723
|
|
857
724
|
def process_super(exp)
|
858
|
-
args =
|
859
|
-
|
860
|
-
|
725
|
+
args = []
|
726
|
+
until exp.empty? do
|
727
|
+
args << process(exp.shift)
|
728
|
+
end
|
729
|
+
|
730
|
+
"super(#{args.join(', ')})"
|
861
731
|
end
|
862
732
|
|
863
733
|
def process_svalue(exp)
|
864
|
-
|
734
|
+
code = []
|
735
|
+
until exp.empty? do
|
736
|
+
code << process(exp.shift)
|
737
|
+
end
|
738
|
+
code.join(", ")
|
865
739
|
end
|
866
740
|
|
867
741
|
def process_to_ary(exp)
|
@@ -912,24 +786,18 @@ class Ruby2Ruby < SexpProcessor
|
|
912
786
|
end
|
913
787
|
|
914
788
|
def process_yield(exp)
|
915
|
-
args =
|
916
|
-
|
917
|
-
args
|
918
|
-
args = process(args)
|
789
|
+
args = []
|
790
|
+
until exp.empty? do
|
791
|
+
args << process(exp.shift)
|
919
792
|
end
|
920
793
|
|
921
|
-
|
922
|
-
|
923
|
-
"yield(#{args})"
|
794
|
+
unless args.empty? then
|
795
|
+
"yield(#{args.join(', ')})"
|
924
796
|
else
|
925
797
|
"yield"
|
926
798
|
end
|
927
799
|
end
|
928
800
|
|
929
|
-
def process_zarray(exp)
|
930
|
-
"[]"
|
931
|
-
end
|
932
|
-
|
933
801
|
def process_zsuper(exp)
|
934
802
|
"super"
|
935
803
|
end
|
@@ -957,24 +825,52 @@ class Ruby2Ruby < SexpProcessor
|
|
957
825
|
############################################################
|
958
826
|
# Rewriters:
|
959
827
|
|
828
|
+
def rewrite_attrasgn exp
|
829
|
+
if context.first(2) == [:array, :masgn] then
|
830
|
+
exp[0] = :call
|
831
|
+
exp[2] = exp[2].to_s.sub(/=$/, '').to_sym
|
832
|
+
end
|
833
|
+
|
834
|
+
exp
|
835
|
+
end
|
836
|
+
|
837
|
+
def rewrite_ensure exp
|
838
|
+
exp = s(:begin, exp) unless context.first == :begin
|
839
|
+
exp
|
840
|
+
end
|
841
|
+
|
960
842
|
def rewrite_rescue exp
|
961
|
-
|
962
|
-
|
963
|
-
|
843
|
+
complex = false
|
844
|
+
complex ||= exp.size > 3
|
845
|
+
complex ||= exp.block
|
846
|
+
complex ||= exp.find_nodes(:resbody).any? { |n| n.array != s(:array) }
|
847
|
+
complex ||= exp.find_nodes(:resbody).any? { |n| n.last.nil? }
|
848
|
+
|
849
|
+
handled = context.first == :ensure
|
850
|
+
|
851
|
+
exp = s(:begin, exp) if complex unless handled
|
852
|
+
|
964
853
|
exp
|
965
854
|
end
|
966
855
|
|
856
|
+
def rewrite_svalue(exp)
|
857
|
+
case exp.last.first
|
858
|
+
when :array
|
859
|
+
s(:svalue, *exp[1][1..-1])
|
860
|
+
when :splat
|
861
|
+
exp
|
862
|
+
else
|
863
|
+
raise "huh: #{exp.inspect}"
|
864
|
+
end
|
865
|
+
end
|
866
|
+
|
967
867
|
############################################################
|
968
868
|
# Utility Methods:
|
969
869
|
|
970
870
|
def util_dthing(exp, regx = false)
|
971
871
|
s = []
|
972
872
|
suck = true
|
973
|
-
|
974
|
-
x = exp.shift.gsub(/"/, '\"').gsub(/\n/, '\n')
|
975
|
-
else
|
976
|
-
x = exp.shift.dump[1..-2]
|
977
|
-
end
|
873
|
+
x = exp.shift.gsub(/"/, '\"').gsub(/\n/, '\n')
|
978
874
|
x.gsub!(/\//, '\/') if regx
|
979
875
|
|
980
876
|
s << x
|
@@ -984,18 +880,15 @@ class Ruby2Ruby < SexpProcessor
|
|
984
880
|
when Sexp then
|
985
881
|
case pt.first
|
986
882
|
when :str then
|
987
|
-
|
988
|
-
x = pt.last.gsub(/"/, '\"').gsub(/\n/, '\n')
|
989
|
-
else
|
990
|
-
x = pt.last.dump[1..-2]
|
991
|
-
end
|
883
|
+
x = pt.last.gsub(/"/, '\"').gsub(/\n/, '\n')
|
992
884
|
x.gsub!(/\//, '\/') if regx
|
993
885
|
s << x
|
994
886
|
else
|
995
887
|
s << '#{' << process(pt) << '}' # do not use interpolation here
|
996
888
|
end
|
997
889
|
else
|
998
|
-
#
|
890
|
+
# HACK: raise "huh?: #{pt.inspect}"
|
891
|
+
# do nothing for now
|
999
892
|
end
|
1000
893
|
end
|
1001
894
|
|
@@ -1038,71 +931,3 @@ class Ruby2Ruby < SexpProcessor
|
|
1038
931
|
s.to_s.split(/\n/).map{|line| @indent + line}.join("\n")
|
1039
932
|
end
|
1040
933
|
end
|
1041
|
-
|
1042
|
-
RubyToRuby = Ruby2Ruby # For backwards compatibilty... TODO: remove 2008-03-28
|
1043
|
-
|
1044
|
-
class Method
|
1045
|
-
def with_class_and_method_name
|
1046
|
-
if self.inspect =~ /<Method: (.*)\#(.*)>/ then
|
1047
|
-
klass = eval $1
|
1048
|
-
method = $2.intern
|
1049
|
-
raise "Couldn't determine class from #{self.inspect}" if klass.nil?
|
1050
|
-
return yield(klass, method)
|
1051
|
-
else
|
1052
|
-
raise "Can't parse signature: #{self.inspect}"
|
1053
|
-
end
|
1054
|
-
end
|
1055
|
-
|
1056
|
-
def to_sexp
|
1057
|
-
require 'parse_tree'
|
1058
|
-
parser = ParseTree.new(false)
|
1059
|
-
with_class_and_method_name do |klass, method|
|
1060
|
-
parser.parse_tree_for_method(klass, method)
|
1061
|
-
end
|
1062
|
-
end
|
1063
|
-
|
1064
|
-
def to_ruby
|
1065
|
-
Ruby2Ruby.new.process(self.to_sexp)
|
1066
|
-
end
|
1067
|
-
end
|
1068
|
-
|
1069
|
-
class ProcStoreTmp
|
1070
|
-
@@n = 0
|
1071
|
-
def self.new_name
|
1072
|
-
@@n += 1
|
1073
|
-
return :"myproc#{@@n}"
|
1074
|
-
end
|
1075
|
-
end
|
1076
|
-
|
1077
|
-
class UnboundMethod
|
1078
|
-
def to_ruby
|
1079
|
-
name = ProcStoreTmp.new_name
|
1080
|
-
ProcStoreTmp.send(:define_method, name, self)
|
1081
|
-
m = ProcStoreTmp.new.method(name)
|
1082
|
-
result = m.to_ruby.sub(/def #{name}(?:\(([^\)]*)\))?/,
|
1083
|
-
'proc { |\1|').sub(/end\Z/, '}')
|
1084
|
-
return result
|
1085
|
-
end
|
1086
|
-
end
|
1087
|
-
|
1088
|
-
class Proc
|
1089
|
-
def to_method
|
1090
|
-
name = ProcStoreTmp.new_name
|
1091
|
-
ProcStoreTmp.send(:define_method, name, self)
|
1092
|
-
ProcStoreTmp.new.method(name)
|
1093
|
-
end
|
1094
|
-
|
1095
|
-
def to_sexp
|
1096
|
-
sexp = self.to_method.to_sexp
|
1097
|
-
body = sexp[2]
|
1098
|
-
body[0] = :block
|
1099
|
-
args = body.delete_at 1
|
1100
|
-
body = body[1] if body.size == 2
|
1101
|
-
|
1102
|
-
[:iter, [:fcall, :proc], args, body]
|
1103
|
-
end
|
1104
|
-
|
1105
|
-
def to_ruby
|
1106
|
-
Ruby2Ruby.new.process(self.to_sexp).sub(/^\Aproc do/, 'proc {').sub(/end\Z/, '}')
|
1107
|
-
end
|
1108
|
-
end
|
data/test/test_ruby2ruby.rb
CHANGED
@@ -14,8 +14,29 @@ require 'tmpdir'
|
|
14
14
|
|
15
15
|
FileUtils.rm_rf File.expand_path("~/.ruby_inline") # for self-translation
|
16
16
|
|
17
|
-
class
|
17
|
+
class R2RTestCase < ParseTreeTestCase
|
18
|
+
def self.previous key
|
19
|
+
"ParseTree"
|
20
|
+
end
|
21
|
+
|
22
|
+
def self.generate_test klass, node, data, input_name, output_name
|
23
|
+
output_name = data.has_key?('Ruby2Ruby') ? 'Ruby2Ruby' : 'Ruby'
|
24
|
+
|
25
|
+
klass.class_eval <<-EOM
|
26
|
+
def test_#{node}
|
27
|
+
pt = #{data[input_name].inspect}
|
28
|
+
rb = #{data[output_name].inspect}
|
29
|
+
|
30
|
+
refute_nil pt, \"ParseTree for #{node} undefined\"
|
31
|
+
refute_nil rb, \"Ruby for #{node} undefined\"
|
32
|
+
|
33
|
+
assert_equal rb, @processor.process(pt)
|
34
|
+
end
|
35
|
+
EOM
|
36
|
+
end
|
37
|
+
end
|
18
38
|
|
39
|
+
class TestRuby2Ruby < R2RTestCase
|
19
40
|
alias :refute_nil :assert_not_nil unless defined? Mini
|
20
41
|
|
21
42
|
def setup
|
@@ -30,35 +51,6 @@ class TestRuby2Ruby < Test::Unit::TestCase
|
|
30
51
|
end if defined?(@rootdir) && @rootdir
|
31
52
|
end
|
32
53
|
|
33
|
-
def util_setup_inline
|
34
|
-
@rootdir = File.join(Dir.tmpdir, "test_ruby_to_ruby.#{$$}")
|
35
|
-
Dir.mkdir @rootdir, 0700 unless test ?d, @rootdir
|
36
|
-
ENV['INLINEDIR'] = @rootdir
|
37
|
-
end
|
38
|
-
|
39
|
-
def test_proc_to_ruby
|
40
|
-
util_setup_inline
|
41
|
-
block = proc { puts "something" }
|
42
|
-
assert_equal 'proc { puts("something") }', block.to_ruby
|
43
|
-
end unless SKIP_PROCS
|
44
|
-
|
45
|
-
def test_lit_regexp_slash
|
46
|
-
inn = s(:lit, /blah\/blah/)
|
47
|
-
out = '/blah\/blah/'
|
48
|
-
|
49
|
-
assert_equal out, @processor.process(inn)
|
50
|
-
|
51
|
-
r = eval(out)
|
52
|
-
assert_equal(/blah\/blah/, r)
|
53
|
-
end
|
54
|
-
|
55
|
-
def util_thingy(type)
|
56
|
-
s(type,
|
57
|
-
'blah"blah',
|
58
|
-
s(:call, s(:lit, 1), :+, s(:array, s(:lit, 1))),
|
59
|
-
s(:str, 'blah"blah/blah'))
|
60
|
-
end
|
61
|
-
|
62
54
|
def test_dregx_slash
|
63
55
|
inn = util_thingy(:dregx)
|
64
56
|
out = "/blah\\\"blah#\{(1 + 1)}blah\\\"blah\\/blah/"
|
@@ -89,58 +81,59 @@ class TestRuby2Ruby < Test::Unit::TestCase
|
|
89
81
|
assert_equal :"blah\"blah2blah\"blah/blah", r
|
90
82
|
end
|
91
83
|
|
92
|
-
def
|
93
|
-
|
94
|
-
|
95
|
-
s = [:iter, [:fcall, :proc], nil, [:call, [:lit, 1], :+, [:array, [:lit, 1]]]]
|
96
|
-
assert_equal s, p.to_sexp
|
97
|
-
end unless SKIP_PROCS
|
98
|
-
|
99
|
-
def test_unbound_method_to_ruby
|
100
|
-
util_setup_inline
|
101
|
-
r = "proc { ||\n util_setup_inline\n p = proc { (1 + 1) }\n s = [:iter, [:fcall, :proc], nil, [:call, [:lit, 1], :+, [:array, [:lit, 1]]]]\n assert_equal(s, p.to_sexp)\n}"
|
102
|
-
m = self.class.instance_method(:test_proc_to_sexp)
|
103
|
-
|
104
|
-
assert_equal r, m.to_ruby
|
105
|
-
end unless SKIP_PROCS
|
84
|
+
def test_lit_regexp_slash
|
85
|
+
inn = s(:lit, /blah\/blah/)
|
86
|
+
out = '/blah\/blah/'
|
106
87
|
|
107
|
-
|
108
|
-
next if node == "vcall" # HACK
|
88
|
+
assert_equal out, @processor.process(inn)
|
109
89
|
|
110
|
-
|
111
|
-
|
112
|
-
|
90
|
+
r = eval(out)
|
91
|
+
assert_equal(/blah\/blah/, r)
|
92
|
+
end
|
113
93
|
|
114
|
-
|
115
|
-
|
94
|
+
def util_setup_inline
|
95
|
+
@rootdir = File.join(Dir.tmpdir, "test_ruby_to_ruby.#{$$}")
|
96
|
+
Dir.mkdir @rootdir, 0700 unless test ?d, @rootdir
|
97
|
+
ENV['INLINEDIR'] = @rootdir
|
98
|
+
end
|
116
99
|
|
117
|
-
|
118
|
-
|
119
|
-
|
100
|
+
def util_thingy(type)
|
101
|
+
s(type,
|
102
|
+
'blah"blah',
|
103
|
+
s(:call, s(:lit, 1), :+, s(:array, s(:lit, 1))),
|
104
|
+
s(:str, 'blah"blah/blah'))
|
105
|
+
end
|
120
106
|
end
|
121
107
|
|
122
108
|
##
|
123
109
|
# Converts a +target+ using a +processor+ and converts +target+ name
|
124
110
|
# in the source adding +gen+ to allow easy renaming.
|
125
111
|
|
112
|
+
$broken = false
|
126
113
|
def morph_and_eval(processor, target, gen, n)
|
114
|
+
return if $broken
|
127
115
|
begin
|
128
116
|
processor = Object.const_get processor if Symbol === processor
|
129
117
|
target = Object.const_get target if Symbol === target
|
130
118
|
old_name = target.name
|
131
119
|
new_name = target.name.sub(/\d*$/, gen.to_s)
|
132
|
-
ruby
|
120
|
+
ruby = processor.translate(target).sub(old_name, new_name)
|
133
121
|
|
122
|
+
old, $-w = $-w, nil
|
134
123
|
eval ruby
|
124
|
+
$-w = old
|
125
|
+
|
135
126
|
target.constants.each do |constant|
|
136
127
|
eval "#{new_name}::#{constant} = #{old_name}::#{constant}"
|
137
128
|
end
|
138
129
|
rescue Exception => e
|
139
130
|
warn "Self-Translation Generation #{n} failed:"
|
140
131
|
warn "#{e.class}: #{e.message}"
|
132
|
+
warn e.backtrace.join("\n ")
|
141
133
|
warn ""
|
142
134
|
warn ruby
|
143
135
|
warn ""
|
136
|
+
$broken = true
|
144
137
|
else
|
145
138
|
begin
|
146
139
|
yield if block_given?
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ruby2ruby
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Ryan Davis
|
@@ -9,26 +9,28 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2008-
|
12
|
+
date: 2008-10-22 00:00:00 -05:00
|
13
13
|
default_executable:
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: ParseTree
|
17
|
+
type: :runtime
|
17
18
|
version_requirement:
|
18
19
|
version_requirements: !ruby/object:Gem::Requirement
|
19
20
|
requirements:
|
20
|
-
- -
|
21
|
+
- - ~>
|
21
22
|
- !ruby/object:Gem::Version
|
22
|
-
version: "0"
|
23
|
+
version: "3.0"
|
23
24
|
version:
|
24
25
|
- !ruby/object:Gem::Dependency
|
25
26
|
name: hoe
|
27
|
+
type: :development
|
26
28
|
version_requirement:
|
27
29
|
version_requirements: !ruby/object:Gem::Requirement
|
28
30
|
requirements:
|
29
31
|
- - ">="
|
30
32
|
- !ruby/object:Gem::Version
|
31
|
-
version: 1.
|
33
|
+
version: 1.8.0
|
32
34
|
version:
|
33
35
|
description: ruby2ruby provides a means of generating pure ruby code easily from ParseTree's Sexps. This makes making dynamic language processors much easier in ruby than ever before.
|
34
36
|
email:
|
@@ -73,7 +75,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
73
75
|
requirements: []
|
74
76
|
|
75
77
|
rubyforge_project: seattlerb
|
76
|
-
rubygems_version: 1.
|
78
|
+
rubygems_version: 1.3.0
|
77
79
|
signing_key:
|
78
80
|
specification_version: 2
|
79
81
|
summary: ruby2ruby provides a means of generating pure ruby code easily from ParseTree's Sexps
|