fastruby 0.0.3 → 0.0.4
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.
- 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
|