fastruby 0.0.3 → 0.0.4

Sign up to get free protection for your applications and to get access to all the features.
data/CHANGELOG ADDED
@@ -0,0 +1,21 @@
1
+ 0.0.4 Basic support fot non-local goto: return, break, next
2
+
3
+ Basic support for exceptions
4
+
5
+ Support for defined?
6
+
7
+ Support for modules
8
+
9
+ Support for singleton methods
10
+
11
+ 0.0.3 Implemented global array to make references to literal objects used in code
12
+
13
+ Added support to write and read constants
14
+
15
+ Added support to execution of complete ruby code (entire clases o any ruby code)
16
+
17
+ Refactored code to avoid use sexp_processor
18
+
19
+ 0.0.2 Added missing sexp_processor dependency
20
+
21
+ 0.0.1 First test release
data/README CHANGED
@@ -55,11 +55,10 @@ I will stabilize the API and document it for next releases. I promise
55
55
 
56
56
  == Known Limitations & Issues
57
57
 
58
+ * Bootstrap is very slow since this is a Poc :P
58
59
  * monkey patching does not work with fastruby methods
59
60
  * calls with blocks to ruby or cruby methods are almost as slow as normal ruby (if the called method is defined by fastruby, the call it's pretty fast)
60
- * does not support singleton methods (both define & call)
61
61
  * does not support methods with variable number of arguments
62
- * does not support exception handling (rescue, ensure, etc...)
63
62
 
64
63
  == Usage
65
64
 
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.3'
10
+ s.version = '0.0.4'
11
11
  s.author = 'Dario Seminara'
12
12
  s.email = 'robertodarioseminara@gmail.com'
13
13
  s.platform = Gem::Platform::RUBY
@@ -19,7 +19,7 @@ spec = Gem::Specification.new do |s|
19
19
  s.extra_rdoc_files = [ 'README' ]
20
20
  # s.rdoc_options << '--main' << 'README'
21
21
  s.files = Dir.glob("{benchmarks,examples,lib,spec}/**/*") +
22
- [ 'LICENSE', 'AUTHORS', 'README', 'Rakefile', 'TODO' ]
22
+ [ 'LICENSE', 'AUTHORS', 'README', 'Rakefile', 'TODO', 'CHANGELOG' ]
23
23
  end
24
24
 
25
25
  desc 'Run tests'
data/TODO CHANGED
@@ -1,10 +1,8 @@
1
1
  Basic functionality:
2
2
 
3
3
  * Flow control setences: case
4
- * Exceptions
5
4
  * Defining and call of methods with variable number of arguments
6
5
  * Blocks with variable number of arguments
7
- * call to monkey patched methods from fastruby code
8
6
  * callcc
9
7
 
10
8
  To improve:
@@ -22,9 +22,27 @@ require "fastruby/translator"
22
22
  require "fastruby/inline_extension"
23
23
  require "fastruby/method_extension"
24
24
  require "fastruby/logging"
25
+ require "fastruby/getlocals"
25
26
 
26
27
  module FastRuby
27
28
 
29
+ def self.build_defs(tree, *options)
30
+ method_name = tree[2].to_s
31
+
32
+ FastRuby.logger.info "Building singleton method #{self}::#{@method_name}"
33
+
34
+ locals = GetLocalsProcessor.get_locals(tree)
35
+ locals << :self
36
+
37
+ context = FastRuby::Context.new(false)
38
+ context.locals = locals
39
+ context.options = options
40
+
41
+ context.alt_method_name = "singleton_" + method_name + rand(100000000).to_s
42
+
43
+ [context.extra_code + context.to_c_method_defs(tree), context.alt_method_name]
44
+ end
45
+
28
46
  class Method
29
47
  attr_accessor :tree
30
48
  attr_accessor :locals
@@ -43,7 +61,7 @@ module FastRuby
43
61
  begin
44
62
  if (@owner.instance_method(mname))
45
63
  FastRuby.logger.info "NOT Building #{self}::#{@method_name} for signature #{signature.inspect}, it's already done"
46
- return
64
+ return @owner.instance_method(mname)
47
65
  end
48
66
  rescue NameError
49
67
  FastRuby.logger.info "Building #{self}::#{@method_name} for signature #{signature.inspect}"
@@ -0,0 +1,48 @@
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 Kernel
22
+ def fastruby_require(path)
23
+ if path =~ /\.so$/
24
+ require(path)
25
+ else
26
+ FastRuby.logger.info "trying to load '#{path}'"
27
+
28
+ complete_path = path + (path =~ /\.rb$/ ? "" : ".rb")
29
+
30
+ $LOAD_PATH.each do |load_path|
31
+ begin
32
+ source = nil
33
+ File.open(load_path + "/" + complete_path) do |file|
34
+ source = file.read
35
+ end
36
+
37
+ FastRuby.logger.info "loading '#{load_path + "/" + complete_path}'"
38
+
39
+ fastruby source
40
+ return true
41
+ rescue Errno::ENOENT
42
+ end
43
+ end
44
+
45
+ raise LoadError
46
+ end
47
+ end
48
+ end
@@ -62,13 +62,25 @@ class Object
62
62
  raise ArgumentError
63
63
  end
64
64
 
65
+ return unless tree
66
+
65
67
  if tree[0] == :class
66
68
  classname = Object.to_class_name tree[1]
67
69
 
68
- eval("
69
- class #{classname}
70
+ if tree[2]
71
+ superclassname = Object.to_class_name tree[2]
72
+
73
+ eval("
74
+ class #{classname} < #{superclassname}
75
+ end
76
+ ", $top_level_binding)
77
+
78
+ else
79
+ eval("
80
+ class #{classname}
81
+ end
82
+ ", $top_level_binding)
70
83
  end
71
- ", $top_level_binding)
72
84
 
73
85
  klass = eval(classname)
74
86
 
@@ -83,6 +95,29 @@ class Object
83
95
  end
84
96
 
85
97
  klass.send(method_name)
98
+ elsif tree[0] == :module
99
+ modulename = Object.to_class_name tree[1]
100
+
101
+ eval("
102
+ module #{modulename}
103
+ end
104
+ ", $top_level_binding)
105
+
106
+ klass = eval(modulename)
107
+
108
+ method_name = "_anonymous_" + rand(100000000000).to_s
109
+ $generated_tree = FastRuby.encapsulate_tree(tree[2],method_name)
110
+ $options_hashes = options_hashes
111
+
112
+ klass.class_eval do
113
+ class << self
114
+ fastruby $generated_tree, *$options_hashes
115
+ end
116
+ end
117
+
118
+ klass.send(method_name)
119
+ elsif tree[0] == :defn
120
+ Object.fastruby_defn(tree, *options_hashes)
86
121
  else
87
122
  method_name = "_anonymous_" + rand(100000000000).to_s
88
123
  Object.fastruby(FastRuby.encapsulate_tree(tree,method_name), *options_hashes)
@@ -90,6 +125,10 @@ class Object
90
125
  end
91
126
  end
92
127
 
128
+ def self.fastruby_defs(*args)
129
+ raise NoMethodError, "not implemented yet"
130
+ end
131
+
93
132
  def self.fastruby(argument,*options_hashes)
94
133
 
95
134
  tree = nil
@@ -102,6 +141,8 @@ class Object
102
141
  raise ArgumentError
103
142
  end
104
143
 
144
+ return unless tree
145
+
105
146
  if tree.node_type == :defn
106
147
  fastruby_defn(tree,*options_hashes)
107
148
  else
@@ -173,7 +214,7 @@ class Object
173
214
 
174
215
  eval("#{hashname} = hash")
175
216
 
176
- value_cast = ( ["VALUE"]*(args_tree.size+1) ).join(",")
217
+ value_cast = ( ["VALUE"]*(args_tree.size+2) ).join(",")
177
218
 
178
219
  main_signature_argument = args_tree[1..-1].first || "self"
179
220
 
@@ -181,9 +222,9 @@ class Object
181
222
  strmethodargs_class = (["self"] + args_tree[1..-1]).map{|arg| "CLASS_OF(#{arg.to_s})"}.join(",")
182
223
 
183
224
  if args_tree.size > 1
184
- strmethodargs = "self,block,#{args_tree[1..-1].map(&:to_s).join(",") }"
225
+ strmethodargs = "self,block,(VALUE)&frame,#{args_tree[1..-1].map(&:to_s).join(",") }"
185
226
  else
186
- strmethodargs = "self,block"
227
+ strmethodargs = "self,block,(VALUE)&frame"
187
228
  end
188
229
 
189
230
  strmethod_signature = (["self"] + args_tree[1..-1]).map { |arg|
@@ -217,6 +258,22 @@ class Object
217
258
  }
218
259
 
219
260
  if (nd_type(body) == NODE_CFUNC) {
261
+ struct {
262
+ void* parent_frame;
263
+ void* target_frame;
264
+ void* plocals;
265
+ jmp_buf jmp;
266
+ VALUE return_value;
267
+ VALUE exception;
268
+ int rescue;
269
+ } frame;
270
+
271
+ frame.target_frame = 0;
272
+ frame.parent_frame = 0;
273
+ frame.rescue = 0;
274
+ frame.exception = Qnil;
275
+ frame.return_value = Qnil;
276
+
220
277
  int argc = body->nd_argc;
221
278
 
222
279
  VALUE block = Qfalse;
@@ -233,13 +290,19 @@ class Object
233
290
  block = (VALUE)&block_struct;
234
291
  }
235
292
 
236
- if (argc == #{args_tree.size}) {
293
+ int aux = setjmp(frame.jmp);
294
+ if (aux != 0) {
295
+ rb_funcall(self, #{:raise.to_i}, 1, frame.exception);
296
+ return Qnil;
297
+ }
298
+
299
+ if (argc == #{args_tree.size+1}) {
237
300
  return ((VALUE(*)(#{value_cast}))body->nd_cfnc)(#{strmethodargs});
238
301
  } else if (argc == -1) {
239
- VALUE argv[] = {#{(["block"]+args_tree[1..-1]).map(&:to_s).join(",")} };
302
+ VALUE argv[] = {#{(["block,(VALUE)&frame"]+args_tree[1..-1]).map(&:to_s).join(",")} };
240
303
  return ((VALUE(*)(int,VALUE*,VALUE))body->nd_cfnc)(#{args_tree.size},argv,self);
241
304
  } else if (argc == -2) {
242
- VALUE argv[] = {#{(["block"]+args_tree[1..-1]).map(&:to_s).join(",")} };
305
+ VALUE argv[] = {#{(["block,(VALUE)&frame"]+args_tree[1..-1]).map(&:to_s).join(",")} };
243
306
  return ((VALUE(*)(VALUE,VALUE))body->nd_cfnc)(self, rb_ary_new4(#{args_tree.size},argv));
244
307
  } else {
245
308
  rb_raise(rb_eArgError, \"wrong number of arguments (#{args_tree.size-1} for %d)\", argc);
@@ -251,7 +314,7 @@ class Object
251
314
 
252
315
  inline :C do |builder|
253
316
  builder.include "<node.h>"
254
- builder.inc << "static VALUE re_yield(int argc, VALUE* argv, VALUE param) {
317
+ builder.inc << "static VALUE re_yield(int argc, VALUE* argv, VALUE param, VALUE _parent_frame) {
255
318
  return rb_yield_splat(rb_ary_new4(argc,argv));
256
319
  }"
257
320
  builder.c c_code