fastruby 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,17 @@
1
+ require "fastruby"
2
+
3
+ class X
4
+ fastruby '
5
+ def foo
6
+ lvar_type(i, Fixnum)
7
+ i = 100
8
+
9
+ while (i > 0)
10
+ i = i - 1
11
+ end
12
+ nil
13
+ end
14
+ '
15
+ end
16
+
17
+ X.new.foo
@@ -0,0 +1,97 @@
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
+ require "fastruby/translator"
22
+ require "fastruby/inline_extension"
23
+ require "fastruby/logging"
24
+
25
+ module FastRuby
26
+ module BuilderModule
27
+ def build(signature, method_name)
28
+ tree = self.method_tree[method_name]
29
+ locals = self.method_locals[method_name]
30
+ options = self.method_options[method_name]
31
+ mname = "_" + method_name.to_s + signature.map(&:internal_value).map(&:to_s).join
32
+
33
+ FastRuby.logger.info mname.to_s
34
+
35
+ begin
36
+ if (self.instance_method(mname))
37
+ FastRuby.logger.info "NOT Building #{self}::#{method_name} for signature #{signature.inspect}, it's already done"
38
+ return
39
+ end
40
+ rescue NameError
41
+ FastRuby.logger.info "Building #{self}::#{method_name} for signature #{signature.inspect}"
42
+ end
43
+
44
+ context = FastRuby::Context.new
45
+ context.locals = locals
46
+ context.options = options
47
+
48
+ args_tree = tree[2]
49
+
50
+ # create random method name
51
+ context.alt_method_name = mname
52
+
53
+ (1..signature.size).each do |i|
54
+ arg = args_tree[i]
55
+ context.infer_lvar_map[arg] = signature[i]
56
+ end
57
+
58
+ context.infer_self = signature[0]
59
+
60
+ c_code = context.to_c(tree)
61
+
62
+ inline :C do |builder|
63
+ builder.inc << context.extra_code
64
+ builder.include "<node.h>"
65
+ builder.c c_code
66
+ end
67
+
68
+
69
+ ret = instance_method(mname)
70
+
71
+ ret.extend MethodExtent
72
+ ret.yield_signature = context.yield_signature
73
+
74
+ ret
75
+ end
76
+
77
+ module MethodExtent
78
+ attr_accessor :yield_signature
79
+ end
80
+
81
+ def method_tree
82
+ @method_tree = Hash.new unless @method_tree
83
+ @method_tree
84
+ end
85
+
86
+ def method_locals
87
+ @method_locals = Hash.new unless @method_locals
88
+ @method_locals
89
+ end
90
+
91
+ def method_options
92
+ @method_options = Hash.new unless @method_options
93
+ @method_options
94
+ end
95
+
96
+ end
97
+ end
@@ -0,0 +1,24 @@
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 FastRuby
22
+ class TypeMismatchAssignmentException < Exception
23
+ end
24
+ end
@@ -0,0 +1,47 @@
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
+ require "rubygems"
22
+ require "sexp_processor"
23
+ require "set"
24
+
25
+ module FastRuby
26
+ class GetLocalsProcessor < SexpProcessor
27
+
28
+ attr_reader :locals
29
+
30
+ def initialize
31
+ super()
32
+ self.require_empty = false
33
+ @locals = Set.new
34
+ end
35
+
36
+ def process_lasgn(tree)
37
+ @locals << tree[1]
38
+ tree.dup
39
+ end
40
+
41
+ def self.get_locals(tree)
42
+ processor = GetLocalsProcessor.new
43
+ processor.process(tree)
44
+ processor.locals
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,87 @@
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 Inline
22
+ class C
23
+ attr_reader :inc
24
+
25
+ def generate(src, options={})
26
+ options = {:expand_types=>options} unless Hash === options
27
+
28
+ expand_types = options[:expand_types]
29
+ singleton = options[:singleton]
30
+ result = self.strip_comments(src)
31
+
32
+ signature = parse_signature(src, !expand_types)
33
+ function_name = signature['name']
34
+ method_name = options[:method_name]
35
+ method_name ||= test_to_normal function_name
36
+ return_type = signature['return']
37
+ arity = options[:arity] || signature['arity']
38
+
39
+ raise ArgumentError, "too many arguments" if arity > MAGIC_ARITY_THRESHOLD
40
+
41
+ if expand_types then
42
+ prefix = "static VALUE #{function_name}("
43
+ if arity <= MAGIC_ARITY then
44
+ prefix += "int argc, VALUE *argv, VALUE self"
45
+ else
46
+ prefix += "VALUE self"
47
+ prefix += signature['args'].map { |arg, type| ", VALUE _#{arg}"}.join
48
+ end
49
+ prefix += ") {\n"
50
+ prefix += signature['args'].map { |arg, type|
51
+ " #{type} #{arg} = #{ruby2c(type)}(_#{arg});\n"
52
+ }.join
53
+
54
+ # replace the function signature (hopefully) with new sig (prefix)
55
+ result.sub!(/[^;\/\"\>]+#{function_name}\s*\([^\{]+\{/, "\n" + prefix)
56
+ result.sub!(/\A\n/, '') # strip off the \n in front in case we added it
57
+ unless return_type == "void" then
58
+ raise SyntaxError, "Couldn't find return statement for #{function_name}" unless
59
+ result =~ /return/
60
+ else
61
+ result.sub!(/\s*\}\s*\Z/, "\nreturn Qnil;\n}")
62
+ end
63
+ else
64
+ prefix = "static #{return_type} #{function_name}("
65
+ result.sub!(/[^;\/\"\>]+#{function_name}\s*\(/, prefix)
66
+ result.sub!(/\A\n/, '') # strip off the \n in front in case we added it
67
+ end
68
+
69
+ delta = if result =~ /\A(static.*?\{)/m then
70
+ $1.split(/\n/).size
71
+ else
72
+ warn "WAR\NING: Can't find signature in #{result.inspect}\n" unless $TESTING
73
+ 0
74
+ end
75
+
76
+ file, line = caller[1].split(/:/)
77
+ result = "# line #{line.to_i + delta} \"#{file}\"\n" + result unless $DEBUG and not $TESTING
78
+
79
+ @src << result
80
+ @sig[function_name] = [arity,singleton,method_name]
81
+
82
+ return result if $TESTING
83
+ end # def generate
84
+
85
+ end
86
+ end
87
+
@@ -0,0 +1,37 @@
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
+ require "logger"
22
+
23
+ module FastRuby
24
+ module SingletonLogger
25
+ def logger
26
+ unless @logger
27
+ @logger = Logger.new(ENV['FASTRUBY_LOG'] || "/dev/stdout")
28
+ @logger.level = (ENV['FASTRUBY_LOG_LEVEL']||"2").to_i
29
+ end
30
+ @logger
31
+ end
32
+ end
33
+
34
+ class << self
35
+ include SingletonLogger
36
+ end
37
+ end
@@ -0,0 +1,168 @@
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
+ require "fastruby/translator"
22
+ require "fastruby/builder"
23
+ require "fastruby/getlocals"
24
+ require "ruby_parser"
25
+ require "inline"
26
+
27
+ # clean rubyinline cache
28
+ system("rm -fr #{ENV["HOME"]}/.ruby_inline/*")
29
+
30
+ class Object
31
+ def self.fastruby(rubycode, *options_hashes)
32
+ tree = RubyParser.new.parse rubycode
33
+
34
+ options_hash = {:validate_lvar_types => true}
35
+ options_hashes.each do |opt|
36
+ options_hash.merge!(opt)
37
+ end
38
+
39
+ if tree[0] != :defn
40
+ raise ArgumentError, "Only definition of methods are accepted"
41
+ end
42
+
43
+ method_name = tree[1]
44
+ args_tree = tree[2]
45
+
46
+ hashname = "$hash" + rand(1000000).to_s
47
+
48
+ hash = Hash.new
49
+
50
+ locals = Set.new
51
+ locals << :self
52
+
53
+ FastRuby::GetLocalsProcessor.get_locals(RubyParser.new.parse(rubycode)).each do |local|
54
+ locals << local
55
+ end
56
+
57
+ self_ = self
58
+ hash.instance_eval{@klass = self_}
59
+ hash.instance_eval{@method_name = method_name}
60
+
61
+ class_eval do
62
+ class << self
63
+ include FastRuby::BuilderModule
64
+ end
65
+ end
66
+
67
+ self_.method_tree[method_name] = tree
68
+ self_.method_locals[method_name] = locals
69
+ self_.method_options[method_name] = options_hash
70
+
71
+ def hash.build(key)
72
+ @klass.build(key, @method_name)
73
+ end
74
+
75
+ eval("#{hashname} = hash")
76
+
77
+ value_cast = ( ["VALUE"]*(args_tree.size+1) ).join(",")
78
+
79
+ main_signature_argument = args_tree[1..-1].first || "self"
80
+
81
+ strmethodargs = ""
82
+ strmethodargs_class = (["self"] + args_tree[1..-1]).map{|arg| "CLASS_OF(#{arg.to_s})"}.join(",")
83
+
84
+ if args_tree.size > 1
85
+ strmethodargs = "self,block,#{args_tree[1..-1].map(&:to_s).join(",") }"
86
+ else
87
+ strmethodargs = "self,block"
88
+ end
89
+
90
+ strmethod_signature = (["self"] + args_tree[1..-1]).map { |arg|
91
+ "sprintf(method_name+strlen(method_name), \"%lu\", CLASS_OF(#{arg}));\n"
92
+ }.join
93
+
94
+ c_code = "VALUE #{method_name}(#{args_tree[1..-1].map{|arg| "VALUE #{arg}" }.join(",")}) {
95
+ VALUE method_hash = (VALUE)#{hash.internal_value};
96
+ VALUE klass = (VALUE)#{self.internal_value};
97
+
98
+ char method_name[0x100];
99
+
100
+ method_name[0] = '_';
101
+ method_name[1] = 0;
102
+
103
+ sprintf(method_name+1, \"#{method_name}\");
104
+ #{strmethod_signature}
105
+
106
+ NODE* body;
107
+ ID id;
108
+
109
+ id = rb_intern(method_name);
110
+ body = rb_method_node(klass,id);
111
+
112
+ if (body == 0) {
113
+ VALUE argv_class[] = {#{strmethodargs_class} };
114
+ VALUE signature = rb_ary_new4(#{args_tree.size},argv_class);
115
+
116
+ rb_funcall(method_hash, #{:build.to_i}, 1, signature);
117
+ body = rb_method_node(klass,id);
118
+ }
119
+
120
+ if (nd_type(body) == NODE_CFUNC) {
121
+ int argc = body->nd_argc;
122
+
123
+ VALUE block = Qfalse;
124
+
125
+ if (rb_block_given_p()) {
126
+ struct {
127
+ void *block_function_address;
128
+ void *block_function_param;
129
+ } block_struct;
130
+
131
+ block_struct.block_function_address = re_yield;
132
+ block_struct.block_function_param = 0;
133
+
134
+ block = (VALUE)&block_struct;
135
+ }
136
+
137
+ if (argc == #{args_tree.size}) {
138
+ return ((VALUE(*)(#{value_cast}))body->nd_cfnc)(#{strmethodargs});
139
+ } else if (argc == -1) {
140
+ VALUE argv[] = {#{(["block"]+args_tree[1..-1]).map(&:to_s).join(",")} };
141
+ return ((VALUE(*)(int,VALUE*,VALUE))body->nd_cfnc)(#{args_tree.size},argv,self);
142
+ } else if (argc == -2) {
143
+ VALUE argv[] = {#{(["block"]+args_tree[1..-1]).map(&:to_s).join(",")} };
144
+ return ((VALUE(*)(VALUE,VALUE))body->nd_cfnc)(self, rb_ary_new4(#{args_tree.size},argv));
145
+ } else {
146
+ rb_raise(rb_eArgError, \"wrong number of arguments (#{args_tree.size-1} for %d)\", argc);
147
+ }
148
+ }
149
+
150
+ return Qnil;
151
+ }"
152
+
153
+ inline :C do |builder|
154
+ builder.include "<node.h>"
155
+ builder.inc << "static VALUE re_yield(int argc, VALUE* argv, VALUE param) {
156
+ return rb_yield_splat(rb_ary_new4(argc,argv));
157
+ }"
158
+ builder.c c_code
159
+ end
160
+ end
161
+
162
+ inline :C do |builder|
163
+ builder.c "VALUE internal_value() {
164
+ return INT2FIX(self);
165
+ }"
166
+ end
167
+ end
168
+