fastruby 0.0.16 → 0.0.17

Sign up to get free protection for your applications and to get access to all the features.
Files changed (78) hide show
  1. data/CHANGELOG +17 -1
  2. data/Rakefile +1 -1
  3. data/ext/fastruby_base/fastruby_base.inl +81 -3
  4. data/lib/fastruby/fastruby_sexp.rb +21 -0
  5. data/lib/fastruby/getlocals.rb +2 -1
  6. data/lib/fastruby/object.rb +1 -1
  7. data/lib/fastruby/sexp_extension.rb +189 -0
  8. data/lib/fastruby/sexp_extension_edges.rb +210 -0
  9. data/lib/fastruby/translator/modules/block.rb +29 -22
  10. data/lib/fastruby/translator/modules/call.rb +211 -34
  11. data/lib/fastruby/translator/modules/defn.rb +64 -29
  12. data/lib/fastruby/translator/modules/exceptions.rb +1 -1
  13. data/lib/fastruby/translator/modules/flow.rb +93 -31
  14. data/lib/fastruby/translator/modules/iter.rb +277 -340
  15. data/lib/fastruby/translator/modules/literal.rb +97 -20
  16. data/lib/fastruby/translator/modules/logical.rb +40 -5
  17. data/lib/fastruby/translator/modules/method_group.rb +41 -19
  18. data/lib/fastruby/translator/modules/nonlocal.rb +74 -29
  19. data/lib/fastruby/translator/modules/variable.rb +151 -42
  20. data/lib/fastruby/translator/scope_mode_helper.rb +161 -0
  21. data/lib/fastruby/translator/translator.rb +389 -302
  22. data/lib/fastruby.rb +1 -1
  23. data/lib/fastruby.rb~ +36 -0
  24. data/spec/edges_helper.rb +91 -0
  25. data/spec/graph/base_spec.rb +35 -0
  26. data/spec/graph/path_spec.rb +48 -0
  27. data/spec/graph/vertex_spec.rb +58 -0
  28. data/spec/ruby/block/proc_as_block_spec.rb +214 -0
  29. data/spec/ruby/block/redo_spec.rb +133 -0
  30. data/spec/ruby/defn/single_function_spec.rb +50 -0
  31. data/spec/scope_mode/base_spec.rb +55 -0
  32. data/spec/scope_mode/block_spec.rb +105 -0
  33. data/spec/scope_mode/call_spec.rb +24 -0
  34. data/spec/scope_mode/exception_spec.rb +34 -0
  35. data/spec/scope_mode/flow_spec.rb +99 -0
  36. data/spec/scope_mode/optimization_spec.rb +130 -0
  37. data/spec/sexp2graph/base_spec.rb +36 -0
  38. data/spec/sexp2graph/exception_spec.rb +172 -0
  39. data/spec/sexp2graph/flow_spec.rb +67 -0
  40. data/spec/sexp2graph/logical_spec.rb +21 -0
  41. data/spec/sexp2graph/variable_spec.rb +26 -0
  42. metadata +110 -120
  43. data/lib/fastruby/self +0 -82
  44. data/lib/len +0 -280
  45. data/spec/block/proc_as_block_spec.rb +0 -111
  46. data/spec/block/redo_spec.rb +0 -67
  47. /data/spec/{base_spec.rb → ruby/base_spec.rb} +0 -0
  48. /data/spec/{block → ruby/block}/arguments_spec.rb +0 -0
  49. /data/spec/{block → ruby/block}/block_as_proc_spec.rb +0 -0
  50. /data/spec/{block → ruby/block}/break_spec.rb +0 -0
  51. /data/spec/{block → ruby/block}/callcc_spec.rb +0 -0
  52. /data/spec/{block → ruby/block}/lambda_spec.rb +0 -0
  53. /data/spec/{block → ruby/block}/next_spec.rb +0 -0
  54. /data/spec/{block → ruby/block}/proc_spec.rb +0 -0
  55. /data/spec/{block → ruby/block}/retry_spec.rb +0 -0
  56. /data/spec/{block_spec.rb → ruby/block_spec.rb} +0 -0
  57. /data/spec/{call → ruby/call}/base_call_spec.rb +0 -0
  58. /data/spec/{call → ruby/call}/multiple_args_spec.rb +0 -0
  59. /data/spec/{control_spec.rb → ruby/control_spec.rb} +0 -0
  60. /data/spec/{defn → ruby/defn}/default_args_spec.rb +0 -0
  61. /data/spec/{defn → ruby/defn}/multiple_args_spec.rb +0 -0
  62. /data/spec/{defn → ruby/defn}/replacement_spec.rb +0 -0
  63. /data/spec/{exception → ruby/exception}/base_spec.rb +0 -0
  64. /data/spec/{exception → ruby/exception}/ensure_spec.rb +0 -0
  65. /data/spec/{exception → ruby/exception}/exc_trap_spec.rb +0 -0
  66. /data/spec/{exception → ruby/exception}/internal_ex_spec.rb +0 -0
  67. /data/spec/{exception → ruby/exception}/syntaxis_spec.rb +0 -0
  68. /data/spec/{expression_spec.rb → ruby/expression_spec.rb} +0 -0
  69. /data/spec/{flow_control → ruby/flow_control}/case_spec.rb +0 -0
  70. /data/spec/{flow_control → ruby/flow_control}/for_spec.rb +0 -0
  71. /data/spec/{integrity_spec.rb → ruby/integrity_spec.rb} +0 -0
  72. /data/spec/{jump → ruby/jump}/next_spec.rb +0 -0
  73. /data/spec/{literal_spec.rb → ruby/literal_spec.rb} +0 -0
  74. /data/spec/{module_spec.rb → ruby/module_spec.rb} +0 -0
  75. /data/spec/{return_spec.rb → ruby/return_spec.rb} +0 -0
  76. /data/spec/{singleton_spec.rb → ruby/singleton_spec.rb} +0 -0
  77. /data/spec/{sugar_spec.rb → ruby/sugar_spec.rb} +0 -0
  78. /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
@@ -7,7 +7,7 @@ require "rspec/core/rake_task"
7
7
 
8
8
  spec = Gem::Specification.new do |s|
9
9
  s.name = 'fastruby'
10
- s.version = '0.0.16'
10
+ s.version = '0.0.17'
11
11
  s.author = 'Dario Seminara'
12
12
  s.email = 'robertodarioseminara@gmail.com'
13
13
  s.platform = Gem::Platform::RUBY
@@ -37,7 +37,71 @@ struct FASTRUBYTHREADDATA {
37
37
 
38
38
  #ifdef RUBY_1_9
39
39
 
40
- void* rb_method_entry(VALUE klass, ID id);
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; i++) {
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
- rb_gc_mark(sc->pages[page][position_in_page]);
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
@@ -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
@@ -95,7 +95,7 @@ class Object
95
95
  if $last_obj_proc
96
96
  FastRuby.cache.register_proc(obj, $last_obj_proc)
97
97
  end
98
- FastRuby.cache.execute(obj, self)
98
+ FastRuby.cache.execute(obj, self.kind_of?(Class) ? self : Object)
99
99
  rescue Exception => e
100
100
  p e
101
101
  end
@@ -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
+