fastruby 0.0.16 → 0.0.17
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +17 -1
- data/Rakefile +1 -1
- data/ext/fastruby_base/fastruby_base.inl +81 -3
- data/lib/fastruby/fastruby_sexp.rb +21 -0
- data/lib/fastruby/getlocals.rb +2 -1
- data/lib/fastruby/object.rb +1 -1
- data/lib/fastruby/sexp_extension.rb +189 -0
- data/lib/fastruby/sexp_extension_edges.rb +210 -0
- data/lib/fastruby/translator/modules/block.rb +29 -22
- data/lib/fastruby/translator/modules/call.rb +211 -34
- data/lib/fastruby/translator/modules/defn.rb +64 -29
- data/lib/fastruby/translator/modules/exceptions.rb +1 -1
- data/lib/fastruby/translator/modules/flow.rb +93 -31
- data/lib/fastruby/translator/modules/iter.rb +277 -340
- data/lib/fastruby/translator/modules/literal.rb +97 -20
- data/lib/fastruby/translator/modules/logical.rb +40 -5
- data/lib/fastruby/translator/modules/method_group.rb +41 -19
- data/lib/fastruby/translator/modules/nonlocal.rb +74 -29
- data/lib/fastruby/translator/modules/variable.rb +151 -42
- data/lib/fastruby/translator/scope_mode_helper.rb +161 -0
- data/lib/fastruby/translator/translator.rb +389 -302
- data/lib/fastruby.rb +1 -1
- data/lib/fastruby.rb~ +36 -0
- data/spec/edges_helper.rb +91 -0
- data/spec/graph/base_spec.rb +35 -0
- data/spec/graph/path_spec.rb +48 -0
- data/spec/graph/vertex_spec.rb +58 -0
- data/spec/ruby/block/proc_as_block_spec.rb +214 -0
- data/spec/ruby/block/redo_spec.rb +133 -0
- data/spec/ruby/defn/single_function_spec.rb +50 -0
- data/spec/scope_mode/base_spec.rb +55 -0
- data/spec/scope_mode/block_spec.rb +105 -0
- data/spec/scope_mode/call_spec.rb +24 -0
- data/spec/scope_mode/exception_spec.rb +34 -0
- data/spec/scope_mode/flow_spec.rb +99 -0
- data/spec/scope_mode/optimization_spec.rb +130 -0
- data/spec/sexp2graph/base_spec.rb +36 -0
- data/spec/sexp2graph/exception_spec.rb +172 -0
- data/spec/sexp2graph/flow_spec.rb +67 -0
- data/spec/sexp2graph/logical_spec.rb +21 -0
- data/spec/sexp2graph/variable_spec.rb +26 -0
- metadata +110 -120
- data/lib/fastruby/self +0 -82
- data/lib/len +0 -280
- data/spec/block/proc_as_block_spec.rb +0 -111
- data/spec/block/redo_spec.rb +0 -67
- /data/spec/{base_spec.rb → ruby/base_spec.rb} +0 -0
- /data/spec/{block → ruby/block}/arguments_spec.rb +0 -0
- /data/spec/{block → ruby/block}/block_as_proc_spec.rb +0 -0
- /data/spec/{block → ruby/block}/break_spec.rb +0 -0
- /data/spec/{block → ruby/block}/callcc_spec.rb +0 -0
- /data/spec/{block → ruby/block}/lambda_spec.rb +0 -0
- /data/spec/{block → ruby/block}/next_spec.rb +0 -0
- /data/spec/{block → ruby/block}/proc_spec.rb +0 -0
- /data/spec/{block → ruby/block}/retry_spec.rb +0 -0
- /data/spec/{block_spec.rb → ruby/block_spec.rb} +0 -0
- /data/spec/{call → ruby/call}/base_call_spec.rb +0 -0
- /data/spec/{call → ruby/call}/multiple_args_spec.rb +0 -0
- /data/spec/{control_spec.rb → ruby/control_spec.rb} +0 -0
- /data/spec/{defn → ruby/defn}/default_args_spec.rb +0 -0
- /data/spec/{defn → ruby/defn}/multiple_args_spec.rb +0 -0
- /data/spec/{defn → ruby/defn}/replacement_spec.rb +0 -0
- /data/spec/{exception → ruby/exception}/base_spec.rb +0 -0
- /data/spec/{exception → ruby/exception}/ensure_spec.rb +0 -0
- /data/spec/{exception → ruby/exception}/exc_trap_spec.rb +0 -0
- /data/spec/{exception → ruby/exception}/internal_ex_spec.rb +0 -0
- /data/spec/{exception → ruby/exception}/syntaxis_spec.rb +0 -0
- /data/spec/{expression_spec.rb → ruby/expression_spec.rb} +0 -0
- /data/spec/{flow_control → ruby/flow_control}/case_spec.rb +0 -0
- /data/spec/{flow_control → ruby/flow_control}/for_spec.rb +0 -0
- /data/spec/{integrity_spec.rb → ruby/integrity_spec.rb} +0 -0
- /data/spec/{jump → ruby/jump}/next_spec.rb +0 -0
- /data/spec/{literal_spec.rb → ruby/literal_spec.rb} +0 -0
- /data/spec/{module_spec.rb → ruby/module_spec.rb} +0 -0
- /data/spec/{return_spec.rb → ruby/return_spec.rb} +0 -0
- /data/spec/{singleton_spec.rb → ruby/singleton_spec.rb} +0 -0
- /data/spec/{sugar_spec.rb → ruby/sugar_spec.rb} +0 -0
- /data/spec/{variable_spec.rb → ruby/variable_spec.rb} +0 -0
data/CHANGELOG
CHANGED
@@ -1,3 +1,19 @@
|
|
1
|
+
0.0.17 Fixed bug of non-volatile variables on scopes calling setjmp
|
2
|
+
|
3
|
+
Fixed bug of native pointers encoding on 32 bits systems
|
4
|
+
|
5
|
+
peforrmance: implemented linear stack scopes when possible
|
6
|
+
|
7
|
+
performance: refactored C translation to avoid unecessary non-local jumps such return
|
8
|
+
|
9
|
+
performance: refactored C translation to avoid unecessary anonymous C functions
|
10
|
+
|
11
|
+
performance: Implemented direct call to CFUNC methods on ruby1.9
|
12
|
+
|
13
|
+
Added support for single methods (with "no class")
|
14
|
+
|
15
|
+
Fixed bug with default argument initialization and redo
|
16
|
+
|
1
17
|
0.0.16 Limited (see known issues on README) support for ruby1.9-p180 (tested with rvm)
|
2
18
|
|
3
19
|
Support for ruby1.8-p334 (tested with rvm)
|
@@ -82,4 +98,4 @@
|
|
82
98
|
|
83
99
|
0.0.2 Added missing sexp_processor dependency
|
84
100
|
|
85
|
-
0.0.1 First test release
|
101
|
+
0.0.1 First test release
|
data/Rakefile
CHANGED
@@ -37,7 +37,71 @@ struct FASTRUBYTHREADDATA {
|
|
37
37
|
|
38
38
|
#ifdef RUBY_1_9
|
39
39
|
|
40
|
-
|
40
|
+
|
41
|
+
typedef enum {
|
42
|
+
NOEX_PUBLIC = 0x00,
|
43
|
+
NOEX_NOSUPER = 0x01,
|
44
|
+
NOEX_PRIVATE = 0x02,
|
45
|
+
NOEX_PROTECTED = 0x04,
|
46
|
+
NOEX_MASK = 0x06,
|
47
|
+
NOEX_BASIC = 0x08,
|
48
|
+
NOEX_UNDEF = NOEX_NOSUPER,
|
49
|
+
NOEX_MODFUNC = 0x12,
|
50
|
+
NOEX_SUPER = 0x20,
|
51
|
+
NOEX_VCALL = 0x40,
|
52
|
+
NOEX_RESPONDS = 0x80
|
53
|
+
} rb_method_flag_t;
|
54
|
+
|
55
|
+
typedef enum {
|
56
|
+
VM_METHOD_TYPE_ISEQ,
|
57
|
+
VM_METHOD_TYPE_CFUNC,
|
58
|
+
VM_METHOD_TYPE_ATTRSET,
|
59
|
+
VM_METHOD_TYPE_IVAR,
|
60
|
+
VM_METHOD_TYPE_BMETHOD,
|
61
|
+
VM_METHOD_TYPE_ZSUPER,
|
62
|
+
VM_METHOD_TYPE_UNDEF,
|
63
|
+
VM_METHOD_TYPE_NOTIMPLEMENTED,
|
64
|
+
VM_METHOD_TYPE_OPTIMIZED, /* Kernel#send, Proc#call, etc */
|
65
|
+
VM_METHOD_TYPE_MISSING /* wrapper for method_missing(id) */
|
66
|
+
} rb_method_type_t;
|
67
|
+
|
68
|
+
typedef struct rb_method_cfunc_struct {
|
69
|
+
VALUE (*func)(ANYARGS);
|
70
|
+
int argc;
|
71
|
+
} rb_method_cfunc_t;
|
72
|
+
|
73
|
+
typedef struct rb_method_attr_struct {
|
74
|
+
ID id;
|
75
|
+
VALUE location;
|
76
|
+
} rb_method_attr_t;
|
77
|
+
|
78
|
+
typedef struct rb_iseq_struct rb_iseq_t;
|
79
|
+
|
80
|
+
typedef struct rb_method_definition_struct {
|
81
|
+
rb_method_type_t type; /* method type */
|
82
|
+
ID original_id;
|
83
|
+
union {
|
84
|
+
rb_iseq_t *iseq; /* should be mark */
|
85
|
+
rb_method_cfunc_t cfunc;
|
86
|
+
rb_method_attr_t attr;
|
87
|
+
VALUE proc; /* should be mark */
|
88
|
+
enum method_optimized_type {
|
89
|
+
OPTIMIZED_METHOD_TYPE_SEND,
|
90
|
+
OPTIMIZED_METHOD_TYPE_CALL
|
91
|
+
} optimize_type;
|
92
|
+
} body;
|
93
|
+
int alias_count;
|
94
|
+
} rb_method_definition_t;
|
95
|
+
|
96
|
+
typedef struct rb_method_entry_struct {
|
97
|
+
rb_method_flag_t flag;
|
98
|
+
char mark;
|
99
|
+
rb_method_definition_t *def;
|
100
|
+
ID called_id;
|
101
|
+
VALUE klass; /* should be mark */
|
102
|
+
} rb_method_entry_t;
|
103
|
+
|
104
|
+
rb_method_entry_t* rb_method_entry(VALUE klass, ID id);
|
41
105
|
void* rb_global_entry(ID id);
|
42
106
|
|
43
107
|
typedef struct RNode {
|
@@ -106,6 +170,11 @@ static inline int stack_chunk_get_current_position(struct STACKCHUNK* sc) {
|
|
106
170
|
}
|
107
171
|
}
|
108
172
|
|
173
|
+
typedef struct {
|
174
|
+
int size;
|
175
|
+
void *p1,*p2,*p3,*p4,*p5;
|
176
|
+
VALUE data[0x10000];
|
177
|
+
} generic_scope_t;
|
109
178
|
|
110
179
|
static inline void* stack_chunk_alloc(struct STACKCHUNK* sc, int size){
|
111
180
|
|
@@ -171,6 +240,7 @@ static inline void* stack_chunk_alloc(struct STACKCHUNK* sc, int size){
|
|
171
240
|
address = sc->pages[page]+position_in_page;
|
172
241
|
}
|
173
242
|
|
243
|
+
((generic_scope_t*)address)->size = size;
|
174
244
|
return address;
|
175
245
|
}
|
176
246
|
|
@@ -178,11 +248,19 @@ static inline void stack_chunk_mark(struct STACKCHUNK* sc) {
|
|
178
248
|
// Mark local variables on each allocated page up to current_position
|
179
249
|
int i;
|
180
250
|
|
181
|
-
for (i=0; i<sc->current_position;
|
251
|
+
for (i=0; i<sc->current_position; ) {
|
182
252
|
int position_in_page = i & PAGE_MASK;
|
183
253
|
int page = i / PAGE_SIZE;
|
184
254
|
|
185
|
-
|
255
|
+
generic_scope_t* scope = (void*)&(sc->pages[page][position_in_page]);
|
256
|
+
|
257
|
+
if (scope->size == 0) {
|
258
|
+
i = i + 1;
|
259
|
+
} else {
|
260
|
+
i = i + scope->size;
|
261
|
+
int j;
|
262
|
+
for (j=0;j<scope->size-6;j++) rb_gc_mark(scope->data[j]);
|
263
|
+
}
|
186
264
|
}
|
187
265
|
}
|
188
266
|
|
@@ -21,5 +21,26 @@ along with fastruby. if not, see <http://www.gnu.org/licenses/>.
|
|
21
21
|
module FastRuby
|
22
22
|
class FastRubySexp < Array
|
23
23
|
alias node_type first
|
24
|
+
|
25
|
+
def walk_tree(&block)
|
26
|
+
each do |subtree|
|
27
|
+
if subtree.instance_of? FastRubySexp
|
28
|
+
subtree.walk_tree(&block)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
block.call(self)
|
32
|
+
end
|
33
|
+
|
34
|
+
def find_tree(ndtype = nil)
|
35
|
+
walk_tree do |subtree|
|
36
|
+
if (not block_given?) || yield(subtree)
|
37
|
+
if (not ndtype) || ndtype == subtree.node_type
|
38
|
+
return subtree
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
return nil
|
44
|
+
end
|
24
45
|
end
|
25
46
|
end
|
data/lib/fastruby/getlocals.rb
CHANGED
@@ -50,6 +50,7 @@ module FastRuby
|
|
50
50
|
|
51
51
|
if tree[0] == :block_pass
|
52
52
|
@locals << :__xblock_arguments
|
53
|
+
@locals << :__x_proc
|
53
54
|
end
|
54
55
|
|
55
56
|
tree.select{|subtree| subtree.instance_of? FastRuby::FastRubySexp}.each do |subtree|
|
@@ -63,4 +64,4 @@ module FastRuby
|
|
63
64
|
processor.locals
|
64
65
|
end
|
65
66
|
end
|
66
|
-
end
|
67
|
+
end
|
data/lib/fastruby/object.rb
CHANGED
@@ -19,6 +19,9 @@ along with fastruby. if not, see <http://www.gnu.org/licenses/>.
|
|
19
19
|
|
20
20
|
=end
|
21
21
|
require "fastruby/fastruby_sexp"
|
22
|
+
require "fastruby/sexp_extension_edges"
|
23
|
+
require "ruby_parser"
|
24
|
+
require "set"
|
22
25
|
|
23
26
|
class Object
|
24
27
|
def to_fastruby_sexp
|
@@ -27,14 +30,200 @@ class Object
|
|
27
30
|
end
|
28
31
|
|
29
32
|
module FastRuby
|
33
|
+
class Graph
|
34
|
+
attr_reader :edges
|
35
|
+
attr_reader :vertexes
|
36
|
+
|
37
|
+
def initialize(hash = {})
|
38
|
+
@edges = []
|
39
|
+
@vertexes = Set.new
|
40
|
+
@vertex_output = Hash.new
|
41
|
+
|
42
|
+
hash.each do |orig,v|
|
43
|
+
v.each do |dest|
|
44
|
+
add_edge(orig,dest)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def add_edge(orig,dest)
|
50
|
+
@vertexes << orig
|
51
|
+
@vertexes << dest
|
52
|
+
|
53
|
+
@vertex_output[orig] ||= Set.new
|
54
|
+
@vertex_output[orig] << dest
|
55
|
+
|
56
|
+
@edges << [orig,dest]
|
57
|
+
end
|
58
|
+
|
59
|
+
def each_vertex_output(vertex,&blk)
|
60
|
+
outputs = @vertex_output[vertex]
|
61
|
+
if outputs
|
62
|
+
blk ? outputs.each(&blk) : outputs
|
63
|
+
else
|
64
|
+
Set.new
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
def each_path_from(vertex, history = [])
|
69
|
+
outputs = each_vertex_output(vertex) - history.select{|h| h[0] == vertex }.map(&:last)
|
70
|
+
outputs.delete(vertex)
|
71
|
+
|
72
|
+
if outputs.count == 0
|
73
|
+
yield [vertex]
|
74
|
+
return
|
75
|
+
end
|
76
|
+
|
77
|
+
outputs.each do |vo|
|
78
|
+
each_path_from(vo,history+[[vertex,vo]]) do |subpath|
|
79
|
+
yield [vertex]+subpath
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
30
85
|
class FastRubySexp
|
31
86
|
def self.from_sexp(value)
|
87
|
+
return nil if value == nil
|
88
|
+
return value if value.kind_of? FastRubySexp
|
89
|
+
|
32
90
|
ary = FastRuby::FastRubySexp.new
|
33
91
|
value.each do |x|
|
34
92
|
ary << x.to_fastruby_sexp
|
35
93
|
end
|
36
94
|
ary
|
37
95
|
end
|
96
|
+
|
97
|
+
def transform(&blk)
|
98
|
+
ret = FastRuby::FastRubySexp.from_sexp( blk.call(self) )
|
99
|
+
|
100
|
+
unless ret
|
101
|
+
ret = FastRuby::FastRubySexp.new
|
102
|
+
each{|st2|
|
103
|
+
if st2.respond_to?(:transform)
|
104
|
+
ret << st2.transform(&blk)
|
105
|
+
else
|
106
|
+
ret << st2
|
107
|
+
end
|
108
|
+
}
|
109
|
+
end
|
110
|
+
|
111
|
+
ret
|
112
|
+
end
|
113
|
+
|
114
|
+
def self.parse(code)
|
115
|
+
from_sexp(RubyParser.new.parse(code))
|
116
|
+
end
|
117
|
+
|
118
|
+
def to_graph
|
119
|
+
graph = Graph.new
|
120
|
+
self.edges.each &graph.method(:add_edge)
|
121
|
+
|
122
|
+
if ENV['FASTRUBY_GRAPH_VERTEX_CHECK'] == '1'
|
123
|
+
output_vertexes = [];
|
124
|
+
|
125
|
+
self.walk_tree do |subtree|
|
126
|
+
if graph.each_vertex_output(subtree).count == 0
|
127
|
+
# vertexes with no output
|
128
|
+
unless [:arglist,:scope].include? subtree.node_type
|
129
|
+
output_vertexes << subtree
|
130
|
+
if output_vertexes.count > 1
|
131
|
+
raise RuntimeError, "invalid output vertexes #{output_vertexes.map &:node_type}"
|
132
|
+
end
|
133
|
+
end
|
134
|
+
end
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
138
|
+
graph
|
139
|
+
end
|
140
|
+
|
141
|
+
def edges
|
142
|
+
Edges.new(self)
|
143
|
+
end
|
144
|
+
|
145
|
+
def first_tree
|
146
|
+
if respond_to? "first_tree_#{node_type}"
|
147
|
+
send("first_tree_#{node_type}")
|
148
|
+
else
|
149
|
+
return self[1].first_tree if self.count == 2 and self[1].respond_to? :node_type
|
150
|
+
return self[1].first_tree if [:if,:block,:while,:until,:or,:and,:ensure].include? node_type
|
151
|
+
return self[2].first_tree if [:lasgn,:iasgn,:gasgn,:cdecl].include? node_type
|
152
|
+
|
153
|
+
self
|
154
|
+
end
|
155
|
+
end
|
156
|
+
|
157
|
+
def first_tree_rescue
|
158
|
+
if self[1].node_type == :resbody
|
159
|
+
return self
|
160
|
+
else
|
161
|
+
return self[1].first_tree
|
162
|
+
end
|
163
|
+
end
|
164
|
+
|
165
|
+
def first_tree_return
|
166
|
+
self[1] ? self[1].first_tree : self
|
167
|
+
end
|
168
|
+
|
169
|
+
alias first_tree_break first_tree_return
|
170
|
+
alias first_tree_next first_tree_return
|
171
|
+
|
172
|
+
def first_tree_yield
|
173
|
+
if self.size > 1
|
174
|
+
self[-1].first_tree
|
175
|
+
else
|
176
|
+
self
|
177
|
+
end
|
178
|
+
end
|
179
|
+
|
180
|
+
def first_tree_iter
|
181
|
+
call_tree = self[1]
|
182
|
+
recv = call_tree[1]
|
183
|
+
if recv
|
184
|
+
recv.first_tree
|
185
|
+
else
|
186
|
+
args_tree = call_tree[3]
|
187
|
+
if args_tree.size > 1
|
188
|
+
args_tree[1].first_tree
|
189
|
+
else
|
190
|
+
call_tree
|
191
|
+
end
|
192
|
+
end
|
193
|
+
end
|
194
|
+
|
195
|
+
def first_tree_call
|
196
|
+
recv = self[1]
|
197
|
+
if recv
|
198
|
+
recv.first_tree
|
199
|
+
else
|
200
|
+
args_tree = self[3]
|
201
|
+
if args_tree.size > 1
|
202
|
+
args_tree[1].first_tree
|
203
|
+
else
|
204
|
+
self
|
205
|
+
end
|
206
|
+
end
|
207
|
+
end
|
208
|
+
|
209
|
+
def find_break(&blk)
|
210
|
+
subarray = if node_type == :while
|
211
|
+
[]
|
212
|
+
elsif node_type == :iter
|
213
|
+
self[1..-2]
|
214
|
+
elsif node_type == :break
|
215
|
+
blk.call(self)
|
216
|
+
return; nil
|
217
|
+
else
|
218
|
+
self[1..-1]
|
219
|
+
end
|
220
|
+
|
221
|
+
subarray.each do |subtree|
|
222
|
+
if subtree.respond_to? :find_break
|
223
|
+
subtree.find_break(&blk)
|
224
|
+
end
|
225
|
+
end
|
226
|
+
end
|
38
227
|
end
|
39
228
|
end
|
40
229
|
|
@@ -0,0 +1,210 @@
|
|
1
|
+
=begin
|
2
|
+
|
3
|
+
This file is part of the fastruby project, http://github.com/tario/fastruby
|
4
|
+
|
5
|
+
Copyright (c) 2011 Roberto Dario Seminara <robertodarioseminara@gmail.com>
|
6
|
+
|
7
|
+
fastruby is free software: you can redistribute it and/or modify
|
8
|
+
it under the terms of the gnu general public license as published by
|
9
|
+
the free software foundation, either version 3 of the license, or
|
10
|
+
(at your option) any later version.
|
11
|
+
|
12
|
+
fastruby is distributed in the hope that it will be useful,
|
13
|
+
but without any warranty; without even the implied warranty of
|
14
|
+
merchantability or fitness for a particular purpose. see the
|
15
|
+
gnu general public license for more details.
|
16
|
+
|
17
|
+
you should have received a copy of the gnu general public license
|
18
|
+
along with fastruby. if not, see <http://www.gnu.org/licenses/>.
|
19
|
+
|
20
|
+
=end
|
21
|
+
module FastRuby
|
22
|
+
class FastRubySexp
|
23
|
+
class Edges
|
24
|
+
def initialize(frbsexp)
|
25
|
+
@frbsexp = frbsexp
|
26
|
+
end
|
27
|
+
|
28
|
+
def each(&blk)
|
29
|
+
node_type = @frbsexp.node_type
|
30
|
+
|
31
|
+
@frbsexp.each do|st|
|
32
|
+
next unless FastRubySexp === st
|
33
|
+
st.edges.each(&blk)
|
34
|
+
end
|
35
|
+
|
36
|
+
if respond_to? "edges_#{node_type}"
|
37
|
+
send("edges_#{node_type}", &blk)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def edges_lasgn(&blk)
|
42
|
+
blk.call(@frbsexp[2],@frbsexp)
|
43
|
+
end
|
44
|
+
|
45
|
+
alias edges_gasgn edges_lasgn
|
46
|
+
alias edges_cdecl edges_lasgn
|
47
|
+
alias edges_iasgn edges_lasgn
|
48
|
+
|
49
|
+
def edges_ensure(&blk)
|
50
|
+
if @frbsexp.size > 2
|
51
|
+
@frbsexp[1].walk_tree do |subtree|
|
52
|
+
if subtree.node_type == :call or subtree.node_type == :iter
|
53
|
+
blk.call(subtree,@frbsexp[2].first_tree)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
blk.call(@frbsexp[2],@frbsexp)
|
58
|
+
else
|
59
|
+
blk.call(@frbsexp[1],@frbsexp)
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
def edges_rescue(&blk)
|
64
|
+
return if @frbsexp[1].node_type == :resbody
|
65
|
+
|
66
|
+
blk.call(@frbsexp[1],@frbsexp)
|
67
|
+
|
68
|
+
exit_tree = nil
|
69
|
+
resbody_array_tree = @frbsexp[2][1]
|
70
|
+
|
71
|
+
if resbody_array_tree.size > 1
|
72
|
+
exit_tree = resbody_array_tree[1].first_tree
|
73
|
+
lasgn_tree = resbody_array_tree.find{|st|
|
74
|
+
if st.respond_to? :node_type
|
75
|
+
st.node_type == :lasgn
|
76
|
+
else
|
77
|
+
false
|
78
|
+
end
|
79
|
+
}
|
80
|
+
|
81
|
+
(1..resbody_array_tree.size-2).each do |i|
|
82
|
+
blk.call(resbody_array_tree[i], resbody_array_tree[i+1].first_tree)
|
83
|
+
|
84
|
+
if lasgn_tree
|
85
|
+
blk.call(resbody_array_tree[i], lasgn_tree.first_tree)
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
if @frbsexp[2]
|
90
|
+
if @frbsexp[2][2]
|
91
|
+
blk.call(resbody_array_tree[-1],@frbsexp[2][2].first_tree)
|
92
|
+
else
|
93
|
+
blk.call(resbody_array_tree[-1],@frbsexp)
|
94
|
+
end
|
95
|
+
else
|
96
|
+
blk.call(resbody_array_tree[-1],@frbsexp)
|
97
|
+
end
|
98
|
+
else
|
99
|
+
if @frbsexp[2]
|
100
|
+
if @frbsexp[2][2]
|
101
|
+
exit_tree = @frbsexp[2][2].first_tree
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
unless exit_tree
|
107
|
+
exit_tree = @frbsexp
|
108
|
+
end
|
109
|
+
|
110
|
+
if @frbsexp[2]
|
111
|
+
if @frbsexp[2][2]
|
112
|
+
blk.call(@frbsexp[2][2],@frbsexp)
|
113
|
+
blk.call(@frbsexp[1],exit_tree)
|
114
|
+
retry_tree = @frbsexp[2][2].find_tree(:retry)
|
115
|
+
if retry_tree
|
116
|
+
blk.call(retry_tree,@frbsexp[1].first_tree)
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
@frbsexp[1].walk_tree do |subtree|
|
122
|
+
if subtree.node_type == :call or subtree.node_type == :iter
|
123
|
+
blk.call(subtree,exit_tree)
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
end
|
128
|
+
|
129
|
+
def edges_or(&blk)
|
130
|
+
(1..@frbsexp.size-2).each do |i|
|
131
|
+
blk.call(@frbsexp[i],@frbsexp[i+1].first_tree)
|
132
|
+
end
|
133
|
+
|
134
|
+
blk.call(@frbsexp[-1],@frbsexp)
|
135
|
+
end
|
136
|
+
alias edges_and edges_or
|
137
|
+
|
138
|
+
def edges_if(&blk)
|
139
|
+
if @frbsexp[2]
|
140
|
+
blk.call(@frbsexp[1],@frbsexp[2].first_tree)
|
141
|
+
blk.call(@frbsexp[2],@frbsexp)
|
142
|
+
end
|
143
|
+
|
144
|
+
if @frbsexp[3]
|
145
|
+
blk.call(@frbsexp[3],@frbsexp)
|
146
|
+
blk.call(@frbsexp[1],@frbsexp[3].first_tree)
|
147
|
+
end
|
148
|
+
|
149
|
+
unless @frbsexp[2] and @frbsexp[3]
|
150
|
+
blk.call(@frbsexp[1],@frbsexp)
|
151
|
+
end
|
152
|
+
end
|
153
|
+
|
154
|
+
def edges_scope(&blk)
|
155
|
+
blk.call(@frbsexp[1], @frbsexp)
|
156
|
+
end
|
157
|
+
|
158
|
+
def edges_while(&blk)
|
159
|
+
if @frbsexp[2]
|
160
|
+
blk.call(@frbsexp[1], @frbsexp[2].first_tree)
|
161
|
+
blk.call(@frbsexp[2], @frbsexp[1].first_tree)
|
162
|
+
@frbsexp[2].find_break do |subtree|
|
163
|
+
blk.call(subtree, @frbsexp)
|
164
|
+
end
|
165
|
+
end
|
166
|
+
|
167
|
+
blk.call(@frbsexp[1], @frbsexp)
|
168
|
+
end
|
169
|
+
|
170
|
+
alias edges_until edges_while
|
171
|
+
|
172
|
+
def edges_block(&blk)
|
173
|
+
(2..@frbsexp.size-1).each do |i|
|
174
|
+
blk.call(@frbsexp[i-1], @frbsexp[i].first_tree)
|
175
|
+
end
|
176
|
+
blk.call(@frbsexp.last, @frbsexp)
|
177
|
+
end
|
178
|
+
|
179
|
+
def edges_call(&blk)
|
180
|
+
args_tree = @frbsexp[3]
|
181
|
+
|
182
|
+
(2..args_tree.size-1).each do |i|
|
183
|
+
blk.call(args_tree[i-1], args_tree[i])
|
184
|
+
end
|
185
|
+
|
186
|
+
recv_tree = @frbsexp[1]
|
187
|
+
|
188
|
+
if recv_tree
|
189
|
+
if args_tree.size > 1
|
190
|
+
blk.call(recv_tree, args_tree[1])
|
191
|
+
end
|
192
|
+
end
|
193
|
+
|
194
|
+
if args_tree.size > 1
|
195
|
+
blk.call(args_tree.last, @frbsexp)
|
196
|
+
end
|
197
|
+
end
|
198
|
+
|
199
|
+
def self.do_nothing_for(*nodename)
|
200
|
+
nodename.each do |nn|
|
201
|
+
define_method("edges_#{nn}") do
|
202
|
+
end
|
203
|
+
end
|
204
|
+
end
|
205
|
+
|
206
|
+
do_nothing_for(:nil,:lit,:break)
|
207
|
+
end
|
208
|
+
end
|
209
|
+
end
|
210
|
+
|