ParseTree 2.2.0 → 3.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.autotest +16 -0
- data/History.txt +48 -0
- data/Manifest.txt +3 -6
- data/Rakefile +8 -5
- data/lib/parse_tree.rb +67 -11
- data/lib/parse_tree_extensions.rb +69 -0
- data/lib/unified_ruby.rb +170 -42
- data/test/pt_testcase.rb +4240 -2399
- data/test/test_parse_tree.rb +52 -20
- data/test/test_parse_tree_extensions.rb +39 -0
- data/test/test_unified_ruby.rb +292 -234
- metadata +20 -11
- data/lib/composite_sexp_processor.rb +0 -49
- data/lib/sexp.rb +0 -282
- data/lib/sexp_processor.rb +0 -336
- data/test/test_composite_sexp_processor.rb +0 -70
- data/test/test_sexp.rb +0 -313
- data/test/test_sexp_processor.rb +0 -297
data/.autotest
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
# -*- ruby -*-
|
2
|
+
|
3
|
+
require 'autotest/restart'
|
4
|
+
|
5
|
+
Autotest.add_hook :initialize do |at|
|
6
|
+
at.libs << ":../../sexp_processor/dev/lib"
|
7
|
+
at.extra_files << "test/pt_testcase.rb"
|
8
|
+
|
9
|
+
%w(TestRawParseTree).each do |klass|
|
10
|
+
at.extra_class_map[klass] = "test/test_parse_tree.rb"
|
11
|
+
end
|
12
|
+
|
13
|
+
at.add_mapping(/pt_testcase/) do |f, _|
|
14
|
+
at.files_matching(/test_.*rb$/)
|
15
|
+
end
|
16
|
+
end
|
data/History.txt
CHANGED
@@ -1,3 +1,51 @@
|
|
1
|
+
=== 3.0.0 / 2008-10-22
|
2
|
+
|
3
|
+
* 3 major enhancements:
|
4
|
+
|
5
|
+
* Split out sexp_processor project.
|
6
|
+
* ParseTree#process outputs a UnifiedRuby parse tree.
|
7
|
+
* Switched all ParseTree tests to RawParseTree tests.
|
8
|
+
* Added ParseTree tests.
|
9
|
+
* Added UnifiedRuby#process.
|
10
|
+
|
11
|
+
* 28 minor enhancements:
|
12
|
+
|
13
|
+
* PTTC: Added a comprehensive suite of tests for every combo of defn args.
|
14
|
+
* PTTC: Added a ton of new tests.
|
15
|
+
* PTTC: Added extra tests for mri verbose flag testing (horrid horrid bug imhfo)
|
16
|
+
* PTTC: Don't generate tests if class has "TestCase" in the class name.
|
17
|
+
* PTTC: Made self.previous more overridable.
|
18
|
+
* PTTC: Now all tests that have "mri_verbose_flag" activate $VERBOSE
|
19
|
+
* PTTC: Officially added clone_same phase to generate_tests
|
20
|
+
* PTTC: Refactored test generation to make subclasses more flexible.
|
21
|
+
* PTTC: Refactored to use new add_tests. Much much cleaner.
|
22
|
+
* PTTC: Removed Unique from PTTC... subclasses need to deal with this
|
23
|
+
* PTTC: Removed some stupid tests.
|
24
|
+
* PTTC: Renamed a bunch of tests to be more uniform.
|
25
|
+
* UR: Added rewrite_attrasgn to normalize arg array into arglist.
|
26
|
+
* UR: Added rewrite_op_asgn1 to ensure the arglist is an arglist.
|
27
|
+
* UR: Flattened resbodies in rescue node.
|
28
|
+
* UR: Flattened super and yield args yet, deal with array arg properly.
|
29
|
+
* UR: Handle yield(*ary) properly.
|
30
|
+
* UR: Nuked argspush.
|
31
|
+
* UR: Removed begin node from unified sexps.
|
32
|
+
* UR: Removed block from rewritten resbody if only 1 element.
|
33
|
+
* UR: Removed dasgn, dasgn_curr, and dvar nodes.
|
34
|
+
* UR: Removed s(:block_arg, :block) in favor of :"&block"
|
35
|
+
* UR: Rewrote argscat to be a splat inside an array.
|
36
|
+
* UR: Rewrote block_pass into arglist of inner call/super.
|
37
|
+
* UR: Rewrote call to ALWAYS have an argslist (no more splat as arglist).
|
38
|
+
* UR: Rewrote rewrite_resbody from scratch... MUUCH cleaner.
|
39
|
+
* UR: zarray -> array
|
40
|
+
* Used Hoe#add_include_dirs to clean up rakefile.
|
41
|
+
* Moved PT dependent code from ruby2ruby to here (eg Proc#to_sexp & friends).
|
42
|
+
|
43
|
+
* 2 bug fixes:
|
44
|
+
|
45
|
+
* UR: Fixed a bug with resbody that starts with an lasgn.
|
46
|
+
* UR: Fixed args for attrset
|
47
|
+
* Fixed export of symbols to work across platforms.
|
48
|
+
|
1
49
|
=== 2.2.0 / 2008-06-09
|
2
50
|
|
3
51
|
* 18 minor enhancements:
|
data/Manifest.txt
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
.autotest
|
1
2
|
History.txt
|
2
3
|
Manifest.txt
|
3
4
|
README.txt
|
@@ -7,18 +8,14 @@ bin/parse_tree_audit
|
|
7
8
|
bin/parse_tree_deps
|
8
9
|
bin/parse_tree_show
|
9
10
|
demo/printer.rb
|
10
|
-
lib/composite_sexp_processor.rb
|
11
11
|
lib/parse_tree.rb
|
12
|
-
lib/
|
13
|
-
lib/sexp_processor.rb
|
12
|
+
lib/parse_tree_extensions.rb
|
14
13
|
lib/unified_ruby.rb
|
15
14
|
lib/unique.rb
|
16
15
|
test/pt_testcase.rb
|
17
16
|
test/something.rb
|
18
17
|
test/test_all.rb
|
19
|
-
test/test_composite_sexp_processor.rb
|
20
18
|
test/test_parse_tree.rb
|
21
|
-
test/
|
22
|
-
test/test_sexp_processor.rb
|
19
|
+
test/test_parse_tree_extensions.rb
|
23
20
|
test/test_unified_ruby.rb
|
24
21
|
validate.sh
|
data/Rakefile
CHANGED
@@ -3,7 +3,11 @@
|
|
3
3
|
require 'rubygems'
|
4
4
|
require 'hoe'
|
5
5
|
|
6
|
-
|
6
|
+
Hoe.add_include_dirs("../../RubyInline/dev/lib",
|
7
|
+
"../../sexp_processor/dev/lib",
|
8
|
+
"../../ZenTest/dev/lib",
|
9
|
+
"lib")
|
10
|
+
|
7
11
|
require './lib/parse_tree.rb'
|
8
12
|
|
9
13
|
Hoe.new("ParseTree", ParseTree::VERSION) do |pt|
|
@@ -12,14 +16,13 @@ Hoe.new("ParseTree", ParseTree::VERSION) do |pt|
|
|
12
16
|
pt.developer('Ryan Davis', 'ryand-ruby@zenspider.com')
|
13
17
|
|
14
18
|
pt.clean_globs << File.expand_path("~/.ruby_inline")
|
15
|
-
pt.extra_deps << ['RubyInline',
|
19
|
+
pt.extra_deps << ['RubyInline', '>= 3.7.0']
|
20
|
+
pt.extra_deps << ['SexpProcessor', '>= 3.0.0']
|
16
21
|
pt.spec_extras[:require_paths] = proc { |paths| paths << 'test' }
|
17
22
|
|
18
|
-
pt.multiruby_skip << "
|
23
|
+
pt.multiruby_skip << "mri_rel_1_9" << "rubinius" << "mri_trunk"
|
19
24
|
end
|
20
25
|
|
21
|
-
Hoe::RUBY_FLAGS.sub! /-I/, '-I../../RubyInline/dev/lib:test:'
|
22
|
-
|
23
26
|
desc 'Run in gdb'
|
24
27
|
task :debug do
|
25
28
|
puts "RUN: r -d #{Hoe::RUBY_FLAGS} test/test_all.rb #{Hoe::FILTER}"
|
data/lib/parse_tree.rb
CHANGED
@@ -7,6 +7,7 @@ raise LoadError, "ParseTree isn't needed with rubinius" if
|
|
7
7
|
|
8
8
|
require 'rubygems'
|
9
9
|
require 'inline'
|
10
|
+
require 'unified_ruby'
|
10
11
|
|
11
12
|
class Module
|
12
13
|
def modules
|
@@ -40,9 +41,9 @@ end
|
|
40
41
|
# [:args],
|
41
42
|
# [:return, [:call, [:lit, 1], "+", [:array, [:lit, 1]]]]]]]]]
|
42
43
|
|
43
|
-
class
|
44
|
+
class RawParseTree
|
44
45
|
|
45
|
-
VERSION = '
|
46
|
+
VERSION = '3.0.0'
|
46
47
|
|
47
48
|
##
|
48
49
|
# Front end translation method.
|
@@ -288,7 +289,7 @@ class ParseTree
|
|
288
289
|
# 1) Get me a login on your box so I can repro this and get it fixed.
|
289
290
|
# 2) Fix it and send me the patch
|
290
291
|
# 3) (quick, but dirty and bad), comment out the following line:
|
291
|
-
builder.add_compile_flags "-Werror"
|
292
|
+
builder.add_compile_flags "-Werror" unless RUBY_PLATFORM =~ /mswin/
|
292
293
|
|
293
294
|
builder.prefix %{
|
294
295
|
#define nd_3rd u3.node
|
@@ -350,7 +351,7 @@ void add_to_parse_tree(VALUE self, VALUE ary, NODE * n, ID * locals) {
|
|
350
351
|
static int masgn_level = 0;
|
351
352
|
|
352
353
|
if (NIL_P(node_names)) {
|
353
|
-
node_names = rb_const_get_at(rb_path2class("
|
354
|
+
node_names = rb_const_get_at(rb_path2class("RawParseTree"),rb_intern("NODE_NAMES"));
|
354
355
|
}
|
355
356
|
|
356
357
|
if (!node) return;
|
@@ -508,15 +509,27 @@ again:
|
|
508
509
|
|
509
510
|
case NODE_BREAK:
|
510
511
|
case NODE_NEXT:
|
512
|
+
if (node->nd_stts)
|
513
|
+
add_to_parse_tree(self, current, node->nd_stts, locals);
|
514
|
+
|
515
|
+
break;
|
516
|
+
|
511
517
|
case NODE_YIELD:
|
512
518
|
if (node->nd_stts)
|
513
519
|
add_to_parse_tree(self, current, node->nd_stts, locals);
|
520
|
+
|
521
|
+
if (node->nd_stts
|
522
|
+
&& (nd_type(node->nd_stts) == NODE_ARRAY
|
523
|
+
|| nd_type(node->nd_stts) == NODE_ZARRAY)
|
524
|
+
&& !node->nd_state)
|
525
|
+
rb_ary_push(current, Qtrue);
|
526
|
+
|
514
527
|
break;
|
515
528
|
|
516
529
|
case NODE_RESCUE:
|
517
|
-
|
518
|
-
|
519
|
-
|
530
|
+
add_to_parse_tree(self, current, node->nd_1st, locals);
|
531
|
+
add_to_parse_tree(self, current, node->nd_2nd, locals);
|
532
|
+
add_to_parse_tree(self, current, node->nd_3rd, locals);
|
520
533
|
break;
|
521
534
|
|
522
535
|
/*
|
@@ -665,15 +678,25 @@ again:
|
|
665
678
|
|
666
679
|
case NODE_MASGN:
|
667
680
|
masgn_level++;
|
668
|
-
|
681
|
+
if (node->nd_head) {
|
682
|
+
add_to_parse_tree(self, current, node->nd_head, locals);
|
683
|
+
} else {
|
684
|
+
rb_ary_push(current, Qnil);
|
685
|
+
}
|
669
686
|
if (node->nd_args) {
|
670
687
|
if (node->nd_args != (NODE *)-1) {
|
671
688
|
add_to_parse_tree(self, current, node->nd_args, locals);
|
672
689
|
} else {
|
673
690
|
rb_ary_push(current, wrap_into_node("splat", 0));
|
674
691
|
}
|
692
|
+
} else {
|
693
|
+
rb_ary_push(current, Qnil);
|
694
|
+
}
|
695
|
+
if (node->nd_value) {
|
696
|
+
add_to_parse_tree(self, current, node->nd_value, locals);
|
697
|
+
} else {
|
698
|
+
rb_ary_push(current, Qnil);
|
675
699
|
}
|
676
|
-
add_to_parse_tree(self, current, node->nd_value, locals);
|
677
700
|
masgn_level--;
|
678
701
|
break;
|
679
702
|
|
@@ -1051,9 +1074,12 @@ static VALUE parse_tree_for_meth(VALUE klass, VALUE method, VALUE is_cls_meth) {
|
|
1051
1074
|
}
|
1052
1075
|
}
|
1053
1076
|
|
1054
|
-
|
1077
|
+
extern_mode = RUBY_PLATFORM =~ /mswin/ ? 'RUBY_EXTERN' : 'extern'
|
1078
|
+
builder.prefix " #{extern_mode} NODE *ruby_eval_tree_begin; " \
|
1055
1079
|
if RUBY_VERSION < '1.9.0'
|
1056
1080
|
|
1081
|
+
# FIXME: ruby_in_eval is not properly exported across platforms
|
1082
|
+
# http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-core/13558
|
1057
1083
|
builder.c %Q{
|
1058
1084
|
static VALUE parse_tree_for_str(VALUE source, VALUE filename, VALUE line) {
|
1059
1085
|
VALUE tmp;
|
@@ -1094,4 +1120,34 @@ static VALUE parse_tree_for_str(VALUE source, VALUE filename, VALUE line) {
|
|
1094
1120
|
}
|
1095
1121
|
|
1096
1122
|
end # inline call
|
1097
|
-
end #
|
1123
|
+
end # RawParseTree class
|
1124
|
+
|
1125
|
+
class ParseTree < RawParseTree
|
1126
|
+
##
|
1127
|
+
# Initializes a ParseTree instance. Includes newline nodes if
|
1128
|
+
# +include_newlines+ which defaults to +$DEBUG+.
|
1129
|
+
|
1130
|
+
def initialize(include_newlines=$DEBUG)
|
1131
|
+
super
|
1132
|
+
@unifier = Unifier.new
|
1133
|
+
end
|
1134
|
+
|
1135
|
+
##
|
1136
|
+
# Main driver for ParseTree. Returns a Sexp instance containing the
|
1137
|
+
# AST representing the input given. This is a UnifiedRuby sexp, not
|
1138
|
+
# a raw sexp from ruby. If you want raw, use the old
|
1139
|
+
# parse_tree_for_xxx methods... Please tell me if/why you want raw,
|
1140
|
+
# I'd like to know so I can justify keeping the code around.
|
1141
|
+
|
1142
|
+
def process(input, verbose = nil, file = "(string)", line = -1)
|
1143
|
+
case input
|
1144
|
+
when Array then
|
1145
|
+
@unifier.process(input)
|
1146
|
+
when String then
|
1147
|
+
pt = self.parse_tree_for_string(input, file, line, verbose).first
|
1148
|
+
@unifier.process(pt)
|
1149
|
+
else
|
1150
|
+
raise ArgumentError, "Unknown input type #{input.inspect}"
|
1151
|
+
end
|
1152
|
+
end
|
1153
|
+
end
|
@@ -0,0 +1,69 @@
|
|
1
|
+
class Method
|
2
|
+
def with_class_and_method_name
|
3
|
+
if self.inspect =~ /<Method: (.*)\#(.*)>/ then
|
4
|
+
klass = eval $1
|
5
|
+
method = $2.intern
|
6
|
+
raise "Couldn't determine class from #{self.inspect}" if klass.nil?
|
7
|
+
return yield(klass, method)
|
8
|
+
else
|
9
|
+
raise "Can't parse signature: #{self.inspect}"
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
def to_sexp
|
14
|
+
require 'parse_tree'
|
15
|
+
require 'unified_ruby'
|
16
|
+
parser = ParseTree.new(false)
|
17
|
+
unifier = Unifier.new
|
18
|
+
with_class_and_method_name do |klass, method|
|
19
|
+
old_sexp = parser.parse_tree_for_method(klass, method)
|
20
|
+
unifier.process(old_sexp) # HACK
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def to_ruby
|
25
|
+
sexp = self.to_sexp
|
26
|
+
Ruby2Ruby.new.process sexp
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
class ProcStoreTmp
|
31
|
+
@@n = 0
|
32
|
+
def self.new_name
|
33
|
+
@@n += 1
|
34
|
+
return :"myproc#{@@n}"
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
class UnboundMethod
|
39
|
+
def to_ruby
|
40
|
+
name = ProcStoreTmp.new_name
|
41
|
+
ProcStoreTmp.send(:define_method, name, self)
|
42
|
+
m = ProcStoreTmp.new.method(name)
|
43
|
+
result = m.to_ruby.sub(/def #{name}(?:\(([^\)]*)\))?/,
|
44
|
+
'proc { |\1|').sub(/end\Z/, '}')
|
45
|
+
return result
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
class Proc
|
50
|
+
def to_method
|
51
|
+
name = ProcStoreTmp.new_name
|
52
|
+
ProcStoreTmp.send(:define_method, name, self)
|
53
|
+
ProcStoreTmp.new.method(name)
|
54
|
+
end
|
55
|
+
|
56
|
+
def to_sexp
|
57
|
+
sexp = self.to_method.to_sexp
|
58
|
+
body = sexp.scope.block
|
59
|
+
args = sexp.args
|
60
|
+
args = nil if args.size == 1
|
61
|
+
body = body[1] if body.size == 2
|
62
|
+
|
63
|
+
s(:iter, s(:call, nil, :proc, s(:arglist)), args, body)
|
64
|
+
end
|
65
|
+
|
66
|
+
def to_ruby
|
67
|
+
Ruby2Ruby.new.process(self.to_sexp).sub(/^\Aproc do/, 'proc {').sub(/end\Z/, '}')
|
68
|
+
end
|
69
|
+
end
|
data/lib/unified_ruby.rb
CHANGED
@@ -1,17 +1,37 @@
|
|
1
|
+
require 'sexp_processor'
|
1
2
|
|
2
3
|
$TESTING ||= false
|
3
4
|
|
4
5
|
module UnifiedRuby
|
6
|
+
def process exp
|
7
|
+
exp = Sexp.from_array exp unless Sexp === exp or exp.nil?
|
8
|
+
super
|
9
|
+
end
|
10
|
+
|
11
|
+
def rewrite_attrasgn(exp)
|
12
|
+
last = exp.last
|
13
|
+
|
14
|
+
if Sexp === last then
|
15
|
+
last[0] = :arglist if last[0] == :array
|
16
|
+
else
|
17
|
+
exp << s(:arglist)
|
18
|
+
end
|
19
|
+
|
20
|
+
exp
|
21
|
+
end
|
22
|
+
|
5
23
|
def rewrite_bmethod(exp)
|
6
24
|
exp[0] = :scope
|
7
25
|
|
26
|
+
has_splat = exp.masgn.array.splat.lasgn rescue false
|
27
|
+
|
8
28
|
args =
|
9
|
-
if
|
10
|
-
arg = exp.masgn(true).
|
29
|
+
if has_splat then
|
30
|
+
arg = exp.masgn(true).array.splat.lasgn.sexp_body
|
11
31
|
raise "nope: #{arg.size}" unless arg.size == 1
|
12
32
|
s(:args, :"*#{arg.last}")
|
13
33
|
else
|
14
|
-
args = exp.
|
34
|
+
args = exp.lasgn(true)
|
15
35
|
if args then
|
16
36
|
s(:args, *args.sexp_body)
|
17
37
|
else
|
@@ -27,6 +47,35 @@ module UnifiedRuby
|
|
27
47
|
exp
|
28
48
|
end
|
29
49
|
|
50
|
+
def rewrite_argscat exp
|
51
|
+
_, ary, val = exp
|
52
|
+
ary = s(:array, ary) unless ary.first == :array
|
53
|
+
ary << s(:splat, val)
|
54
|
+
end
|
55
|
+
|
56
|
+
def rewrite_argspush exp
|
57
|
+
exp[0] = :arglist
|
58
|
+
exp
|
59
|
+
end
|
60
|
+
|
61
|
+
def rewrite_block_pass exp
|
62
|
+
if exp.size == 3 then
|
63
|
+
_, block, recv = exp
|
64
|
+
case recv.first
|
65
|
+
when :super then
|
66
|
+
recv << s(:block_pass, block)
|
67
|
+
exp = recv
|
68
|
+
when :call then
|
69
|
+
recv.last << s(:block_pass, block)
|
70
|
+
exp = recv
|
71
|
+
else
|
72
|
+
raise "huh?: #{recv.inspect}"
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
exp
|
77
|
+
end
|
78
|
+
|
30
79
|
def rewrite_call(exp)
|
31
80
|
args = exp.last
|
32
81
|
case args
|
@@ -37,7 +86,7 @@ module UnifiedRuby
|
|
37
86
|
when :array, :arglist then
|
38
87
|
args[0] = :arglist
|
39
88
|
when :argscat, :splat then
|
40
|
-
|
89
|
+
exp[-1] = s(:arglist, args)
|
41
90
|
else
|
42
91
|
raise "unknown type in call #{args.first.inspect} in #{exp.inspect}"
|
43
92
|
end
|
@@ -49,6 +98,13 @@ module UnifiedRuby
|
|
49
98
|
exp
|
50
99
|
end
|
51
100
|
|
101
|
+
def rewrite_dasgn(exp)
|
102
|
+
exp[0] = :lasgn
|
103
|
+
exp
|
104
|
+
end
|
105
|
+
|
106
|
+
alias :rewrite_dasgn_curr :rewrite_dasgn
|
107
|
+
|
52
108
|
##
|
53
109
|
# :defn is one of the most complex of all the ASTs in ruby. We do
|
54
110
|
# one of 3 different translations:
|
@@ -91,10 +147,23 @@ module UnifiedRuby
|
|
91
147
|
|
92
148
|
# move block_arg up and in
|
93
149
|
block_arg = exp.scope.block.block_arg(true) rescue nil
|
94
|
-
|
150
|
+
if block_arg
|
151
|
+
block = args.block(true)
|
152
|
+
args << :"&#{block_arg.last}"
|
153
|
+
args << block if block
|
154
|
+
end
|
95
155
|
|
96
156
|
# patch up attr_accessor methods
|
97
|
-
|
157
|
+
if weirdo then
|
158
|
+
case
|
159
|
+
when exp.ivar then
|
160
|
+
exp.insert 2, s(:args)
|
161
|
+
when exp.attrset then
|
162
|
+
exp.insert 2, s(:args, :arg)
|
163
|
+
else
|
164
|
+
raise "unknown wierdo: #{wierdo.inpsect}"
|
165
|
+
end
|
166
|
+
end
|
98
167
|
|
99
168
|
exp
|
100
169
|
end
|
@@ -119,6 +188,11 @@ module UnifiedRuby
|
|
119
188
|
exp.shift # scope / block / body
|
120
189
|
end
|
121
190
|
|
191
|
+
def rewrite_dvar(exp)
|
192
|
+
exp[0] = :lvar
|
193
|
+
exp
|
194
|
+
end
|
195
|
+
|
122
196
|
def rewrite_fcall(exp)
|
123
197
|
exp[0] = :call
|
124
198
|
exp.insert 1, nil
|
@@ -127,55 +201,105 @@ module UnifiedRuby
|
|
127
201
|
rewrite_call(exp)
|
128
202
|
end
|
129
203
|
|
130
|
-
def
|
131
|
-
|
204
|
+
def rewrite_masgn(exp)
|
205
|
+
raise "wtf: #{exp}" unless exp.size == 4
|
132
206
|
|
133
|
-
|
134
|
-
while exp and exp.first == :resbody do
|
135
|
-
code << exp.shift
|
136
|
-
list = exp.shift || s(:array)
|
137
|
-
body = exp.empty? ? nil : exp.shift
|
138
|
-
exp = exp.empty? ? nil : exp.shift
|
207
|
+
t, lhs, lhs_splat, rhs = exp
|
139
208
|
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
list << body
|
147
|
-
body = nil
|
148
|
-
when :block then
|
149
|
-
# TODO: check that it is assigning $!
|
150
|
-
list << body.delete_at(1) if body[1].first == :lasgn
|
151
|
-
else
|
152
|
-
# do nothing (expression form)
|
153
|
-
end if body
|
209
|
+
lhs ||= s(:array)
|
210
|
+
|
211
|
+
if lhs_splat then
|
212
|
+
lhs_splat = s(:splat, lhs_splat) unless lhs_splat[0] == :splat
|
213
|
+
lhs << lhs_splat
|
214
|
+
end
|
154
215
|
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
216
|
+
s(t, lhs, rhs).compact
|
217
|
+
end
|
218
|
+
|
219
|
+
def rewrite_op_asgn1(exp)
|
220
|
+
exp[2][0] = :arglist # if exp[2][0] == :array
|
221
|
+
exp
|
222
|
+
end
|
223
|
+
|
224
|
+
def rewrite_rescue(exp)
|
225
|
+
# SKETCHY HACK return exp if exp.size > 4
|
226
|
+
ignored = exp.shift
|
227
|
+
body = exp.shift unless exp.first.first == :resbody
|
228
|
+
resbody = exp.shift
|
229
|
+
els = exp.shift unless exp.first.first == :resbody unless exp.empty?
|
230
|
+
rest = exp.empty? ? nil : exp # graceful re-rewriting (see rewrite_begin)
|
231
|
+
|
232
|
+
resbodies = []
|
233
|
+
|
234
|
+
unless rest then
|
235
|
+
while resbody do
|
236
|
+
resbodies << resbody
|
237
|
+
resbody = resbody.resbody(true)
|
238
|
+
end
|
239
|
+
|
240
|
+
resbodies.each do |resbody|
|
241
|
+
if resbody[2] && resbody[2][0] == :block && resbody[2].size == 2 then
|
242
|
+
resbody[2] = resbody[2][-1]
|
243
|
+
end
|
159
244
|
end
|
245
|
+
else
|
246
|
+
resbodies = [resbody] + rest
|
160
247
|
end
|
161
248
|
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
249
|
+
resbodies << els if els
|
250
|
+
|
251
|
+
s(:rescue, body, *resbodies).compact
|
252
|
+
end
|
253
|
+
|
254
|
+
def rewrite_resbody(exp)
|
255
|
+
exp[1] ||= s(:array) # no args
|
256
|
+
|
257
|
+
body = exp[2]
|
258
|
+
if body then
|
259
|
+
case body.first
|
260
|
+
when :lasgn, :iasgn then
|
261
|
+
exp[1] << exp.delete_at(2) if body[-1] == s(:gvar, :$!)
|
262
|
+
when :block then
|
263
|
+
exp[1] << body.delete_at(1) if [:lasgn, :iasgn].include?(body[1][0]) &&
|
264
|
+
body[1][-1] == s(:gvar, :$!)
|
265
|
+
end
|
170
266
|
end
|
171
267
|
|
172
|
-
|
268
|
+
exp << nil if exp.size == 2 # no body
|
269
|
+
|
270
|
+
exp
|
271
|
+
end
|
272
|
+
|
273
|
+
def rewrite_begin(exp)
|
274
|
+
raise "wtf: #{exp.inspect}" if exp.size > 2
|
275
|
+
exp.last
|
173
276
|
end
|
174
277
|
|
175
278
|
def rewrite_vcall(exp)
|
176
279
|
exp.push nil
|
177
280
|
rewrite_fcall(exp)
|
178
281
|
end
|
282
|
+
|
283
|
+
def rewrite_yield(exp)
|
284
|
+
# Literal array in yield, not args.
|
285
|
+
if exp.size == 3 and exp.pop == true then
|
286
|
+
# exp[1] = s(:arglist, exp[1])
|
287
|
+
elsif exp.size == 2 && exp.last.first == :array then
|
288
|
+
exp.push(*exp.pop[1..-1])
|
289
|
+
end
|
290
|
+
|
291
|
+
exp
|
292
|
+
end
|
293
|
+
|
294
|
+
def rewrite_super(exp)
|
295
|
+
exp.push(*exp.pop[1..-1]) if exp.size == 2 && exp.last.first == :array
|
296
|
+
exp
|
297
|
+
end
|
298
|
+
|
299
|
+
def rewrite_zarray(exp)
|
300
|
+
exp[0] = :array
|
301
|
+
exp
|
302
|
+
end
|
179
303
|
end
|
180
304
|
|
181
305
|
##
|
@@ -183,5 +307,9 @@ end
|
|
183
307
|
|
184
308
|
class Unifier < SexpProcessor
|
185
309
|
include UnifiedRuby
|
186
|
-
end
|
187
310
|
|
311
|
+
def initialize
|
312
|
+
super
|
313
|
+
@unsupported.delete :newline
|
314
|
+
end
|
315
|
+
end
|