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
@@ -27,8 +27,27 @@ module FastRuby
27
27
  "rb_cvar_get(CLASS_OF(plocals->self) != rb_cClass ? CLASS_OF(plocals->self) : plocals->self,#{intern_num tree[1]})"
28
28
  end
29
29
 
30
- def to_c_cvasgn(tree)
30
+ def to_c_cvasgn(tree, result_var = nil)
31
+ if result_var
32
+ "
33
+ {
34
+ VALUE recv = CLASS_OF(plocals->self) != rb_cClass ? CLASS_OF(plocals->self) : plocals->self;
35
+
36
+ #{to_c tree[2], result_var};
37
+
38
+ #{if RUBY_VERSION =~ /^1\.9/
39
+ "rb_cvar_set(recv,#{intern_num tree[1]},#{result_var});"
40
+ elsif RUBY_VERSION =~ /^1\.8/
41
+ "rb_cvar_set(recv,#{intern_num tree[1]},#{result_var},Qfalse);"
42
+ else
43
+ raise RuntimeError, "unsupported ruby version #{RUBY_VERSION}"
44
+ end
45
+ }
46
+ }
47
+ "
48
+ else
31
49
  "__rb_cvar_set(CLASS_OF(plocals->self) != rb_cClass ? CLASS_OF(plocals->self) : plocals->self,#{intern_num tree[1]},#{to_c tree[2]},Qfalse)"
50
+ end
32
51
  end
33
52
 
34
53
  def to_c_gvar(tree)
@@ -39,48 +58,81 @@ module FastRuby
39
58
  end
40
59
  end
41
60
 
42
- def to_c_gasgn(tree)
61
+ def to_c_gasgn(tree, result_var = nil)
62
+ if result_var
63
+ "
64
+ {
65
+ #{to_c tree[2], result_var};
66
+ rb_gvar_set((void*)#{global_entry(tree[1])},#{result_var});
67
+ }
68
+ "
69
+ else
43
70
  "_rb_gvar_set((void*)#{global_entry(tree[1])}, #{to_c tree[2]})"
71
+ end
44
72
  end
45
73
 
46
74
  def to_c_ivar(tree)
47
75
  "rb_ivar_get(#{locals_accessor}self,#{intern_num tree[1]})"
48
76
  end
49
77
 
50
- def to_c_iasgn(tree)
51
- "_rb_ivar_set(#{locals_accessor}self,#{intern_num tree[1]},#{to_c tree[2]})"
78
+ def to_c_iasgn(tree, result_var = nil)
79
+ if result_var
80
+ "
81
+ {
82
+ #{to_c tree[2], result_var};
83
+ rb_ivar_set(#{locals_accessor}self,#{intern_num tree[1]},#{result_var});
84
+ }
85
+ "
86
+ else
87
+ "_rb_ivar_set(#{locals_accessor}self,#{intern_num tree[1]},#{to_c tree[2]})"
88
+ end
52
89
  end
53
90
 
54
91
  def to_c_const(tree)
55
92
  "rb_const_get(CLASS_OF(plocals->self), #{intern_num(tree[1])})"
56
93
  end
57
94
 
58
- def to_c_cdecl(tree)
95
+ def to_c_cdecl(tree, result_var_ = nil)
96
+
97
+ result_var = result_var_ || "value"
98
+
59
99
  if tree[1].instance_of? Symbol
60
- inline_block "
61
- // set constant #{tree[1].to_s}
62
- VALUE val = #{to_c tree[2]};
63
- rb_const_set(rb_cObject, #{intern_num tree[1]}, val);
64
- return val;
100
+ code = "
101
+ {
102
+ // set constant #{tree[1].to_s}
103
+ #{to_c tree[2], result_var};
104
+ rb_const_set(rb_cObject, #{intern_num tree[1]}, #{result_var});
105
+ }
65
106
  "
66
107
  elsif tree[1].instance_of? FastRuby::FastRubySexp
67
108
 
68
109
  if tree[1].node_type == :colon2
69
- inline_block "
70
- // set constant #{tree[1].to_s}
71
- VALUE val = #{to_c tree[2]};
72
- VALUE klass = #{to_c tree[1][1]};
73
- rb_const_set(klass, #{intern_num tree[1][2]}, val);
74
- return val;
110
+ code = "
111
+ {
112
+ // set constant #{tree[1].to_s}
113
+ #{to_c tree[2], result_var};
114
+ VALUE klass = Qnil;
115
+ #{to_c tree[1][1], "klass"};
116
+ rb_const_set(klass, #{intern_num tree[1][2]}, #{result_var});
117
+ }
75
118
  "
76
119
  elsif tree[1].node_type == :colon3
77
- inline_block "
120
+ code = "
121
+ {
78
122
  // set constant #{tree[1].to_s}
79
- VALUE val = #{to_c tree[2]};
80
- rb_const_set(rb_cObject, #{intern_num tree[1][1]}, val);
81
- return val;
123
+ #{to_c tree[2], result_var};
124
+ rb_const_set(rb_cObject, #{intern_num tree[1][1]}, #{result_var});
125
+ }
82
126
  "
83
127
  end
128
+
129
+ if result_var_
130
+ code
131
+ else
132
+ inline_block "VALUE #{result_var} = Qnil;\n" + code + "
133
+ return #{result_var};
134
+ "
135
+ end
84
136
  end
85
137
  end
86
138
 
@@ -88,15 +140,29 @@ module FastRuby
88
140
  "rb_const_get_from(rb_cObject, #{intern_num tree[1]})"
89
141
  end
90
142
 
91
- def to_c_colon2(tree)
92
- inline_block "
93
- VALUE klass = #{to_c tree[1]};
143
+ def to_c_colon2(tree, result_var = nil)
144
+ code = "
145
+ {
146
+ VALUE klass = Qnil;
147
+
148
+ #{to_c tree[1],"klass"};
149
+ #{
150
+ if result_var
151
+ "#{result_var} = Qnil;"
152
+ end
153
+ }
94
154
 
95
155
  if (rb_is_const_id(#{intern_num tree[2]})) {
96
156
  switch (TYPE(klass)) {
97
157
  case T_CLASS:
98
158
  case T_MODULE:
99
- return rb_const_get_from(klass, #{intern_num tree[2]});
159
+ #{
160
+ if result_var
161
+ "#{result_var} = rb_const_get_from(klass, #{intern_num tree[2]});"
162
+ else
163
+ "return rb_const_get_from(klass, #{intern_num tree[2]});"
164
+ end
165
+ }
100
166
  break;
101
167
  default:
102
168
  #{_raise("rb_eTypeError","not a class/module")};
@@ -104,35 +170,78 @@ module FastRuby
104
170
  }
105
171
  }
106
172
  else {
107
- return rb_funcall(klass, #{intern_num tree[2]}, 0, 0);
173
+ #{
174
+ if result_var
175
+ "#{result_var} = rb_funcall(klass, #{intern_num tree[2]}, 0, 0);"
176
+ else
177
+ "return rb_funcall(klass, #{intern_num tree[2]}, 0, 0);"
178
+ end
179
+ }
108
180
  }
109
-
110
- return Qnil;
181
+
182
+ #{
183
+ unless result_var
184
+ "return Qnil;"
185
+ end
186
+ }
187
+ }
111
188
  "
189
+
190
+ if result_var
191
+ code
192
+ else
193
+ inline_block code
194
+ end
112
195
  end
113
196
 
114
- def to_c_lasgn(tree)
115
- if options[:validate_lvar_types]
116
- klass = @infer_lvar_map[tree[1]]
117
- if klass
197
+ def to_c_lasgn(tree, result_var = nil)
198
+ code = "
199
+ {
200
+ #{to_c tree[2], result_var};
201
+ #{locals_accessor}#{tree[1]} = #{result_var};
202
+ }
203
+ "
118
204
 
119
- verify_type_function = proc { |name| "
120
- static VALUE #{name}(VALUE arg, void* pframe ) {
121
- if (CLASS_OF(arg)!=#{literal_value klass}) {
205
+ if result_var
206
+ if options[:validate_lvar_types]
207
+ klass = @infer_lvar_map[tree[1]]
208
+ if klass
209
+ "
210
+ {
211
+ #{to_c tree[2], result_var};
212
+ if (CLASS_OF(#{result_var})!=#{literal_value klass}) {
122
213
  #{_raise(literal_value(FastRuby::TypeMismatchAssignmentException), "Illegal assignment at runtime (type mismatch)")};
123
214
  }
124
- return arg;
215
+ #{locals_accessor}#{tree[1]} = #{result_var};
125
216
  }
126
- "
127
- }
128
-
129
-
130
- "_lvar_assing(&#{locals_accessor}#{tree[1]}, #{anonymous_function(&verify_type_function)}(#{to_c tree[2]},pframe))"
217
+ "
218
+ else
219
+ code
220
+ end
131
221
  else
132
- "_lvar_assing(&#{locals_accessor}#{tree[1]},#{to_c tree[2]})"
222
+ code
133
223
  end
134
224
  else
135
- "_lvar_assing(&#{locals_accessor}#{tree[1]},#{to_c tree[2]})"
225
+ if options[:validate_lvar_types]
226
+ klass = @infer_lvar_map[tree[1]]
227
+ if klass
228
+ verify_type_function = proc { |name| "
229
+ static VALUE #{name}(VALUE arg, void* pframe ) {
230
+ if (CLASS_OF(arg)!=#{literal_value klass}) {
231
+ #{_raise(literal_value(FastRuby::TypeMismatchAssignmentException), "Illegal assignment at runtime (type mismatch)")};
232
+ }
233
+ return arg;
234
+ }
235
+ "
236
+ }
237
+
238
+ "_lvar_assing(&#{locals_accessor}#{tree[1]}, #{anonymous_function(&verify_type_function)}(#{to_c tree[2]},pframe))"
239
+ else
240
+ "_lvar_assing(&#{locals_accessor}#{tree[1]},#{to_c tree[2]})"
241
+ end
242
+ else
243
+ "_lvar_assing(&#{locals_accessor}#{tree[1]},#{to_c tree[2]})"
244
+ end
136
245
  end
137
246
  end
138
247
 
@@ -0,0 +1,161 @@
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
+ require "fastruby/sexp_extension"
22
+
23
+ module FastRuby
24
+ class ScopeModeHelper
25
+ def self.get_scope_mode(tree_)
26
+ new.get_scope_mode(tree_)
27
+ end
28
+
29
+ def when_array_to_if(array)
30
+ if array.size == 1
31
+ array[0] || s(:nil)
32
+ else
33
+ first_when_tree = array[0]
34
+ comparers = first_when_tree[1][1..-1]
35
+
36
+ condition_tree = s(:or)
37
+ comparers.each do |st|
38
+ condition_tree << s(:call, st, :===, s(:arglist, s(:lvar, :temporal_case_var)))
39
+ end
40
+
41
+ s(:if, condition_tree, first_when_tree[2], when_array_to_if(array[1..-1]) )
42
+ end
43
+ end
44
+
45
+ def get_scope_mode(tree_)
46
+ tree = FastRuby::FastRubySexp.from_sexp(tree_).transform do |subtree|
47
+ if subtree.node_type == :for
48
+ s(:iter,s(:call, subtree[1],:each, s(:arglist)),subtree[2], subtree[3] )
49
+ elsif subtree.node_type == :case
50
+ ifs = when_array_to_if(subtree[2..-1])
51
+
52
+ s(:block, s(:lasgn, :temporal_case_var, subtree[1]), ifs)
53
+ else
54
+ nil
55
+ end
56
+ end
57
+
58
+ if tree.node_type == :defn
59
+ args_tree = tree[2]
60
+ impl_tree = tree[3]
61
+ elsif tree.node_type == :defs
62
+ args_tree = tree[3]
63
+ impl_tree = tree[4]
64
+ end
65
+
66
+ graph = impl_tree.to_graph
67
+
68
+ args_tree[1..-1].each do |subtree|
69
+ return :dag if subtree.to_s =~ /^\&/
70
+ end
71
+
72
+ tree.walk_tree do |subtree|
73
+ if subtree.node_type == :iter
74
+ iter_impl = subtree[3]
75
+
76
+ return :dag if has_local_variable_access?(subtree[3])
77
+ return :dag if subtree[2]
78
+
79
+ if iter_impl
80
+ return_node = iter_impl.find_tree{|st2| st2.node_type == :return}
81
+
82
+ if return_node
83
+ return :dag
84
+ end
85
+ end
86
+ elsif subtree.node_type == :block_pass
87
+ return :dag
88
+ end
89
+ end
90
+
91
+ impl_tree.walk_tree do |subtree|
92
+ graph.each_path_from(subtree) do |path|
93
+ # verify path prohibitive for :linear scope (local variable read after call)
94
+ has_call = false
95
+ writes = Set.new
96
+
97
+ path.each do |st2|
98
+ if st2.node_type == :call
99
+ if has_call and st2[1] == nil
100
+ return :dag
101
+ end
102
+
103
+ writes.clear
104
+ has_call = true
105
+ elsif st2.node_type == :iter
106
+ if has_call and st2[1][1] == nil
107
+ return :dag
108
+ end
109
+
110
+ writes.clear
111
+ has_call = true
112
+ elsif st2.node_type == :lasgn
113
+ writes << st2[1] # record local writes
114
+ elsif st2.node_type == :lvar or st2.node_type == :self or
115
+ st2.node_type == :return or st2.node_type == :yield
116
+
117
+ if has_call
118
+ if st2.node_type == :lvar
119
+ if writes.include? st2[1]
120
+ # no problem
121
+ else
122
+ # read after call, the scope of this function must be implemented on heap
123
+ return :dag
124
+ end
125
+ else
126
+ return :dag
127
+ end
128
+ end
129
+ end
130
+ end
131
+ end
132
+ end
133
+
134
+ :linear
135
+ end
136
+
137
+ private
138
+ def has_local_variable_access?(*trees)
139
+ trees.each do |tree|
140
+ return false unless tree.kind_of? FastRuby::FastRubySexp
141
+
142
+ tree.walk_tree do |subtree|
143
+ if subtree.node_type == :lvar or
144
+ subtree.node_type == :self or
145
+ subtree.node_type == :yield or
146
+ subtree.node_type == :return or
147
+ subtree.node_type == :lasgn
148
+ return true
149
+ end
150
+
151
+ if subtree.node_type == :call
152
+ if subtree[1] == nil
153
+ return true
154
+ end
155
+ end
156
+ end
157
+ end
158
+ false
159
+ end
160
+ end
161
+ end