fastruby 0.0.2 → 0.0.3
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/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
|