fastruby 0.0.12 → 0.0.13

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/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