fastruby 0.0.16 → 0.0.17

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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
+