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 +21 -0
- data/README +1 -2
- data/Rakefile +2 -2
- data/TODO +0 -2
- data/lib/fastruby/builder.rb +19 -1
- data/lib/fastruby/custom_require.rb +48 -0
- data/lib/fastruby/object.rb +73 -10
- data/lib/fastruby/translator.rb +637 -131
- data/lib/fastruby.rb +4 -0
- data/spec/base_spec.rb +37 -0
- data/spec/block/break_spec.rb +190 -0
- data/spec/block/next_spec.rb +85 -0
- data/spec/exception_spec.rb +440 -0
- data/spec/module_spec.rb +36 -0
- data/spec/return_spec.rb +99 -0
- data/spec/singleton_spec.rb +76 -0
- data/spec/sugar_spec.rb +2 -2
- data/spec/variable_spec.rb +64 -0
- metadata +12 -4
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.
|
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:
|
data/lib/fastruby/builder.rb
CHANGED
@@ -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
|
data/lib/fastruby/object.rb
CHANGED
@@ -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
|
-
|
69
|
-
|
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+
|
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
|
-
|
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
|