fastruby 0.0.1

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.
@@ -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
+