fastruby 0.0.2 → 0.0.3
Sign up to get free protection for your applications and to get access to all the features.
- data/README +0 -2
- data/Rakefile +1 -2
- data/TODO +0 -1
- data/lib/fastruby/builder.rb +35 -28
- data/lib/fastruby/getlocals.rb +8 -6
- data/lib/fastruby/method_extension.rb +36 -0
- data/lib/fastruby/object.rb +130 -8
- data/lib/fastruby/translator.rb +133 -54
- data/spec/sugar_spec.rb +138 -0
- data/spec/variable_spec.rb +109 -0
- metadata +6 -20
data/README
CHANGED
@@ -55,8 +55,6 @@ I will stabilize the API and document it for next releases. I promise
|
|
55
55
|
|
56
56
|
== Known Limitations & Issues
|
57
57
|
|
58
|
-
* fastruby only can be called from inside a class scope, and only can be used to define instance methods (no class methods)
|
59
|
-
* fastruby invokations can't take more than one method
|
60
58
|
* monkey patching does not work with fastruby methods
|
61
59
|
* 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)
|
62
60
|
* does not support singleton methods (both define & call)
|
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.3'
|
11
11
|
s.author = 'Dario Seminara'
|
12
12
|
s.email = 'robertodarioseminara@gmail.com'
|
13
13
|
s.platform = Gem::Platform::RUBY
|
@@ -15,7 +15,6 @@ spec = Gem::Specification.new do |s|
|
|
15
15
|
s.homepage = "http://github.com/tario/fastruby"
|
16
16
|
s.add_dependency "RubyInline", "= 3.9.0"
|
17
17
|
s.add_dependency "ruby_parser", "= 2.0.6"
|
18
|
-
s.add_dependency "sexp_processor", "= 3.0.5"
|
19
18
|
s.has_rdoc = true
|
20
19
|
s.extra_rdoc_files = [ 'README' ]
|
21
20
|
# s.rdoc_options << '--main' << 'README'
|
data/TODO
CHANGED
data/lib/fastruby/builder.rb
CHANGED
@@ -20,25 +20,33 @@ along with fastruby. if not, see <http://www.gnu.org/licenses/>.
|
|
20
20
|
=end
|
21
21
|
require "fastruby/translator"
|
22
22
|
require "fastruby/inline_extension"
|
23
|
+
require "fastruby/method_extension"
|
23
24
|
require "fastruby/logging"
|
24
25
|
|
25
26
|
module FastRuby
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
27
|
+
|
28
|
+
class Method
|
29
|
+
attr_accessor :tree
|
30
|
+
attr_accessor :locals
|
31
|
+
attr_accessor :options
|
32
|
+
|
33
|
+
def initialize(method_name, owner)
|
34
|
+
@method_name = method_name
|
35
|
+
@owner = owner
|
36
|
+
end
|
37
|
+
|
38
|
+
def build(signature)
|
39
|
+
mname = "_" + @method_name.to_s + signature.map(&:internal_value).map(&:to_s).join
|
32
40
|
|
33
41
|
FastRuby.logger.info mname.to_s
|
34
42
|
|
35
43
|
begin
|
36
|
-
if (
|
37
|
-
FastRuby.logger.info "NOT Building #{self}::#{method_name} for signature #{signature.inspect}, it's already done"
|
44
|
+
if (@owner.instance_method(mname))
|
45
|
+
FastRuby.logger.info "NOT Building #{self}::#{@method_name} for signature #{signature.inspect}, it's already done"
|
38
46
|
return
|
39
47
|
end
|
40
48
|
rescue NameError
|
41
|
-
FastRuby.logger.info "Building #{self}::#{method_name} for signature #{signature.inspect}"
|
49
|
+
FastRuby.logger.info "Building #{self}::#{@method_name} for signature #{signature.inspect}"
|
42
50
|
end
|
43
51
|
|
44
52
|
context = FastRuby::Context.new
|
@@ -57,41 +65,40 @@ module FastRuby
|
|
57
65
|
|
58
66
|
context.infer_self = signature[0]
|
59
67
|
|
60
|
-
c_code = context.
|
68
|
+
c_code = context.to_c_method(tree)
|
61
69
|
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
70
|
+
@owner.class_eval do
|
71
|
+
inline :C do |builder|
|
72
|
+
builder.inc << context.extra_code
|
73
|
+
builder.include "<node.h>"
|
74
|
+
builder.c c_code
|
75
|
+
end
|
66
76
|
end
|
67
77
|
|
68
|
-
|
69
|
-
ret = instance_method(mname)
|
78
|
+
ret = @owner.instance_method(mname)
|
70
79
|
|
71
80
|
ret.extend MethodExtent
|
72
81
|
ret.yield_signature = context.yield_signature
|
73
82
|
|
74
83
|
ret
|
84
|
+
|
75
85
|
end
|
76
86
|
|
77
87
|
module MethodExtent
|
78
88
|
attr_accessor :yield_signature
|
79
89
|
end
|
90
|
+
end
|
80
91
|
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
end
|
85
|
-
|
86
|
-
def method_locals
|
87
|
-
@method_locals = Hash.new unless @method_locals
|
88
|
-
@method_locals
|
92
|
+
module BuilderModule
|
93
|
+
def build(signature, method_name)
|
94
|
+
fastruby_method(method_name.to_sym).build(signature)
|
89
95
|
end
|
90
96
|
|
91
|
-
def
|
92
|
-
|
93
|
-
@
|
97
|
+
def fastruby_method(mname_)
|
98
|
+
mname = mname_.to_sym
|
99
|
+
@fastruby_method = Hash.new unless @fastruby_method
|
100
|
+
@fastruby_method[mname] = FastRuby::Method.new(mname,self) unless @fastruby_method[mname]
|
101
|
+
@fastruby_method[mname]
|
94
102
|
end
|
95
|
-
|
96
103
|
end
|
97
104
|
end
|
data/lib/fastruby/getlocals.rb
CHANGED
@@ -19,23 +19,25 @@ along with fastruby. if not, see <http://www.gnu.org/licenses/>.
|
|
19
19
|
|
20
20
|
=end
|
21
21
|
require "rubygems"
|
22
|
-
require "sexp_processor"
|
23
22
|
require "set"
|
24
23
|
|
25
24
|
module FastRuby
|
26
|
-
class GetLocalsProcessor
|
25
|
+
class GetLocalsProcessor
|
27
26
|
|
28
27
|
attr_reader :locals
|
29
28
|
|
30
29
|
def initialize
|
31
|
-
super()
|
32
|
-
self.require_empty = false
|
33
30
|
@locals = Set.new
|
34
31
|
end
|
35
32
|
|
36
|
-
def
|
33
|
+
def process(tree)
|
34
|
+
if tree.node_type == :lasgn
|
37
35
|
@locals << tree[1]
|
38
|
-
|
36
|
+
end
|
37
|
+
|
38
|
+
tree.select{|subtree| subtree.instance_of? Sexp}.each do |subtree|
|
39
|
+
process(subtree)
|
40
|
+
end
|
39
41
|
end
|
40
42
|
|
41
43
|
def self.get_locals(tree)
|
@@ -0,0 +1,36 @@
|
|
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
|
+
|
22
|
+
module FastRuby
|
23
|
+
module MethodExtension
|
24
|
+
def fastruby
|
25
|
+
owner.fastruby_method(name.to_sym)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
class Method
|
31
|
+
include FastRuby::MethodExtension
|
32
|
+
end
|
33
|
+
|
34
|
+
class UnboundMethod
|
35
|
+
include FastRuby::MethodExtension
|
36
|
+
end
|
data/lib/fastruby/object.rb
CHANGED
@@ -21,22 +21,120 @@ along with fastruby. if not, see <http://www.gnu.org/licenses/>.
|
|
21
21
|
require "fastruby/translator"
|
22
22
|
require "fastruby/builder"
|
23
23
|
require "fastruby/getlocals"
|
24
|
+
require "fastruby/method_extension"
|
24
25
|
require "ruby_parser"
|
25
26
|
require "inline"
|
26
27
|
|
27
28
|
# clean rubyinline cache
|
28
29
|
system("rm -fr #{ENV["HOME"]}/.ruby_inline/*")
|
29
30
|
|
31
|
+
$top_level_binding = binding
|
32
|
+
|
33
|
+
module FastRuby
|
34
|
+
def self.encapsulate_tree(tree, method_name)
|
35
|
+
generated_tree = tree
|
36
|
+
|
37
|
+
if generated_tree[0] == :scope
|
38
|
+
generated_tree = s(:defn, method_name.to_sym, s(:args),
|
39
|
+
s(:scope, s(:block, generated_tree[1])))
|
40
|
+
elsif generated_tree[0] == :block
|
41
|
+
generated_tree = s(:defn, method_name.to_sym, s(:args),
|
42
|
+
s(:scope, generated_tree))
|
43
|
+
else
|
44
|
+
generated_tree = s(:defn, method_name.to_sym, s(:args),
|
45
|
+
s(:scope, s(:block, generated_tree)))
|
46
|
+
end
|
47
|
+
|
48
|
+
generated_tree
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
30
52
|
class Object
|
31
|
-
|
32
|
-
|
53
|
+
|
54
|
+
def fastruby(argument, *options_hashes)
|
55
|
+
tree = nil
|
56
|
+
|
57
|
+
if argument.instance_of? Sexp
|
58
|
+
tree = argument
|
59
|
+
elsif argument.instance_of? String
|
60
|
+
tree = RubyParser.new.parse(argument)
|
61
|
+
else
|
62
|
+
raise ArgumentError
|
63
|
+
end
|
64
|
+
|
65
|
+
if tree[0] == :class
|
66
|
+
classname = Object.to_class_name tree[1]
|
67
|
+
|
68
|
+
eval("
|
69
|
+
class #{classname}
|
70
|
+
end
|
71
|
+
", $top_level_binding)
|
72
|
+
|
73
|
+
klass = eval(classname)
|
74
|
+
|
75
|
+
method_name = "_anonymous_" + rand(100000000000).to_s
|
76
|
+
$generated_tree = FastRuby.encapsulate_tree(tree[3],method_name)
|
77
|
+
$options_hashes = options_hashes
|
78
|
+
|
79
|
+
klass.class_eval do
|
80
|
+
class << self
|
81
|
+
fastruby $generated_tree, *$options_hashes
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
klass.send(method_name)
|
86
|
+
else
|
87
|
+
method_name = "_anonymous_" + rand(100000000000).to_s
|
88
|
+
Object.fastruby(FastRuby.encapsulate_tree(tree,method_name), *options_hashes)
|
89
|
+
send(method_name)
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
def self.fastruby(argument,*options_hashes)
|
94
|
+
|
95
|
+
tree = nil
|
96
|
+
|
97
|
+
if argument.instance_of? Sexp
|
98
|
+
tree = argument
|
99
|
+
elsif argument.instance_of? String
|
100
|
+
tree = RubyParser.new.parse(argument)
|
101
|
+
else
|
102
|
+
raise ArgumentError
|
103
|
+
end
|
104
|
+
|
105
|
+
if tree.node_type == :defn
|
106
|
+
fastruby_defn(tree,*options_hashes)
|
107
|
+
else
|
108
|
+
method_name = "_anonymous_" + rand(100000000000).to_s
|
109
|
+
$generated_tree = FastRuby.encapsulate_tree(tree,method_name)
|
110
|
+
$options_hashes = options_hashes
|
111
|
+
|
112
|
+
klass = self
|
113
|
+
klass.class_eval do
|
114
|
+
class << self
|
115
|
+
fastruby_defn($generated_tree,*$options_hashes)
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
send(method_name)
|
120
|
+
end
|
121
|
+
|
122
|
+
end
|
123
|
+
|
124
|
+
def self.fastruby_defn(tree, *options_hashes)
|
33
125
|
|
34
126
|
options_hash = {:validate_lvar_types => true}
|
35
127
|
options_hashes.each do |opt|
|
36
128
|
options_hash.merge!(opt)
|
37
129
|
end
|
38
130
|
|
39
|
-
if tree[0]
|
131
|
+
if tree[0] == :block
|
132
|
+
(1..tree.size-1).each do |i|
|
133
|
+
fastruby(tree[i], *options_hashes)
|
134
|
+
end
|
135
|
+
|
136
|
+
return
|
137
|
+
elsif tree[0] != :defn
|
40
138
|
raise ArgumentError, "Only definition of methods are accepted"
|
41
139
|
end
|
42
140
|
|
@@ -50,7 +148,7 @@ class Object
|
|
50
148
|
locals = Set.new
|
51
149
|
locals << :self
|
52
150
|
|
53
|
-
FastRuby::GetLocalsProcessor.get_locals(
|
151
|
+
FastRuby::GetLocalsProcessor.get_locals(tree).each do |local|
|
54
152
|
locals << local
|
55
153
|
end
|
56
154
|
|
@@ -64,9 +162,10 @@ class Object
|
|
64
162
|
end
|
65
163
|
end
|
66
164
|
|
67
|
-
self_.
|
68
|
-
|
69
|
-
|
165
|
+
fastrubym = self_.fastruby_method(method_name)
|
166
|
+
fastrubym.tree = tree
|
167
|
+
fastrubym.locals = locals
|
168
|
+
fastrubym.options = options_hash
|
70
169
|
|
71
170
|
def hash.build(key)
|
72
171
|
@klass.build(key, @method_name)
|
@@ -159,10 +258,33 @@ class Object
|
|
159
258
|
end
|
160
259
|
end
|
161
260
|
|
261
|
+
def internal_value
|
262
|
+
$refered_from_code_array = Array.new unless $refered_from_code_array
|
263
|
+
$refered_from_code_array << self
|
264
|
+
|
265
|
+
internal_value_
|
266
|
+
end
|
267
|
+
|
162
268
|
inline :C do |builder|
|
163
|
-
builder.c "VALUE
|
269
|
+
builder.c "VALUE internal_value_() {
|
164
270
|
return INT2FIX(self);
|
165
271
|
}"
|
166
272
|
end
|
273
|
+
|
274
|
+
private
|
275
|
+
def self.to_class_name(argument)
|
276
|
+
if argument.instance_of? Symbol
|
277
|
+
argument.to_s
|
278
|
+
elsif argument.instance_of? Sexp
|
279
|
+
if argument[0] == :colon3
|
280
|
+
"::" + to_class_name(argument[1])
|
281
|
+
elsif argument[0] == :colon2
|
282
|
+
to_class_name(argument[1]) + "::" + to_class_name(argument[2])
|
283
|
+
elsif argument[0] == :const
|
284
|
+
to_class_name(argument[1])
|
285
|
+
end
|
286
|
+
end
|
287
|
+
end
|
288
|
+
|
167
289
|
end
|
168
290
|
|
data/lib/fastruby/translator.rb
CHANGED
@@ -21,6 +21,7 @@ along with fastruby. if not, see <http://www.gnu.org/licenses/>.
|
|
21
21
|
require "rubygems"
|
22
22
|
require "inline"
|
23
23
|
require "set"
|
24
|
+
require "fastruby/method_extension"
|
24
25
|
|
25
26
|
module FastRuby
|
26
27
|
class Context
|
@@ -133,9 +134,15 @@ module FastRuby
|
|
133
134
|
|
134
135
|
convention = nil
|
135
136
|
|
136
|
-
if recvtype.respond_to? :
|
137
|
+
if recvtype.respond_to? :fastruby_method and inference_complete
|
137
138
|
|
138
|
-
|
139
|
+
method_tree = nil
|
140
|
+
begin
|
141
|
+
method_tree = recvtype.instance_method(call_tree[2]).fastruby.tree
|
142
|
+
rescue NoMethodError
|
143
|
+
end
|
144
|
+
|
145
|
+
if method_tree
|
139
146
|
mobject = recvtype.build(signature, call_tree[2])
|
140
147
|
yield_signature = mobject.yield_signature
|
141
148
|
|
@@ -394,25 +401,18 @@ module FastRuby
|
|
394
401
|
to_c(subtree)
|
395
402
|
}.join(";")
|
396
403
|
|
397
|
-
if tree[-1]
|
398
|
-
str = str + ";last_expression = #{to_c(tree[-1])};"
|
399
|
-
else
|
400
|
-
str = str + ";#{to_c(tree[-1])};"
|
401
|
-
end
|
404
|
+
if tree[-1]
|
402
405
|
|
403
|
-
|
404
|
-
|
405
|
-
|
406
|
-
|
407
|
-
|
408
|
-
|
406
|
+
if tree[-1][0] != :return
|
407
|
+
str = str + ";last_expression = #{to_c(tree[-1])};"
|
408
|
+
else
|
409
|
+
str = str + ";#{to_c(tree[-1])};"
|
410
|
+
end
|
411
|
+
end
|
409
412
|
|
410
|
-
|
411
|
-
}
|
412
|
-
"
|
413
|
-
}
|
413
|
+
str << "return last_expression;"
|
414
414
|
|
415
|
-
|
415
|
+
inline_block str
|
416
416
|
end
|
417
417
|
|
418
418
|
def to_c_return(tree)
|
@@ -461,7 +461,52 @@ module FastRuby
|
|
461
461
|
end
|
462
462
|
end
|
463
463
|
|
464
|
+
def to_c_scope(tree)
|
465
|
+
if tree[1]
|
466
|
+
to_c(tree[1])
|
467
|
+
else
|
468
|
+
"Qnil"
|
469
|
+
end
|
470
|
+
end
|
471
|
+
|
472
|
+
def to_c_cdecl(tree)
|
473
|
+
if tree[1].instance_of? Symbol
|
474
|
+
inline_block "
|
475
|
+
// set constant #{tree[1].to_s}
|
476
|
+
VALUE val = #{to_c tree[2]};
|
477
|
+
rb_const_set(rb_cObject, #{tree[1].to_i}, val);
|
478
|
+
return val;
|
479
|
+
"
|
480
|
+
elsif tree[1].instance_of? Sexp
|
481
|
+
|
482
|
+
if tree[1].node_type == :colon2
|
483
|
+
inline_block "
|
484
|
+
// set constant #{tree[1].to_s}
|
485
|
+
VALUE val = #{to_c tree[2]};
|
486
|
+
VALUE klass = #{to_c tree[1][1]};
|
487
|
+
rb_const_set(klass, #{tree[1][2].to_i}, val);
|
488
|
+
return val;
|
489
|
+
"
|
490
|
+
elsif tree[1].node_type == :colon3
|
491
|
+
inline_block "
|
492
|
+
// set constant #{tree[1].to_s}
|
493
|
+
VALUE val = #{to_c tree[2]};
|
494
|
+
rb_const_set(rb_cObject, #{tree[1][1].to_i}, val);
|
495
|
+
return val;
|
496
|
+
"
|
497
|
+
end
|
498
|
+
end
|
499
|
+
end
|
500
|
+
|
501
|
+
def to_c_const(tree)
|
502
|
+
"rb_const_get(CLASS_OF(plocals->self), #{tree[1].to_i})"
|
503
|
+
end
|
504
|
+
|
464
505
|
def to_c_defn(tree)
|
506
|
+
"rb_funcall(plocals->self,#{:fastruby.to_i},1,(VALUE)#{tree.internal_value})"
|
507
|
+
end
|
508
|
+
|
509
|
+
def to_c_method(tree)
|
465
510
|
method_name = tree[1]
|
466
511
|
args_tree = tree[2]
|
467
512
|
|
@@ -501,7 +546,7 @@ module FastRuby
|
|
501
546
|
#{@locals_struct} locals;
|
502
547
|
#{@locals_struct} *plocals = (void*)&locals;
|
503
548
|
#{@block_struct} *pblock;
|
504
|
-
VALUE last_expression;
|
549
|
+
VALUE last_expression = Qnil;
|
505
550
|
|
506
551
|
#{args_tree[1..-1].map { |arg|
|
507
552
|
"locals.#{arg} = #{arg};\n"
|
@@ -546,6 +591,33 @@ module FastRuby
|
|
546
591
|
"_rb_ivar_set(#{locals_accessor}self,#{tree[1].to_i},#{to_c tree[2]})"
|
547
592
|
end
|
548
593
|
|
594
|
+
def to_c_colon3(tree)
|
595
|
+
"rb_const_get_from(rb_cObject, #{tree[1].to_i})"
|
596
|
+
end
|
597
|
+
def to_c_colon2(tree)
|
598
|
+
inline_block "
|
599
|
+
VALUE klass = #{to_c tree[1]};
|
600
|
+
|
601
|
+
if (rb_is_const_id(#{tree[2].to_i})) {
|
602
|
+
switch (TYPE(klass)) {
|
603
|
+
case T_CLASS:
|
604
|
+
case T_MODULE:
|
605
|
+
return rb_const_get_from(klass, #{tree[2].to_i});
|
606
|
+
break;
|
607
|
+
default:
|
608
|
+
rb_raise(rb_eTypeError, \"%s is not a class/module\",
|
609
|
+
RSTRING(rb_obj_as_string(klass))->ptr);
|
610
|
+
break;
|
611
|
+
}
|
612
|
+
}
|
613
|
+
else {
|
614
|
+
return rb_funcall(klass, #{tree[2].to_i}, 0, 0);
|
615
|
+
}
|
616
|
+
|
617
|
+
return Qnil;
|
618
|
+
"
|
619
|
+
end
|
620
|
+
|
549
621
|
def to_c_lasgn(tree)
|
550
622
|
if options[:validate_lvar_types]
|
551
623
|
klass = @infer_lvar_map[tree[1]]
|
@@ -601,31 +673,19 @@ module FastRuby
|
|
601
673
|
condition_tree = tree[1]
|
602
674
|
impl_tree = tree[2]
|
603
675
|
else_tree = tree[3]
|
604
|
-
code = "if (RTEST(#{to_c condition_tree})) {
|
605
|
-
last_expression = #{to_c impl_tree};
|
606
|
-
}
|
607
|
-
"
|
608
|
-
|
609
|
-
if (else_tree)
|
610
|
-
code = code + " else {
|
611
|
-
last_expression = #{to_c else_tree};
|
612
|
-
}
|
613
|
-
"
|
614
|
-
end
|
615
676
|
|
616
|
-
|
617
|
-
|
618
|
-
|
619
|
-
|
620
|
-
|
621
|
-
|
622
|
-
|
623
|
-
|
677
|
+
inline_block "
|
678
|
+
if (RTEST(#{to_c condition_tree})) {
|
679
|
+
last_expression = #{to_c impl_tree};
|
680
|
+
}#{else_tree ?
|
681
|
+
" else {
|
682
|
+
last_expression = #{to_c else_tree};
|
683
|
+
}
|
684
|
+
" : ""
|
624
685
|
}
|
625
|
-
"
|
626
|
-
}
|
627
686
|
|
628
|
-
|
687
|
+
return last_expression;
|
688
|
+
"
|
629
689
|
end
|
630
690
|
|
631
691
|
def to_c_call(tree)
|
@@ -665,9 +725,15 @@ module FastRuby
|
|
665
725
|
|
666
726
|
convention = nil
|
667
727
|
|
668
|
-
if recvtype.respond_to? :
|
728
|
+
if recvtype.respond_to? :fastruby_method and inference_complete
|
669
729
|
|
670
|
-
|
730
|
+
method_tree = nil
|
731
|
+
begin
|
732
|
+
method_tree = recvtype.instance_method(tree[2]).fastruby.tree
|
733
|
+
rescue NoMethodError
|
734
|
+
end
|
735
|
+
|
736
|
+
if method_tree
|
671
737
|
mobject = recvtype.build(signature, tree[2])
|
672
738
|
convention = :fastruby
|
673
739
|
else
|
@@ -773,22 +839,21 @@ module FastRuby
|
|
773
839
|
end
|
774
840
|
end
|
775
841
|
|
776
|
-
def
|
777
|
-
|
778
|
-
|
779
|
-
|
780
|
-
|
842
|
+
def to_c_class(tree)
|
843
|
+
inline_block("
|
844
|
+
rb_funcall(plocals->self,#{:fastruby.to_i},1,(VALUE)#{tree.internal_value});
|
845
|
+
return Qnil;
|
846
|
+
")
|
781
847
|
|
848
|
+
end
|
849
|
+
|
850
|
+
def to_c_while(tree)
|
851
|
+
inline_block("
|
782
852
|
while (#{to_c tree[1]}) {
|
783
853
|
#{to_c tree[2]};
|
784
854
|
}
|
785
|
-
|
786
855
|
return Qnil;
|
787
|
-
|
788
|
-
"
|
789
|
-
}
|
790
|
-
|
791
|
-
anonymous_function(caller_code) + "((VALUE)#{locals_pointer})"
|
856
|
+
")
|
792
857
|
end
|
793
858
|
|
794
859
|
def infer_type(recv)
|
@@ -850,6 +915,20 @@ module FastRuby
|
|
850
915
|
end
|
851
916
|
end
|
852
917
|
|
918
|
+
def inline_block(code)
|
919
|
+
caller_code = proc { |name| "
|
920
|
+
static VALUE #{name}(VALUE param) {
|
921
|
+
#{@locals_struct} *plocals = (void*)param;
|
922
|
+
VALUE last_expression = Qnil;
|
923
|
+
|
924
|
+
#{code}
|
925
|
+
}
|
926
|
+
"
|
927
|
+
}
|
928
|
+
|
929
|
+
anonymous_function(caller_code) + "((VALUE)#{locals_pointer})"
|
930
|
+
end
|
931
|
+
|
853
932
|
inline :C do |builder|
|
854
933
|
builder.include "<node.h>"
|
855
934
|
builder.c "VALUE getaddress(VALUE method) {
|
data/spec/sugar_spec.rb
ADDED
@@ -0,0 +1,138 @@
|
|
1
|
+
require "fastruby"
|
2
|
+
|
3
|
+
describe FastRuby, "fastruby" do
|
4
|
+
it "should compile fastruby code with two methods" do
|
5
|
+
class ::E1
|
6
|
+
fastruby "
|
7
|
+
def foo
|
8
|
+
12
|
9
|
+
end
|
10
|
+
|
11
|
+
def bar
|
12
|
+
15
|
13
|
+
end
|
14
|
+
"
|
15
|
+
end
|
16
|
+
|
17
|
+
e1 = ::E1.new
|
18
|
+
e1.foo.should be == 12
|
19
|
+
e1.bar.should be == 15
|
20
|
+
end
|
21
|
+
|
22
|
+
it "should compile fastruby code with class definition and one method" do
|
23
|
+
fastruby "
|
24
|
+
class ::E2
|
25
|
+
def foo
|
26
|
+
12
|
27
|
+
end
|
28
|
+
end
|
29
|
+
"
|
30
|
+
|
31
|
+
e2 = ::E2.new
|
32
|
+
e2.foo.should be == 12
|
33
|
+
end
|
34
|
+
|
35
|
+
it "should compile fastruby code with class definition and two methods" do
|
36
|
+
fastruby "
|
37
|
+
class ::E3
|
38
|
+
def foo
|
39
|
+
12
|
40
|
+
end
|
41
|
+
def bar
|
42
|
+
15
|
43
|
+
end
|
44
|
+
end
|
45
|
+
"
|
46
|
+
|
47
|
+
e3 = ::E3.new
|
48
|
+
e3.foo.should be == 12
|
49
|
+
e3.bar.should be == 15
|
50
|
+
end
|
51
|
+
|
52
|
+
class ::E4
|
53
|
+
def foo
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
it "should compile standalone code and execute it inmediatly" do
|
58
|
+
$e4 = ::E4
|
59
|
+
fastruby "
|
60
|
+
require 'fastruby'
|
61
|
+
$e4.new.foo
|
62
|
+
"
|
63
|
+
end
|
64
|
+
|
65
|
+
it "should compile standalone code togheter with classes and execute it inmediatly" do
|
66
|
+
$e4 = ::E4
|
67
|
+
fastruby "
|
68
|
+
require 'fastruby'
|
69
|
+
$e4.new.foo
|
70
|
+
|
71
|
+
class ::E5
|
72
|
+
def foo
|
73
|
+
12
|
74
|
+
end
|
75
|
+
def bar
|
76
|
+
15
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
"
|
81
|
+
|
82
|
+
e5 = ::E5.new
|
83
|
+
e5.foo.should be == 12
|
84
|
+
e5.bar.should be == 15
|
85
|
+
end
|
86
|
+
|
87
|
+
class ::E6
|
88
|
+
attr_reader :called
|
89
|
+
def foo
|
90
|
+
@called = true
|
91
|
+
end
|
92
|
+
end
|
93
|
+
it "should execute standalone code" do
|
94
|
+
$e6 = ::E6.new
|
95
|
+
fastruby "
|
96
|
+
$e6.foo
|
97
|
+
"
|
98
|
+
$e6.called.should be == true
|
99
|
+
end
|
100
|
+
|
101
|
+
it "should execute standalone code inside a class definition" do
|
102
|
+
$e6_1 = ::E6.new
|
103
|
+
fastruby "
|
104
|
+
class X
|
105
|
+
$e6_1.foo
|
106
|
+
end
|
107
|
+
"
|
108
|
+
$e6_1.called.should be == true
|
109
|
+
end
|
110
|
+
|
111
|
+
it "should allow define multiple classes in only one call to fastruby" do
|
112
|
+
fastruby "
|
113
|
+
class E7X
|
114
|
+
end
|
115
|
+
class E7Y
|
116
|
+
end
|
117
|
+
"
|
118
|
+
end
|
119
|
+
|
120
|
+
it "should allow define multiple classes with methods in only one call to fastruby" do
|
121
|
+
fastruby "
|
122
|
+
class E8X
|
123
|
+
def foo
|
124
|
+
123
|
125
|
+
end
|
126
|
+
end
|
127
|
+
class E8Y
|
128
|
+
def bar
|
129
|
+
456
|
130
|
+
end
|
131
|
+
end
|
132
|
+
"
|
133
|
+
|
134
|
+
E8X.new.foo.should be == 123
|
135
|
+
E8Y.new.bar.should be == 456
|
136
|
+
end
|
137
|
+
|
138
|
+
end
|
data/spec/variable_spec.rb
CHANGED
@@ -60,4 +60,113 @@ describe FastRuby, "fastruby" do
|
|
60
60
|
u4.foo.should be == 88
|
61
61
|
end
|
62
62
|
|
63
|
+
class ::U5
|
64
|
+
fastruby "
|
65
|
+
def foo
|
66
|
+
U5C = 11
|
67
|
+
end
|
68
|
+
"
|
69
|
+
end
|
70
|
+
|
71
|
+
it "should write constants" do
|
72
|
+
::U5.new.foo
|
73
|
+
|
74
|
+
U5C.should be == 11
|
75
|
+
end
|
76
|
+
|
77
|
+
class ::U6
|
78
|
+
fastruby "
|
79
|
+
def foo
|
80
|
+
U6C
|
81
|
+
end
|
82
|
+
"
|
83
|
+
end
|
84
|
+
|
85
|
+
it "should read constants" do
|
86
|
+
::U6C = 11
|
87
|
+
::U6.new.foo.should be == 11
|
88
|
+
end
|
89
|
+
|
90
|
+
|
91
|
+
class ::U7
|
92
|
+
class U71
|
93
|
+
fastruby "
|
94
|
+
def foo
|
95
|
+
U7C = 11
|
96
|
+
end
|
97
|
+
"
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
it "should write nested constants" do
|
102
|
+
::U7::U71.new.foo
|
103
|
+
::U7::U71::U7C.should be == 11
|
104
|
+
|
105
|
+
lambda {
|
106
|
+
::U7::U7C.should be == 11
|
107
|
+
}.should_not raise_error
|
108
|
+
end
|
109
|
+
|
110
|
+
class ::U8
|
111
|
+
class U81
|
112
|
+
fastruby "
|
113
|
+
def foo
|
114
|
+
U8C
|
115
|
+
end
|
116
|
+
"
|
117
|
+
end
|
118
|
+
end
|
119
|
+
it "should read nested constants" do
|
120
|
+
::U8::U81::U8C = 11
|
121
|
+
::U8::U81.new.foo.should be == 11
|
122
|
+
end
|
123
|
+
|
124
|
+
class ::U9
|
125
|
+
fastruby "
|
126
|
+
def foo
|
127
|
+
::U9C
|
128
|
+
end
|
129
|
+
"
|
130
|
+
end
|
131
|
+
it "should read constant with colon3" do
|
132
|
+
::U9C = 21
|
133
|
+
::U9.new.foo.should be == 21
|
134
|
+
end
|
135
|
+
|
136
|
+
it "should write constant with colon3" do
|
137
|
+
class ::U10
|
138
|
+
fastruby "
|
139
|
+
::U10C = 51
|
140
|
+
def foo
|
141
|
+
end
|
142
|
+
"
|
143
|
+
end
|
144
|
+
::U10.new.foo
|
145
|
+
::U10C.should be == 51
|
146
|
+
end
|
147
|
+
|
148
|
+
class ::U11
|
149
|
+
fastruby "
|
150
|
+
def foo
|
151
|
+
::U11::U11C
|
152
|
+
end
|
153
|
+
"
|
154
|
+
end
|
155
|
+
it "should read constant with colon3 and colon2" do
|
156
|
+
::U11::U11C = 21
|
157
|
+
::U11.new.foo.should be == 21
|
158
|
+
end
|
159
|
+
|
160
|
+
it "should write constant with colon3 and colon2" do
|
161
|
+
class ::U12
|
162
|
+
fastruby "
|
163
|
+
::U12::U12C = 51
|
164
|
+
def foo
|
165
|
+
end
|
166
|
+
"
|
167
|
+
end
|
168
|
+
::U12.new.foo
|
169
|
+
::U12::U12C.should be == 51
|
170
|
+
end
|
171
|
+
|
63
172
|
end
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: fastruby
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 25
|
5
5
|
prerelease: false
|
6
6
|
segments:
|
7
7
|
- 0
|
8
8
|
- 0
|
9
|
-
-
|
10
|
-
version: 0.0.
|
9
|
+
- 3
|
10
|
+
version: 0.0.3
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Dario Seminara
|
@@ -15,7 +15,7 @@ autorequire:
|
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
17
|
|
18
|
-
date: 2011-
|
18
|
+
date: 2011-08-03 00:00:00 -03:00
|
19
19
|
default_executable:
|
20
20
|
dependencies:
|
21
21
|
- !ruby/object:Gem::Dependency
|
@@ -50,22 +50,6 @@ dependencies:
|
|
50
50
|
version: 2.0.6
|
51
51
|
type: :runtime
|
52
52
|
version_requirements: *id002
|
53
|
-
- !ruby/object:Gem::Dependency
|
54
|
-
name: sexp_processor
|
55
|
-
prerelease: false
|
56
|
-
requirement: &id003 !ruby/object:Gem::Requirement
|
57
|
-
none: false
|
58
|
-
requirements:
|
59
|
-
- - "="
|
60
|
-
- !ruby/object:Gem::Version
|
61
|
-
hash: 13
|
62
|
-
segments:
|
63
|
-
- 3
|
64
|
-
- 0
|
65
|
-
- 5
|
66
|
-
version: 3.0.5
|
67
|
-
type: :runtime
|
68
|
-
version_requirements: *id003
|
69
53
|
description:
|
70
54
|
email: robertodarioseminara@gmail.com
|
71
55
|
executables: []
|
@@ -92,12 +76,14 @@ files:
|
|
92
76
|
- lib/fastruby/getlocals.rb
|
93
77
|
- lib/fastruby/translator.rb
|
94
78
|
- lib/fastruby/object.rb
|
79
|
+
- lib/fastruby/method_extension.rb
|
95
80
|
- lib/fastruby.rb
|
96
81
|
- spec/variable_spec.rb
|
97
82
|
- spec/control_spec.rb
|
98
83
|
- spec/expression_spec.rb
|
99
84
|
- spec/base_spec.rb
|
100
85
|
- spec/block_spec.rb
|
86
|
+
- spec/sugar_spec.rb
|
101
87
|
- spec/literal_spec.rb
|
102
88
|
- spec/integrity_spec.rb
|
103
89
|
- LICENSE
|