ruby2ruby 1.1.7 → 1.1.8
Sign up to get free protection for your applications and to get access to all the features.
- data/.autotest +15 -0
- data/History.txt +38 -2
- data/Manifest.txt +1 -0
- data/README.txt +1 -1
- data/Rakefile +1 -1
- data/lib/ruby2ruby.rb +151 -134
- data/test/test_ruby2ruby.rb +61 -38
- metadata +59 -51
data/.autotest
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
# -*- ruby -*-
|
2
|
+
|
3
|
+
Autotest.add_hook :initialize do |at|
|
4
|
+
at.extra_files << "../../ParseTree/dev/test/pt_testcase.rb"
|
5
|
+
at.extra_files << "../../ParseTree/dev/lib/unified_ruby.rb"
|
6
|
+
at.libs << ":../../ParseTree/dev/lib:../../ParseTree/dev/test"
|
7
|
+
|
8
|
+
(1..4).each do |n|
|
9
|
+
at.extra_class_map["TestRuby2Ruby#{n}"] = "test/test_ruby2ruby.rb"
|
10
|
+
end
|
11
|
+
|
12
|
+
at.add_mapping(/unified|pt_testcase/) do |f, _|
|
13
|
+
at.files_matching(/^test.*rb$/)
|
14
|
+
end
|
15
|
+
end
|
data/History.txt
CHANGED
@@ -1,15 +1,36 @@
|
|
1
|
+
=== 1.1.8 / 2007-08-21
|
2
|
+
|
3
|
+
* 6 minor enhancements:
|
4
|
+
|
5
|
+
* Added super awesome .autotest file. YAY!
|
6
|
+
* Removed nil.method_missing... too many ppl bitching about it.
|
7
|
+
* Renamed RubyToRuby (the class name) to Ruby2Ruby.
|
8
|
+
* Restructured self-translation tests so they were friendlier when dying.
|
9
|
+
* Strings are now always one line long only.
|
10
|
+
* Fully in sync with ParseTree and ruby_parser.
|
11
|
+
|
12
|
+
* 2 bug fixes:
|
13
|
+
|
14
|
+
* Fixed a number of issues/bugs discovered via ruby_parser.
|
15
|
+
* Cleaned out some dead code and hacks we don't need anymore.
|
16
|
+
|
1
17
|
=== 1.1.7 / 2007-08-21
|
2
18
|
|
3
19
|
* 2 major enhancements:
|
20
|
+
|
4
21
|
* Switched to ParseTree's UnifiedRuby... much much cleaner now!
|
5
22
|
* Made test_ruby2ruby MUCH more rigorous with circular testing.
|
23
|
+
|
6
24
|
* 5 minor enhancements:
|
25
|
+
|
7
26
|
* Add r2r_show command like parse_tree_show.
|
8
27
|
* Add parens for :block nodes as appropriate. May be overzealous.
|
9
28
|
* Make SexpAny work with #==.
|
10
29
|
* Removed calls to processor_stack / caller in favor of self.context.
|
11
30
|
* Some style differences, eschew rescue.
|
31
|
+
|
12
32
|
* 6 bug fixes:
|
33
|
+
|
13
34
|
* Fix R2R bug with masgn/argscat.
|
14
35
|
* Fixed a bug with new resbody unification.
|
15
36
|
* Fixes for changes to pt_testcase.
|
@@ -20,19 +41,25 @@
|
|
20
41
|
=== 1.1.6 / 2007-06-05
|
21
42
|
|
22
43
|
* 2 minor enhancements:
|
44
|
+
|
23
45
|
* Extended tests for dstr/dsym/drgx to test against embedded slashes and quotes.
|
24
46
|
* Updated for dasgn_curr changes to PT.
|
47
|
+
|
25
48
|
* 2 bug fixes:
|
49
|
+
|
26
50
|
* Fixed a bug with begin/rescue/ensure.
|
27
51
|
* Fixed argscat and blockpass bug. blah(42, *args, &block) handled.
|
28
52
|
|
29
53
|
=== 1.1.5 / 2007-02-13
|
30
54
|
|
31
55
|
* 3 minor enhancements:
|
56
|
+
|
32
57
|
* Can now heckle ActiveRecord::Base in full.
|
33
58
|
* Cleaned up 1-liner generating code.
|
34
59
|
* Made clean/simple rescues 1-liners.
|
60
|
+
|
35
61
|
* 7 bug fixes:
|
62
|
+
|
36
63
|
* Finally got the rest of block_pass working.
|
37
64
|
* Fixed block_pass on procs in iters. UGH!
|
38
65
|
* Fixed attrasgn in masgn.
|
@@ -44,11 +71,14 @@
|
|
44
71
|
=== 1.1.4 / 2007-01-15
|
45
72
|
|
46
73
|
* 4 minor enhancements:
|
74
|
+
|
47
75
|
* Added some extra rewriting code and tests for various bmethods. Ugh.
|
48
76
|
* Added support for splatted block args.
|
49
77
|
* Refactored class/module and dsym/dstr.
|
50
78
|
* Short if/unless statements are now post-conditional expressions.
|
79
|
+
|
51
80
|
* 4 bug fixes:
|
81
|
+
|
52
82
|
* Finally fixed eric's nebulous proc code-in-goalposts bug.
|
53
83
|
* Fixed dasgn_curr so block's dasgn vars decl goes away (bug 7420).
|
54
84
|
* Fixed dmethod. I think the tests were bogus before.
|
@@ -57,16 +87,22 @@
|
|
57
87
|
=== 1.1.3 / 2006-12-20
|
58
88
|
|
59
89
|
* 1 minor enhancement
|
90
|
+
|
60
91
|
* Unit tests do self-translation and retesting for 3 generations! Solid. BAM!
|
92
|
+
|
61
93
|
* 1 bug fixes
|
94
|
+
|
62
95
|
* iasgn inside masgn was totally borked in ruby2ruby.
|
63
96
|
|
64
97
|
=== 1.1.2 / 2006-12-19
|
65
98
|
|
66
99
|
* 2 minor enhancements
|
100
|
+
|
67
101
|
* Improved []= and [] to be more idiomatic.
|
68
102
|
* Support for nested whens (from when case has no expression).
|
103
|
+
|
69
104
|
* 3 bug fixes
|
105
|
+
|
70
106
|
* Fixed case output when there is no case expression.
|
71
107
|
* NEARLY have RubyToRuby self-cloning and passing tests again.
|
72
108
|
* Minor cleanup
|
@@ -74,6 +110,7 @@
|
|
74
110
|
=== 1.1.1 / 2006-11-13
|
75
111
|
|
76
112
|
* 3 bug fixes
|
113
|
+
|
77
114
|
* Fixed procs
|
78
115
|
* Cleaned return when no return values.
|
79
116
|
* Rewrote process_if. No more elsif but no more bugs. :)
|
@@ -81,7 +118,6 @@
|
|
81
118
|
=== 1.1.0 / 2006-10-11
|
82
119
|
|
83
120
|
* 2 major enhancements
|
121
|
+
|
84
122
|
* Released separately from ZenHacks.
|
85
123
|
* Major overhaul/audit from the new ParseTree test infrastructure. Very complete now.
|
86
|
-
|
87
|
-
|
data/Manifest.txt
CHANGED
data/README.txt
CHANGED
@@ -28,7 +28,7 @@ easier in ruby than ever before.
|
|
28
28
|
|
29
29
|
(The MIT License)
|
30
30
|
|
31
|
-
Copyright (c) 2006 Ryan Davis
|
31
|
+
Copyright (c) 2006-2007 Ryan Davis
|
32
32
|
|
33
33
|
Permission is hereby granted, free of charge, to any person obtaining
|
34
34
|
a copy of this software and associated documentation files (the
|
data/Rakefile
CHANGED
@@ -13,7 +13,7 @@ Hoe.new('ruby2ruby', RubyToRuby::VERSION) do |p|
|
|
13
13
|
p.summary = 'ruby2ruby provides a means of generating pure ruby code easily from ParseTree\'s Sexps.'
|
14
14
|
p.description = p.paragraphs_of('README.txt', 2).join
|
15
15
|
p.url = p.paragraphs_of('README.txt', 0).first.split(/\n/)[1..-1].map {|u| u.strip }
|
16
|
-
p.changes = p.paragraphs_of('History.txt', 0..
|
16
|
+
p.changes = p.paragraphs_of('History.txt', 0..4).join("\n\n")
|
17
17
|
p.clean_globs << File.expand_path("~/.ruby_inline")
|
18
18
|
p.extra_deps << "ParseTree"
|
19
19
|
end
|
data/lib/ruby2ruby.rb
CHANGED
@@ -5,16 +5,10 @@ require 'parse_tree'
|
|
5
5
|
require 'sexp_processor'
|
6
6
|
require 'unified_ruby'
|
7
7
|
|
8
|
-
class
|
9
|
-
def method_missing(msg, *args, &block)
|
10
|
-
nil
|
11
|
-
end
|
12
|
-
end
|
13
|
-
|
14
|
-
class RubyToRuby < SexpProcessor
|
8
|
+
class Ruby2Ruby < SexpProcessor
|
15
9
|
include UnifiedRuby
|
16
10
|
|
17
|
-
VERSION = '1.1.
|
11
|
+
VERSION = '1.1.8'
|
18
12
|
LINE_LENGTH = 78
|
19
13
|
|
20
14
|
##
|
@@ -84,17 +78,6 @@ class RubyToRuby < SexpProcessor
|
|
84
78
|
end
|
85
79
|
when :block_arg then
|
86
80
|
args << "&#{arg.last}"
|
87
|
-
when :array then
|
88
|
-
names = arg
|
89
|
-
vals = exp.shift
|
90
|
-
names.shift
|
91
|
-
vals.shift
|
92
|
-
v_size = vals.size
|
93
|
-
|
94
|
-
args << process(names.shift) until names.size == v_size
|
95
|
-
names.zip(vals) do |name, val|
|
96
|
-
args << "#{process name} = #{process val}"
|
97
|
-
end
|
98
81
|
else
|
99
82
|
raise "unknown arg type #{arg.first.inspect}"
|
100
83
|
end
|
@@ -130,13 +113,7 @@ class RubyToRuby < SexpProcessor
|
|
130
113
|
end
|
131
114
|
|
132
115
|
def process_argspush(exp)
|
133
|
-
|
134
|
-
|
135
|
-
until exp.empty? do
|
136
|
-
args << process(exp.shift)
|
137
|
-
end
|
138
|
-
|
139
|
-
"#{args.join ', '}"
|
116
|
+
process_arglist(exp)
|
140
117
|
end
|
141
118
|
|
142
119
|
def process_array(exp)
|
@@ -151,7 +128,7 @@ class RubyToRuby < SexpProcessor
|
|
151
128
|
case name
|
152
129
|
when :[]= then
|
153
130
|
rhs = process args.pop
|
154
|
-
args[0] = :arglist
|
131
|
+
args[0] = :arglist if args[0] == :array
|
155
132
|
"#{receiver}[#{process(args)}] = #{rhs}"
|
156
133
|
else
|
157
134
|
if args then
|
@@ -172,7 +149,7 @@ class RubyToRuby < SexpProcessor
|
|
172
149
|
code << "begin"
|
173
150
|
until exp.empty?
|
174
151
|
src = process(exp.shift)
|
175
|
-
src = indent(src) unless src =~
|
152
|
+
src = indent(src) unless src =~ /(^|\n)rescue/ # ensures no level 0 rescues
|
176
153
|
code << src
|
177
154
|
end
|
178
155
|
code << "end" unless is_rescue
|
@@ -182,6 +159,7 @@ class RubyToRuby < SexpProcessor
|
|
182
159
|
def process_block(exp)
|
183
160
|
result = []
|
184
161
|
|
162
|
+
exp << nil if exp.empty?
|
185
163
|
until exp.empty? do
|
186
164
|
code = exp.shift
|
187
165
|
if code.nil? or code.first == :nil then
|
@@ -240,11 +218,11 @@ class RubyToRuby < SexpProcessor
|
|
240
218
|
end
|
241
219
|
|
242
220
|
def process_call(exp)
|
243
|
-
receiver_node_type = exp.first.first
|
221
|
+
receiver_node_type = exp.first.nil? ? nil : exp.first.first
|
244
222
|
receiver = process exp.shift
|
245
223
|
|
246
224
|
receiver = "(#{receiver})" if
|
247
|
-
|
225
|
+
Ruby2Ruby::ASSIGN_NODES.include? receiver_node_type
|
248
226
|
|
249
227
|
name = exp.shift
|
250
228
|
args_exp = exp.shift rescue nil
|
@@ -256,7 +234,7 @@ class RubyToRuby < SexpProcessor
|
|
256
234
|
end
|
257
235
|
|
258
236
|
case name
|
259
|
-
when :<=>, :==, :<, :>, :<=, :>=, :-, :+, :*, :/, :%, :<<,
|
237
|
+
when :<=>, :==, :<, :>, :<=, :>=, :-, :+, :*, :/, :%, :<<, :>>, :** then
|
260
238
|
"(#{receiver} #{name} #{args})"
|
261
239
|
when :[] then
|
262
240
|
"#{receiver}[#{args}]"
|
@@ -333,34 +311,32 @@ class RubyToRuby < SexpProcessor
|
|
333
311
|
|
334
312
|
def process_dasgn_curr(exp)
|
335
313
|
lhs = exp.shift.to_s
|
336
|
-
rhs = exp.
|
337
|
-
|
314
|
+
rhs = (exp.empty? ? nil : exp.shift)
|
315
|
+
if rhs.nil? then
|
316
|
+
if self.context[1] == :block then
|
317
|
+
return ''
|
318
|
+
end
|
319
|
+
|
320
|
+
return lhs
|
321
|
+
end
|
338
322
|
return "#{lhs} = #{process rhs}" unless rhs.first == :dasgn_curr
|
339
323
|
|
340
324
|
# keep recursing. ensure that the leaf node assigns to _something_
|
341
|
-
|
342
|
-
if rhs =~ /=/ then
|
343
|
-
"#{lhs} = #{rhs}"
|
344
|
-
else
|
345
|
-
""
|
346
|
-
end
|
325
|
+
"#{lhs} = #{process rhs}"
|
347
326
|
end
|
348
327
|
|
349
328
|
def process_dasgn(exp)
|
350
|
-
|
329
|
+
if exp.size == 1 then
|
330
|
+
exp.shift.to_s
|
331
|
+
else
|
332
|
+
"#{exp.shift} = #{process(exp.shift)}"
|
333
|
+
end
|
351
334
|
end
|
352
335
|
|
353
336
|
def process_defined(exp)
|
354
337
|
"defined? #{process(exp.shift)}"
|
355
338
|
end
|
356
339
|
|
357
|
-
def process_defs(exp)
|
358
|
-
receiver = process(exp.shift)
|
359
|
-
name = exp.shift
|
360
|
-
exp.unshift "#{receiver}.#{name}"
|
361
|
-
process_defn(exp)
|
362
|
-
end
|
363
|
-
|
364
340
|
def process_defn(exp)
|
365
341
|
type1 = exp[1].first
|
366
342
|
type2 = exp[2].first rescue nil
|
@@ -380,32 +356,20 @@ class RubyToRuby < SexpProcessor
|
|
380
356
|
end
|
381
357
|
|
382
358
|
case type1
|
383
|
-
when :cfunc then
|
384
|
-
s = "# method '#{exp.shift}' defined in a C function"
|
385
|
-
exp.shift
|
386
|
-
return s
|
387
359
|
when :scope, :args then
|
388
360
|
name = exp.shift
|
389
361
|
args = process(exp.shift)
|
390
362
|
args = "" if args == "()"
|
391
363
|
body = indent(process(exp.shift))
|
392
364
|
return "def #{name}#{args}\n#{body}\nend".gsub(/\n\s*\n+/, "\n")
|
393
|
-
when :fcall then
|
394
|
-
# skip the fcall (to define_method and such) and grab the body
|
395
|
-
name = exp.shift
|
396
|
-
exp.shift # :fcall to define_method
|
397
|
-
body = process(exp.shift)
|
398
|
-
raise "no"
|
399
365
|
else
|
400
366
|
raise "Unknown defn type: #{type1} for #{exp.inspect}"
|
401
367
|
end
|
402
368
|
end
|
403
369
|
|
404
|
-
def
|
405
|
-
|
406
|
-
|
407
|
-
body = indent(process(exp.shift))
|
408
|
-
return "defx #{name}#{args}\n#{body}end".gsub(/\n\s*\n+/, "\n")
|
370
|
+
def process_defs(exp)
|
371
|
+
exp.unshift "#{process(exp.shift)}.#{exp.shift}"
|
372
|
+
process_defn(exp)
|
409
373
|
end
|
410
374
|
|
411
375
|
def process_dot2(exp)
|
@@ -416,27 +380,8 @@ class RubyToRuby < SexpProcessor
|
|
416
380
|
"(#{process exp.shift}...#{process exp.shift})"
|
417
381
|
end
|
418
382
|
|
419
|
-
def util_dthing(exp, dump=false)
|
420
|
-
s = []
|
421
|
-
s << exp.shift.dump[1..-2]
|
422
|
-
until exp.empty?
|
423
|
-
pt = exp.shift
|
424
|
-
s << case pt.first
|
425
|
-
when :str then
|
426
|
-
if dump then
|
427
|
-
pt.last.dump[1..-2]
|
428
|
-
else
|
429
|
-
pt.last.gsub(%r%/%, '\/')
|
430
|
-
end
|
431
|
-
else
|
432
|
-
"#\{#{process(pt)}}"
|
433
|
-
end
|
434
|
-
end
|
435
|
-
s
|
436
|
-
end
|
437
|
-
|
438
383
|
def process_dregx(exp)
|
439
|
-
"
|
384
|
+
"/" << util_dthing(exp, true) << "/"
|
440
385
|
end
|
441
386
|
|
442
387
|
def process_dregx_once(exp)
|
@@ -444,11 +389,11 @@ class RubyToRuby < SexpProcessor
|
|
444
389
|
end
|
445
390
|
|
446
391
|
def process_dstr(exp)
|
447
|
-
"\"#{util_dthing(exp
|
392
|
+
"\"#{util_dthing(exp)}\""
|
448
393
|
end
|
449
394
|
|
450
395
|
def process_dsym(exp)
|
451
|
-
"
|
396
|
+
":#{process_dstr(exp)}"
|
452
397
|
end
|
453
398
|
|
454
399
|
def process_dvar(exp)
|
@@ -465,6 +410,10 @@ class RubyToRuby < SexpProcessor
|
|
465
410
|
return "#{body}\nensure\n#{indent ens}"
|
466
411
|
end
|
467
412
|
|
413
|
+
def process_evstr(exp)
|
414
|
+
process exp.shift
|
415
|
+
end
|
416
|
+
|
468
417
|
def process_false(exp)
|
469
418
|
"false"
|
470
419
|
end
|
@@ -493,8 +442,13 @@ class RubyToRuby < SexpProcessor
|
|
493
442
|
def process_for(exp)
|
494
443
|
recv = process exp.shift
|
495
444
|
iter = process exp.shift
|
496
|
-
body = process
|
497
|
-
|
445
|
+
body = exp.empty? ? nil : process(exp.shift)
|
446
|
+
|
447
|
+
result = ["for #{iter} in #{recv} do"]
|
448
|
+
result << indent(body ? body : "# do nothing")
|
449
|
+
result << "end"
|
450
|
+
|
451
|
+
result.join("\n")
|
498
452
|
end
|
499
453
|
|
500
454
|
def process_gasgn(exp)
|
@@ -510,7 +464,13 @@ class RubyToRuby < SexpProcessor
|
|
510
464
|
until exp.empty?
|
511
465
|
result << "#{process(exp.shift)} => #{process(exp.shift)}"
|
512
466
|
end
|
513
|
-
|
467
|
+
|
468
|
+
case self.context[1]
|
469
|
+
when :arglist, :argscat then
|
470
|
+
return "#{result.join(', ')}" # HACK - this will break w/ 2 hashes as args
|
471
|
+
else
|
472
|
+
return "{ #{result.join(', ')} }"
|
473
|
+
end
|
514
474
|
end
|
515
475
|
|
516
476
|
def process_iasgn(exp)
|
@@ -522,15 +482,11 @@ class RubyToRuby < SexpProcessor
|
|
522
482
|
end
|
523
483
|
end
|
524
484
|
|
525
|
-
def cond_indent_process(pt)
|
526
|
-
(pt and pt.first == :block) ? process(pt) : indent(process(pt))
|
527
|
-
end
|
528
|
-
|
529
485
|
def process_if(exp)
|
530
|
-
|
531
|
-
|
532
|
-
|
533
|
-
|
486
|
+
expand = Ruby2Ruby::ASSIGN_NODES.include? exp.first.first
|
487
|
+
c = process exp.shift
|
488
|
+
t = process exp.shift
|
489
|
+
f = process exp.shift
|
534
490
|
|
535
491
|
c = "(#{c.chomp})" if c =~ /\n/
|
536
492
|
|
@@ -561,7 +517,8 @@ class RubyToRuby < SexpProcessor
|
|
561
517
|
|
562
518
|
def process_iter(exp)
|
563
519
|
iter = process exp.shift
|
564
|
-
args =
|
520
|
+
args = exp.shift
|
521
|
+
args = (args == 0) ? '' : process(args)
|
565
522
|
body = exp.empty? ? nil : process(exp.shift)
|
566
523
|
|
567
524
|
b, e = if iter == "END" then
|
@@ -588,13 +545,9 @@ class RubyToRuby < SexpProcessor
|
|
588
545
|
result = []
|
589
546
|
result << "#{iter} #{b}"
|
590
547
|
result << " |#{args}|" if args
|
591
|
-
|
592
|
-
|
593
|
-
|
594
|
-
result << "\n"
|
595
|
-
else
|
596
|
-
result << ' '
|
597
|
-
end
|
548
|
+
result << "\n"
|
549
|
+
result << indent(body.strip)
|
550
|
+
result << "\n"
|
598
551
|
result << e
|
599
552
|
result.join
|
600
553
|
end
|
@@ -632,7 +585,7 @@ class RubyToRuby < SexpProcessor
|
|
632
585
|
rhs = exp.empty? ? nil : exp.shift
|
633
586
|
|
634
587
|
unless exp.empty? then
|
635
|
-
rhs[-1] = splat(rhs[-1])
|
588
|
+
rhs[-1] = splat(rhs[-1]) unless rhs == s(:splat)
|
636
589
|
lhs << rhs
|
637
590
|
rhs = exp.shift
|
638
591
|
end
|
@@ -650,18 +603,28 @@ class RubyToRuby < SexpProcessor
|
|
650
603
|
end
|
651
604
|
when :dasgn_curr then
|
652
605
|
lhs = [ splat(lhs.last) ]
|
606
|
+
when :splat then
|
607
|
+
lhs = [ :"*" ]
|
653
608
|
else
|
654
609
|
raise "no clue: #{lhs.inspect}"
|
655
610
|
end
|
656
611
|
|
612
|
+
if context[1] == :iter and rhs then
|
613
|
+
lhs << splat(rhs.last)
|
614
|
+
rhs = nil
|
615
|
+
end
|
616
|
+
|
657
617
|
unless rhs.nil? then
|
658
|
-
|
659
|
-
rhs = if
|
660
|
-
|
618
|
+
t = rhs.first
|
619
|
+
rhs = if t == :argscat then
|
620
|
+
rhs.shift
|
621
|
+
process_argscat(rhs)
|
661
622
|
else
|
662
|
-
|
623
|
+
r = process(rhs)
|
624
|
+
r = r[1..-2] if t != :to_ary
|
625
|
+
r
|
663
626
|
end
|
664
|
-
return "#{lhs.join(", ")} = #{rhs
|
627
|
+
return "#{lhs.join(", ")} = #{rhs}"
|
665
628
|
else
|
666
629
|
return lhs.join(", ")
|
667
630
|
end
|
@@ -689,7 +652,12 @@ class RubyToRuby < SexpProcessor
|
|
689
652
|
end
|
690
653
|
|
691
654
|
def process_next(exp)
|
692
|
-
|
655
|
+
val = exp.empty? ? nil : process(exp.shift)
|
656
|
+
if val then
|
657
|
+
"next #{val}"
|
658
|
+
else
|
659
|
+
"next"
|
660
|
+
end
|
693
661
|
end
|
694
662
|
|
695
663
|
def process_nil(exp)
|
@@ -759,12 +727,19 @@ class RubyToRuby < SexpProcessor
|
|
759
727
|
list = sexp.shift
|
760
728
|
body = sexp.shift
|
761
729
|
|
762
|
-
var = if list and
|
730
|
+
var = if list and
|
731
|
+
list.size > 1 and
|
732
|
+
[:lasgn, :dasgn, :dasgn_curr].include? list.last.first then
|
763
733
|
list.pop[1]
|
764
734
|
else
|
765
735
|
nil
|
766
736
|
end
|
767
737
|
|
738
|
+
# FIX: omg this is horrid. I should be punished
|
739
|
+
var = body.delete_at(1)[1] if
|
740
|
+
[:dasgn_curr, :dasgn].include? body[1][0] unless
|
741
|
+
var or body.nil? rescue nil
|
742
|
+
|
768
743
|
if list and list.size > 1 then
|
769
744
|
list[0] = :arglist
|
770
745
|
code << "rescue #{process(list)}"
|
@@ -799,24 +774,25 @@ class RubyToRuby < SexpProcessor
|
|
799
774
|
current = self.context[1]
|
800
775
|
case current
|
801
776
|
when :begin, :ensure, :block then
|
802
|
-
body = process
|
803
|
-
resbody = exp.empty? ?
|
777
|
+
body = (exp.first.first == :resbody) ? nil : process(exp.shift)
|
778
|
+
resbody = exp.empty? ? '' : process(exp.shift)
|
804
779
|
els = exp.empty? ? nil : process(exp.shift)
|
805
780
|
|
806
781
|
code = []
|
807
|
-
code << indent(body)
|
782
|
+
code << indent(body) if body
|
808
783
|
code << resbody
|
809
784
|
if els then
|
810
785
|
code << "else"
|
811
786
|
code << indent(els)
|
812
787
|
else
|
813
|
-
unless [:block
|
814
|
-
code << "end\n"
|
788
|
+
unless [:block].include? current then
|
789
|
+
code << "end\n" unless current == :ensure
|
815
790
|
else
|
816
|
-
r = [body, resbody.gsub(/rescue\n\s+/, 'rescue ')].join(' ')
|
791
|
+
r = [body, resbody.gsub(/rescue\n\s+/, 'rescue ')].compact.join(' ')
|
817
792
|
code = [r] if (@indent+r).size < LINE_LENGTH and r !~ /\n/
|
818
793
|
end
|
819
794
|
end
|
795
|
+
|
820
796
|
code.join("\n").chomp
|
821
797
|
else # a rescue b and others
|
822
798
|
body = process exp.shift
|
@@ -864,7 +840,11 @@ class RubyToRuby < SexpProcessor
|
|
864
840
|
end
|
865
841
|
|
866
842
|
def process_splat(exp)
|
867
|
-
|
843
|
+
if exp.empty? then
|
844
|
+
"*"
|
845
|
+
else
|
846
|
+
"*#{process(exp.shift)}"
|
847
|
+
end
|
868
848
|
end
|
869
849
|
|
870
850
|
def process_str(exp)
|
@@ -873,7 +853,7 @@ class RubyToRuby < SexpProcessor
|
|
873
853
|
|
874
854
|
def process_super(exp)
|
875
855
|
args = exp.shift
|
876
|
-
args[0] = :arglist
|
856
|
+
args[0] = :arglist if args[0] == :array
|
877
857
|
"super(#{process(args)})"
|
878
858
|
end
|
879
859
|
|
@@ -901,22 +881,22 @@ class RubyToRuby < SexpProcessor
|
|
901
881
|
"alias #{exp.shift} #{exp.shift}"
|
902
882
|
end
|
903
883
|
|
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
|
910
|
-
|
911
884
|
def process_when(exp)
|
912
885
|
src = []
|
913
886
|
|
887
|
+
if self.context[1] == :array then # ugh. matz! why not an argscat?!?
|
888
|
+
val = process(exp.shift)
|
889
|
+
exp.shift # empty body
|
890
|
+
return "*#{val}"
|
891
|
+
end
|
892
|
+
|
914
893
|
until exp.empty?
|
915
894
|
cond = process(exp.shift).to_s[1..-2]
|
916
895
|
code = indent(process(exp.shift))
|
917
896
|
code = indent "# do nothing" if code =~ /\A\s*\Z/
|
918
897
|
src << "when #{cond} then\n#{code.chomp}"
|
919
898
|
end
|
899
|
+
|
920
900
|
src.join("\n")
|
921
901
|
end
|
922
902
|
|
@@ -972,18 +952,53 @@ class RubyToRuby < SexpProcessor
|
|
972
952
|
end
|
973
953
|
|
974
954
|
############################################################
|
975
|
-
# Rewriters
|
955
|
+
# Rewriters:
|
976
956
|
|
977
|
-
def
|
978
|
-
|
979
|
-
|
980
|
-
|
981
|
-
|
957
|
+
def rewrite_rescue exp
|
958
|
+
exp = s(:begin, exp) if
|
959
|
+
context[1] == :block unless
|
960
|
+
context[2] == :scope and [:defn, :defs].include? context[3]
|
961
|
+
exp
|
982
962
|
end
|
983
963
|
|
984
964
|
############################################################
|
985
965
|
# Utility Methods:
|
986
966
|
|
967
|
+
def util_dthing(exp, regx = false)
|
968
|
+
s = []
|
969
|
+
suck = true
|
970
|
+
if suck then
|
971
|
+
x = exp.shift.gsub(/"/, '\"').gsub(/\n/, '\n')
|
972
|
+
else
|
973
|
+
x = exp.shift.dump[1..-2]
|
974
|
+
end
|
975
|
+
x.gsub!(/\//, '\/') if regx
|
976
|
+
|
977
|
+
s << x
|
978
|
+
until exp.empty?
|
979
|
+
pt = exp.shift
|
980
|
+
case pt
|
981
|
+
when Sexp then
|
982
|
+
case pt.first
|
983
|
+
when :str then
|
984
|
+
if suck then
|
985
|
+
x = pt.last.gsub(/"/, '\"').gsub(/\n/, '\n')
|
986
|
+
else
|
987
|
+
x = pt.last.dump[1..-2]
|
988
|
+
end
|
989
|
+
x.gsub!(/\//, '\/') if regx
|
990
|
+
s << x
|
991
|
+
else
|
992
|
+
s << '#{' << process(pt) << '}' # do not use interpolation here
|
993
|
+
end
|
994
|
+
else
|
995
|
+
# do nothing - yet
|
996
|
+
end
|
997
|
+
end
|
998
|
+
|
999
|
+
s.join
|
1000
|
+
end
|
1001
|
+
|
987
1002
|
def util_module_or_class(exp, is_class=false)
|
988
1003
|
s = "#{exp.shift}"
|
989
1004
|
|
@@ -1012,6 +1027,8 @@ class RubyToRuby < SexpProcessor
|
|
1012
1027
|
end
|
1013
1028
|
end
|
1014
1029
|
|
1030
|
+
RubyToRuby = Ruby2Ruby # For backwards compatibilty... TODO: remove 2008-03-28
|
1031
|
+
|
1015
1032
|
class Method
|
1016
1033
|
def with_class_and_method_name
|
1017
1034
|
if self.inspect =~ /<Method: (.*)\#(.*)>/ then
|
@@ -1031,7 +1048,7 @@ class Method
|
|
1031
1048
|
end
|
1032
1049
|
|
1033
1050
|
def to_ruby
|
1034
|
-
|
1051
|
+
Ruby2Ruby.new.process(self.to_sexp)
|
1035
1052
|
end
|
1036
1053
|
end
|
1037
1054
|
|
@@ -1048,7 +1065,7 @@ class UnboundMethod
|
|
1048
1065
|
name = ProcStoreTmp.name
|
1049
1066
|
ProcStoreTmp.send(:define_method, name, self)
|
1050
1067
|
m = ProcStoreTmp.new.method(name)
|
1051
|
-
result = m.to_ruby.sub(/def #{name}
|
1068
|
+
result = m.to_ruby.sub(/def #{name}(?:\(([^\)]*)\))?/,
|
1052
1069
|
'proc { |\1|').sub(/end\Z/, '}')
|
1053
1070
|
return result
|
1054
1071
|
end
|
data/test/test_ruby2ruby.rb
CHANGED
@@ -2,16 +2,15 @@
|
|
2
2
|
|
3
3
|
$TESTING = true
|
4
4
|
|
5
|
+
$: << 'lib'
|
6
|
+
|
5
7
|
require 'test/unit'
|
6
|
-
begin require 'rubygems'; rescue LoadError; end
|
7
8
|
require 'ruby2ruby'
|
8
9
|
require 'pt_testcase'
|
9
10
|
|
10
|
-
|
11
|
-
|
12
|
-
class TestRubyToRuby < Test::Unit::TestCase
|
11
|
+
class TestRuby2Ruby < Test::Unit::TestCase
|
13
12
|
def setup
|
14
|
-
@processor =
|
13
|
+
@processor = Ruby2Ruby.new
|
15
14
|
end
|
16
15
|
|
17
16
|
def test_proc_to_ruby
|
@@ -31,39 +30,52 @@ class TestRubyToRuby < Test::Unit::TestCase
|
|
31
30
|
|
32
31
|
def util_thingy(type)
|
33
32
|
s(type,
|
34
|
-
"blah
|
33
|
+
'blah"blah',
|
35
34
|
s(:call, s(:lit, 1), :+, s(:array, s(:lit, 1))),
|
36
35
|
s(:str, 'blah"blah/blah'))
|
37
36
|
end
|
38
37
|
|
39
38
|
def test_dregx_slash
|
40
39
|
inn = util_thingy(:dregx)
|
41
|
-
out =
|
40
|
+
out = "/blah\\\"blah#\{(1 + 1)}blah\\\"blah\\/blah/"
|
42
41
|
|
43
42
|
assert_equal out, @processor.process(inn)
|
44
43
|
|
45
44
|
r = eval(out)
|
46
|
-
assert_equal(/blah2blah"blah\/blah/, r)
|
45
|
+
assert_equal(/blah\"blah2blah\"blah\/blah/, r)
|
47
46
|
end
|
48
47
|
|
49
48
|
def test_dstr_quote
|
50
49
|
inn = util_thingy(:dstr)
|
51
|
-
out =
|
50
|
+
out = "\"blah\\\"blah#\{(1 + 1)}blah\\\"blah/blah\""
|
52
51
|
|
53
52
|
assert_equal out, @processor.process(inn)
|
54
53
|
|
55
54
|
r = eval(out)
|
56
|
-
assert_equal "blah2blah\"blah/blah", r
|
55
|
+
assert_equal "blah\"blah2blah\"blah/blah", r
|
57
56
|
end
|
58
57
|
|
59
58
|
def test_dsym_quote
|
60
59
|
inn = util_thingy(:dsym)
|
61
|
-
out =
|
60
|
+
out = ":\"blah\\\"blah#\{(1 + 1)}blah\\\"blah/blah\""
|
62
61
|
|
63
62
|
assert_equal out, @processor.process(inn)
|
64
63
|
|
65
64
|
r = eval(out)
|
66
|
-
assert_equal :"blah2blah\"blah/blah", r
|
65
|
+
assert_equal :"blah\"blah2blah\"blah/blah", r
|
66
|
+
end
|
67
|
+
|
68
|
+
def test_proc_to_sexp
|
69
|
+
p = proc { 1 + 1 }
|
70
|
+
s = [:proc, nil, [:call, [:lit, 1], :+, [:array, [:lit, 1]]]]
|
71
|
+
assert_equal s, p.to_sexp
|
72
|
+
end
|
73
|
+
|
74
|
+
def test_unbound_method_to_ruby
|
75
|
+
r = "proc { ||\n p = proc { (1 + 1) }\n s = [:proc, nil, [:call, [:lit, 1], :+, [:array, [:lit, 1]]]]\n assert_equal(s, p.to_sexp)\n}"
|
76
|
+
m = self.class.instance_method(:test_proc_to_sexp)
|
77
|
+
|
78
|
+
assert_equal r, m.to_ruby
|
67
79
|
end
|
68
80
|
|
69
81
|
eval ParseTreeTestCase.testcases.map { |node, data|
|
@@ -85,25 +97,34 @@ end
|
|
85
97
|
# Converts a +target+ using a +processor+ and converts +target+ name
|
86
98
|
# in the source adding +gen+ to allow easy renaming.
|
87
99
|
|
88
|
-
def morph_and_eval(processor, target, gen)
|
100
|
+
def morph_and_eval(processor, target, gen, n)
|
89
101
|
begin
|
90
102
|
old_name = target.name
|
91
103
|
new_name = target.name.sub(/\d*$/, gen.to_s)
|
92
104
|
ruby = processor.translate(target).sub(old_name, new_name)
|
105
|
+
|
93
106
|
eval ruby
|
94
107
|
target.constants.each do |constant|
|
95
108
|
eval "#{new_name}::#{constant} = #{old_name}::#{constant}"
|
96
109
|
end
|
97
110
|
rescue SyntaxError => e
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
111
|
+
warn "Self-Translation Generation #{n} failed:"
|
112
|
+
warn "#{e.class}: #{e.message}"
|
113
|
+
warn ""
|
114
|
+
warn ruby
|
115
|
+
warn ""
|
102
116
|
rescue => e
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
117
|
+
warn "Self-Translation Generation #{n} failed:"
|
118
|
+
warn "#{e.class}: #{e.message}"
|
119
|
+
warn ""
|
120
|
+
warn ruby
|
121
|
+
warn ""
|
122
|
+
else
|
123
|
+
begin
|
124
|
+
yield if block_given?
|
125
|
+
rescue
|
126
|
+
# probably already handled
|
127
|
+
end
|
107
128
|
end
|
108
129
|
end
|
109
130
|
|
@@ -116,28 +137,30 @@ end
|
|
116
137
|
# s
|
117
138
|
# t new 2 3
|
118
139
|
|
119
|
-
# Self-Translation: 1st Generation - morph
|
120
|
-
morph_and_eval
|
121
|
-
class
|
122
|
-
|
123
|
-
|
140
|
+
# Self-Translation: 1st Generation - morph Ruby2Ruby using Ruby2Ruby
|
141
|
+
morph_and_eval Ruby2Ruby, Ruby2Ruby, 2, 1 do
|
142
|
+
class TestRuby2Ruby1 < TestRuby2Ruby
|
143
|
+
def setup
|
144
|
+
@processor = Ruby2Ruby2.new
|
145
|
+
end
|
124
146
|
end
|
125
147
|
end
|
126
148
|
|
127
|
-
# Self-Translation: 2nd Generation - morph
|
128
|
-
morph_and_eval
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
149
|
+
# Self-Translation: 2nd Generation - morph TestRuby2Ruby using Ruby2Ruby
|
150
|
+
morph_and_eval Ruby2Ruby, TestRuby2Ruby, 2, 2 do
|
151
|
+
# Self-Translation: 3rd Generation - test Ruby2Ruby2 with TestRuby2Ruby1
|
152
|
+
class TestRuby2Ruby3 < TestRuby2Ruby2
|
153
|
+
def setup
|
154
|
+
@processor = Ruby2Ruby2.new
|
155
|
+
end
|
134
156
|
end
|
135
157
|
end
|
136
158
|
|
137
159
|
# Self-Translation: 4th (and final) Generation - fully circular
|
138
|
-
morph_and_eval
|
139
|
-
class
|
140
|
-
|
141
|
-
|
160
|
+
morph_and_eval(Ruby2Ruby2, Ruby2Ruby2, 3, 4) do
|
161
|
+
class TestRuby2Ruby4 < TestRuby2Ruby3
|
162
|
+
def setup
|
163
|
+
@processor = Ruby2Ruby3.new
|
164
|
+
end
|
142
165
|
end
|
143
|
-
end
|
166
|
+
end rescue nil # for Ruby2Ruby2 at the top
|
metadata
CHANGED
@@ -1,72 +1,80 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
|
-
rubygems_version: 0.9.4
|
3
|
-
specification_version: 1
|
4
2
|
name: ruby2ruby
|
5
3
|
version: !ruby/object:Gem::Version
|
6
|
-
version: 1.1.
|
7
|
-
date: 2007-08-21 00:00:00 -07:00
|
8
|
-
summary: ruby2ruby provides a means of generating pure ruby code easily from ParseTree's Sexps.
|
9
|
-
require_paths:
|
10
|
-
- lib
|
11
|
-
email: ryand-ruby@zenspider.com
|
12
|
-
homepage: http://seattlerb.rubyforge.org/
|
13
|
-
rubyforge_project: seattlerb
|
14
|
-
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.
|
15
|
-
autorequire:
|
16
|
-
default_executable:
|
17
|
-
bindir: bin
|
18
|
-
has_rdoc: true
|
19
|
-
required_ruby_version: !ruby/object:Gem::Version::Requirement
|
20
|
-
requirements:
|
21
|
-
- - ">"
|
22
|
-
- !ruby/object:Gem::Version
|
23
|
-
version: 0.0.0
|
24
|
-
version:
|
4
|
+
version: 1.1.8
|
25
5
|
platform: ruby
|
26
|
-
signing_key:
|
27
|
-
cert_chain:
|
28
|
-
post_install_message:
|
29
6
|
authors:
|
30
7
|
- Ryan Davis
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
- README.txt
|
35
|
-
- Rakefile
|
36
|
-
- bin/r2r_show
|
37
|
-
- lib/ruby2ruby.rb
|
38
|
-
- test/test_ruby2ruby.rb
|
39
|
-
test_files:
|
40
|
-
- test/test_ruby2ruby.rb
|
41
|
-
rdoc_options:
|
42
|
-
- --main
|
43
|
-
- README.txt
|
44
|
-
extra_rdoc_files:
|
45
|
-
- History.txt
|
46
|
-
- Manifest.txt
|
47
|
-
- README.txt
|
48
|
-
executables:
|
49
|
-
- r2r_show
|
50
|
-
extensions: []
|
51
|
-
|
52
|
-
requirements: []
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
53
11
|
|
12
|
+
date: 2007-12-22 00:00:00 -08:00
|
13
|
+
default_executable:
|
54
14
|
dependencies:
|
55
15
|
- !ruby/object:Gem::Dependency
|
56
16
|
name: ParseTree
|
57
17
|
version_requirement:
|
58
|
-
version_requirements: !ruby/object:Gem::
|
18
|
+
version_requirements: !ruby/object:Gem::Requirement
|
59
19
|
requirements:
|
60
|
-
- - "
|
20
|
+
- - ">="
|
61
21
|
- !ruby/object:Gem::Version
|
62
|
-
version: 0
|
22
|
+
version: "0"
|
63
23
|
version:
|
64
24
|
- !ruby/object:Gem::Dependency
|
65
25
|
name: hoe
|
66
26
|
version_requirement:
|
67
|
-
version_requirements: !ruby/object:Gem::
|
27
|
+
version_requirements: !ruby/object:Gem::Requirement
|
68
28
|
requirements:
|
69
29
|
- - ">="
|
70
30
|
- !ruby/object:Gem::Version
|
71
|
-
version: 1.
|
31
|
+
version: 1.4.0
|
72
32
|
version:
|
33
|
+
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
|
+
email: ryand-ruby@zenspider.com
|
35
|
+
executables:
|
36
|
+
- r2r_show
|
37
|
+
extensions: []
|
38
|
+
|
39
|
+
extra_rdoc_files:
|
40
|
+
- History.txt
|
41
|
+
- Manifest.txt
|
42
|
+
- README.txt
|
43
|
+
files:
|
44
|
+
- .autotest
|
45
|
+
- History.txt
|
46
|
+
- Manifest.txt
|
47
|
+
- README.txt
|
48
|
+
- Rakefile
|
49
|
+
- bin/r2r_show
|
50
|
+
- lib/ruby2ruby.rb
|
51
|
+
- test/test_ruby2ruby.rb
|
52
|
+
has_rdoc: true
|
53
|
+
homepage: http://seattlerb.rubyforge.org/
|
54
|
+
post_install_message:
|
55
|
+
rdoc_options:
|
56
|
+
- --main
|
57
|
+
- README.txt
|
58
|
+
require_paths:
|
59
|
+
- lib
|
60
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
61
|
+
requirements:
|
62
|
+
- - ">="
|
63
|
+
- !ruby/object:Gem::Version
|
64
|
+
version: "0"
|
65
|
+
version:
|
66
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
67
|
+
requirements:
|
68
|
+
- - ">="
|
69
|
+
- !ruby/object:Gem::Version
|
70
|
+
version: "0"
|
71
|
+
version:
|
72
|
+
requirements: []
|
73
|
+
|
74
|
+
rubyforge_project: seattlerb
|
75
|
+
rubygems_version: 1.0.1
|
76
|
+
signing_key:
|
77
|
+
specification_version: 2
|
78
|
+
summary: ruby2ruby provides a means of generating pure ruby code easily from ParseTree's Sexps.
|
79
|
+
test_files:
|
80
|
+
- test/test_ruby2ruby.rb
|