fastruby 0.0.12 → 0.0.13

Sign up to get free protection for your applications and to get access to all the features.
data/CHANGELOG CHANGED
@@ -1,3 +1,11 @@
1
+ 0.0.13 Argument splat method calls (not optimized yet)
2
+
3
+ Array arguments on methods (optional arguments, variable number of arguments)
4
+
5
+ Fixed bug of return when trying to return from a proc (illegal overwrite of memory on stack when trying to flag frame as targetted)
6
+
7
+ Internal refactor
8
+
1
9
  0.0.12 Completed exception support (multiple rescue clauses, multiple exceptions in only one rescue, assign exceptions to variables and fastruby internal exceptions)
2
10
 
3
11
  0.0.11 Fixed packaging error
data/README CHANGED
@@ -61,7 +61,6 @@ I will stabilize the API and document it for next releases. I promise
61
61
  * callcc is not supported, it works but using it may result in unexpected behaviour
62
62
  * recursive methods will be slow since the optimization of method calls only works with already defined methods
63
63
  * 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)
64
- * does not support methods with variable number of arguments
65
64
 
66
65
  == Usage
67
66
 
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.12'
10
+ s.version = '0.0.13'
11
11
  s.author = 'Dario Seminara'
12
12
  s.email = 'robertodarioseminara@gmail.com'
13
13
  s.platform = Gem::Platform::RUBY
@@ -88,7 +88,14 @@ module FastRuby
88
88
  end
89
89
 
90
90
  if method_tree
91
- :fastruby
91
+
92
+ args_tree = method_tree[2]
93
+
94
+ if args_tree.any?{|x|x.to_s.match(/\*/)}
95
+ :fastruby_array
96
+ else
97
+ :fastruby
98
+ end
92
99
  else
93
100
  :cruby
94
101
  end
@@ -98,7 +105,7 @@ module FastRuby
98
105
  end
99
106
 
100
107
  def build(signature, noreturn = false)
101
- require "fastruby/translator"
108
+ require "fastruby/translator/translator"
102
109
  require "rubygems"
103
110
  require "inline"
104
111
 
@@ -0,0 +1,92 @@
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
+ module BlockTranslator
23
+
24
+ register_translator_module self
25
+
26
+ def to_c_yield(tree)
27
+
28
+ block_code = proc { |name| "
29
+ static VALUE #{name}(VALUE frame_param, VALUE* block_args) {
30
+
31
+ #{@locals_struct} *plocals;
32
+ #{@frame_struct} *pframe;
33
+ pframe = (void*)frame_param;
34
+ plocals = (void*)pframe->plocals;
35
+
36
+ if (FIX2LONG(plocals->block_function_address) == 0) {
37
+ #{_raise("rb_eLocalJumpError", "no block given")};
38
+ } else {
39
+ return ((VALUE(*)(int,VALUE*,VALUE,VALUE))FIX2LONG(plocals->block_function_address))(#{tree.size-1}, block_args, FIX2LONG(plocals->block_function_param), (VALUE)pframe);
40
+ }
41
+ }
42
+ "
43
+ }
44
+
45
+ new_yield_signature = tree[1..-1].map{|subtree| infer_type subtree}
46
+ # merge the new_yield_signature with the new
47
+ if @yield_signature
48
+ if new_yield_signature.size == @yield_signature.size
49
+ (0..new_yield_signature.size-1).each do |i|
50
+ if @yield_signature[i] != new_yield_signature[i]
51
+ @yield_signature[i] = nil
52
+ end
53
+ end
54
+ else
55
+ @yield_signature = new_yield_signature.map{|x| nil}
56
+ end
57
+ else
58
+ @yield_signature = new_yield_signature
59
+ end
60
+
61
+ ret = if tree.size > 1
62
+ anonymous_function(&block_code)+"((VALUE)pframe, (VALUE[]){#{tree[1..-1].map{|subtree| to_c subtree}.join(",")}})"
63
+ else
64
+ anonymous_function(&block_code)+"((VALUE)pframe, (VALUE[]){})"
65
+ end
66
+
67
+ protected_block(ret, false)
68
+ end
69
+
70
+ def to_c_block(tree)
71
+
72
+ str = ""
73
+ str = tree[1..-2].map{ |subtree|
74
+ to_c(subtree)
75
+ }.join(";")
76
+
77
+ if tree[-1]
78
+
79
+ if tree[-1][0] != :return
80
+ str = str + ";last_expression = #{to_c(tree[-1])};"
81
+ else
82
+ str = str + ";#{to_c(tree[-1])};"
83
+ end
84
+ end
85
+
86
+ str << "return last_expression;"
87
+
88
+ inline_block str
89
+ end
90
+
91
+ end
92
+ end
@@ -0,0 +1,137 @@
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
+ module CallTranslator
23
+
24
+ register_translator_module self
25
+
26
+ def to_c_call(tree, repass_var = nil)
27
+ directive_code = directive(tree)
28
+ if directive_code
29
+ return directive_code
30
+ end
31
+
32
+ if tree[2] == :require
33
+ tree[2] = :fastruby_require
34
+ elsif tree[2] == :raise
35
+ # raise code
36
+ args = tree[3]
37
+ return _raise(args[1],args[2])
38
+ end
39
+
40
+ recv = tree[1]
41
+ mname = tree[2]
42
+ args = tree[3]
43
+
44
+ mname = :require_fastruby if mname == :require
45
+
46
+ argnum = args.size - 1
47
+
48
+ recv = recv || s(:self)
49
+
50
+ recvtype = infer_type(recv)
51
+
52
+ if args.size > 1
53
+ if args.last[0] == :splat
54
+ return protected_block(
55
+ inline_block(
56
+ "
57
+
58
+ VALUE array = #{to_c args.last[1]};
59
+
60
+ if (TYPE(array) != T_ARRAY) {
61
+ array = rb_ary_new4(1,&array);
62
+ }
63
+
64
+ int argc = #{args.size-2};
65
+ VALUE argv[#{args.size} + RARRAY(array)->len];
66
+
67
+ #{
68
+ i = -1
69
+ args[1..-2].map {|arg|
70
+ i = i + 1
71
+ "argv[#{i}] = #{to_c arg}"
72
+ }.join(";\n")
73
+ };
74
+
75
+ int array_len = RARRAY(array)->len;
76
+
77
+ int i;
78
+ for (i=0; i<array_len;i++) {
79
+ argv[argc] = rb_ary_entry(array,i);
80
+ argc++;
81
+ }
82
+
83
+ return rb_funcall2(#{to_c recv}, #{intern_num tree[2]}, argc, argv);
84
+ "
85
+ ), true, repass_var)
86
+ end
87
+ end
88
+
89
+ strargs = args[1..-1].map{|arg| to_c arg}.join(",")
90
+
91
+ if recvtype
92
+
93
+ address = nil
94
+ mobject = nil
95
+
96
+ inference_complete = true
97
+ signature = [recvtype]
98
+
99
+ args[1..-1].each do |arg|
100
+ argtype = infer_type(arg)
101
+ if argtype
102
+ signature << argtype
103
+ else
104
+ inference_complete = false
105
+ end
106
+ end
107
+
108
+ if repass_var
109
+ extraargs = ","+repass_var
110
+ extraargs_signature = ",VALUE " + repass_var
111
+ else
112
+ extraargs = ""
113
+ extraargs_signature = ""
114
+ end
115
+
116
+ if argnum == 0
117
+ value_cast = "VALUE,VALUE,VALUE"
118
+ "((VALUE(*)(#{value_cast}))#{encode_address(recvtype,signature,mname,tree,inference_complete)})(#{to_c recv}, Qfalse, (VALUE)pframe)"
119
+ else
120
+ value_cast = ( ["VALUE"]*(args.size) ).join(",") + ",VALUE,VALUE"
121
+ "((VALUE(*)(#{value_cast}))#{encode_address(recvtype,signature,mname,tree,inference_complete)})(#{to_c recv}, Qfalse, (VALUE)pframe, #{strargs})"
122
+ end
123
+
124
+ else # else recvtype
125
+ if argnum == 0
126
+ protected_block("rb_funcall(#{to_c recv}, #{intern_num tree[2]}, 0)", true, repass_var)
127
+ else
128
+ protected_block("rb_funcall(#{to_c recv}, #{intern_num tree[2]}, #{argnum}, #{strargs} )", true, repass_var)
129
+ end
130
+ end # if recvtype
131
+ end
132
+
133
+ def to_c_attrasgn(tree)
134
+ to_c_call(tree)
135
+ end
136
+ end
137
+ end
@@ -0,0 +1,221 @@
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
+ module DefnTranslator
23
+ register_translator_module self
24
+
25
+ def to_c_defn(tree)
26
+
27
+ method_name = tree[1]
28
+ args_tree = tree[2]
29
+
30
+ global_klass_variable = add_global_name("VALUE", "Qnil");
31
+
32
+ hash = Hash.new
33
+ value_cast = ( ["VALUE"]*(args_tree.size+2) ).join(",")
34
+
35
+ multiple_arguments = args_tree[1..-1].find{|x| x.to_s =~ /\*/}
36
+
37
+ args_array_accessors = if multiple_arguments
38
+ (0..args_tree.size-3).map{|x| "argv[#{x}]"} + ["argarray"]
39
+ else
40
+ (0..args_tree.size-2).map{|x| "argv[#{x}]"}
41
+ end
42
+
43
+ strmethodargs = ""
44
+
45
+ if args_tree.size > 1
46
+ strmethodargs = "self,block,(VALUE)&frame,#{args_array_accessors.map(&:to_s).join(",") }"
47
+ else
48
+ strmethodargs = "self,block,(VALUE)&frame"
49
+ end
50
+
51
+ strmakecall = if multiple_arguments
52
+ "
53
+ if (argc_ > #{args_tree.size-2}) {
54
+ VALUE argarray = rb_ary_new4(argc_-#{args_tree.size-2}, argv+#{args_tree.size-2});
55
+ return ((VALUE(*)(#{value_cast}))body->nd_cfnc)(#{strmethodargs});
56
+ } else if (argc_ == #{args_tree.size-2}) {
57
+ // pass pre-calculated method arguments plus an empty array
58
+ VALUE argarray = rb_ary_new();
59
+ return ((VALUE(*)(#{value_cast}))body->nd_cfnc)(#{strmethodargs});
60
+ } else {
61
+ rb_raise(rb_eArgError, \"wrong number of arguments (%d for #{args_tree.size-2}))\", argc_);
62
+ }
63
+ "
64
+ else
65
+ "if (argc_ == #{args_tree.size-1} && argc == #{args_tree.size+1}) {
66
+ return ((VALUE(*)(#{value_cast}))body->nd_cfnc)(#{strmethodargs});
67
+ } else {
68
+ rb_raise(rb_eArgError, \"wrong number of arguments (%d for #{args_tree.size-1}))\", argc_);
69
+ }"
70
+ end
71
+
72
+ anonymous_method_name = anonymous_function{ |anonymous_method_name| "VALUE #{anonymous_method_name}(int argc_, VALUE* argv, VALUE self) {
73
+
74
+ VALUE klass = #{global_klass_variable};
75
+ char method_name[0x100];
76
+
77
+ method_name[0] = '_';
78
+ method_name[1] = 0;
79
+
80
+ sprintf(method_name+1, \"#{method_name}\");
81
+
82
+ int i;
83
+ for (i=0; i<argc_; i++) {
84
+ sprintf(method_name+strlen(method_name), \"%lu\", FIX2LONG(rb_obj_id(CLASS_OF(argv[i]))));
85
+ }
86
+
87
+ NODE* body;
88
+ ID id;
89
+
90
+ id = rb_intern(method_name);
91
+ body = rb_method_node(klass,id);
92
+
93
+ if (body == 0) {
94
+ VALUE argv_class[argc_+1];
95
+
96
+ argv_class[0] = CLASS_OF(self);
97
+ for (i=0; i<argc_; i++) {
98
+ argv_class[i+1] = CLASS_OF(argv[i]);
99
+ }
100
+
101
+ VALUE signature = rb_ary_new4(argc_+1,argv_class);
102
+ VALUE mobject = rb_funcall(#{global_klass_variable}, #{intern_num :build}, 2, signature,rb_str_new2(#{method_name.to_s.inspect}));
103
+
104
+ struct METHOD {
105
+ VALUE klass, rklass;
106
+ VALUE recv;
107
+ ID id, oid;
108
+ int safe_level;
109
+ NODE *body;
110
+ };
111
+
112
+ struct METHOD *data;
113
+ Data_Get_Struct(mobject, struct METHOD, data);
114
+ body = data->body;
115
+
116
+ if (body == 0) {
117
+ rb_raise(rb_eRuntimeError,\"method not found after build: '%s'\", method_name);
118
+ }
119
+ }
120
+
121
+ if (nd_type(body) == NODE_CFUNC) {
122
+ struct {
123
+ void* parent_frame;
124
+ void* plocals;
125
+ jmp_buf jmp;
126
+ VALUE return_value;
127
+ int rescue;
128
+ VALUE last_error;
129
+ VALUE next_recv;
130
+ int targetted;
131
+ struct FASTRUBYTHREADDATA* thread_data;
132
+ } frame;
133
+
134
+ frame.parent_frame = 0;
135
+ frame.rescue = 0;
136
+ frame.return_value = Qnil;
137
+ frame.thread_data = rb_current_thread_data();
138
+ frame.targetted = 0;
139
+
140
+ int argc = body->nd_argc;
141
+
142
+ VALUE block = Qfalse;
143
+
144
+ if (rb_block_given_p()) {
145
+ struct {
146
+ void *block_function_address;
147
+ void *block_function_param;
148
+ } block_struct;
149
+
150
+ block_struct.block_function_address = re_yield;
151
+ block_struct.block_function_param = 0;
152
+
153
+ block = (VALUE)&block_struct;
154
+ }
155
+
156
+ int aux = setjmp(frame.jmp);
157
+ if (aux != 0) {
158
+ if (aux == FASTRUBY_TAG_RAISE) {
159
+ rb_funcall(self, #{intern_num :raise}, 1, frame.thread_data->exception);
160
+ }
161
+
162
+ if (frame.targetted == 0) {
163
+ rb_jump_tag(aux);
164
+ }
165
+
166
+ return Qnil;
167
+ }
168
+
169
+ #{strmakecall}
170
+ }
171
+
172
+ return Qnil;
173
+ }"
174
+ }
175
+
176
+ alt_options = options.dup
177
+
178
+ alt_options.delete(:self)
179
+ alt_options.delete(:main)
180
+
181
+ inline_block "
182
+ #{global_klass_variable} = plocals->self;
183
+
184
+ // set tree
185
+ rb_funcall(#{literal_value FastRuby}, #{intern_num :set_tree}, 5,
186
+ #{global_klass_variable},
187
+ rb_str_new2(#{method_name.to_s.inspect}),
188
+ #{literal_value tree},
189
+ #{literal_value snippet_hash},
190
+ #{literal_value alt_options}
191
+
192
+ );
193
+
194
+ rb_define_method(plocals->self, #{method_name.to_s.inspect}, #{anonymous_method_name}, -1 );
195
+ "
196
+
197
+ end
198
+
199
+ def to_c_defs(tree)
200
+ args_tree = tree[3];
201
+
202
+ tmp = FastRuby.build_defs(tree)
203
+
204
+ extra_code << tmp[0]
205
+ @init_extra = @init_extra + tmp[2]
206
+
207
+ inline_block "
208
+ rb_define_singleton_method(#{to_c tree[1]}, \"#{tree[2].to_s}\", (void*)#{tmp[1]}, #{args_tree.size-1});
209
+ return Qnil;
210
+ "
211
+ end
212
+
213
+ def to_c_scope(tree)
214
+ if tree[1]
215
+ to_c(tree[1])
216
+ else
217
+ "Qnil"
218
+ end
219
+ end
220
+ end
221
+ end
@@ -0,0 +1,134 @@
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
+ module ExceptionsTranslator
23
+ register_translator_module self
24
+
25
+
26
+ def to_c_rescue(tree)
27
+ if tree[1][0] == :resbody
28
+ else_tree = tree[2]
29
+
30
+ if else_tree
31
+ to_c else_tree
32
+ else
33
+ "Qnil"
34
+ end
35
+ else
36
+ resbody_tree = tree[2]
37
+ else_tree = nil
38
+ if tree[-1]
39
+ if tree[-1][0] != :resbody
40
+ else_tree = tree[-1]
41
+ end
42
+ end
43
+
44
+ catch_condition_array = []
45
+ lasgn_code = ""
46
+ resbody_code = to_c(resbody_tree[2])
47
+
48
+ rescue_code = ""
49
+
50
+ tree[1..-1].each do |resbody_tree|
51
+ next if resbody_tree[0] != :resbody
52
+
53
+ if resbody_tree[1].size == 1
54
+ resbody_tree[1][1] = [:const, :Exception]
55
+ end
56
+
57
+ if resbody_tree[1].last[0] == :lasgn
58
+ lasgn_code = to_c(resbody_tree[1].last)
59
+ end
60
+
61
+ resbody_tree[1][1..-1].each do |xtree|
62
+ if xtree[0] != :lasgn
63
+ trapcode = "rb_eException";
64
+
65
+ if xtree
66
+ trapcode = to_c(xtree)
67
+ end
68
+
69
+ catch_condition_array << "(rb_obj_is_kind_of(frame.thread_data->exception,#{trapcode}) == Qtrue)"
70
+ end
71
+ end
72
+
73
+ rescue_code << "
74
+ if (aux == FASTRUBY_TAG_RAISE) {
75
+ if (#{catch_condition_array.join(" || ")})
76
+ {
77
+ // trap exception
78
+ frame.targetted = 1;
79
+
80
+ #{lasgn_code};
81
+
82
+ #{resbody_code};
83
+ }
84
+ }
85
+ "
86
+ end
87
+
88
+ frame_call(
89
+ frame(to_c(tree[1])+";","
90
+ #{rescue_code}
91
+ ", else_tree ? to_c(else_tree) : nil, 1)
92
+
93
+ )
94
+ end
95
+ end
96
+
97
+ def to_c_ensure(tree)
98
+ if tree.size == 2
99
+ to_c tree[1]
100
+ else
101
+ ensured_code = to_c tree[2]
102
+ inline_block "
103
+ #{frame(to_c(tree[1]),ensured_code,ensured_code,1)};
104
+ "
105
+ end
106
+ end
107
+
108
+ def _raise(class_tree, message_tree = nil)
109
+ class_tree = to_c class_tree unless class_tree.instance_of? String
110
+
111
+ if message_tree.instance_of? String
112
+ message_tree = "rb_str_new2(#{message_tree.inspect})"
113
+ else
114
+ message_tree = to_c message_tree
115
+ end
116
+
117
+ if message_tree
118
+ return inline_block("
119
+ pframe->thread_data->exception = rb_funcall(#{class_tree}, #{intern_num :exception},1,#{message_tree});
120
+ longjmp(pframe->jmp, FASTRUBY_TAG_RAISE);
121
+ return Qnil;
122
+ ")
123
+ else
124
+ return inline_block("
125
+ pframe->thread_data->exception = rb_funcall(#{class_tree}, #{intern_num :exception},0);
126
+ longjmp(pframe->jmp, FASTRUBY_TAG_RAISE);
127
+ return Qnil;
128
+ ")
129
+ end
130
+
131
+ end
132
+
133
+ end
134
+ end