ruby2ruby 1.1.9 → 1.2.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.
- 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
|