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 +8 -0
- data/README +0 -1
- data/Rakefile +1 -1
- data/lib/fastruby/builder.rb +9 -2
- data/lib/fastruby/translator/modules/block.rb +92 -0
- data/lib/fastruby/translator/modules/call.rb +137 -0
- data/lib/fastruby/translator/modules/defn.rb +221 -0
- data/lib/fastruby/translator/modules/exceptions.rb +134 -0
- data/lib/fastruby/translator/modules/flow.rb +91 -0
- data/lib/fastruby/translator/modules/iter.rb +584 -0
- data/lib/fastruby/translator/modules/literal.rb +86 -0
- data/lib/fastruby/translator/modules/logical.rb +38 -0
- data/lib/fastruby/translator/modules/method_group.rb +174 -0
- data/lib/fastruby/translator/modules/nonlocal.rb +96 -0
- data/lib/fastruby/translator/modules/variable.rb +190 -0
- data/lib/fastruby/translator/translator.rb +1171 -0
- data/lib/fastruby/translator/translator_modules.rb +49 -0
- data/lib/fastruby.rb +1 -1
- data/spec/call/multiple_args_spec.rb +87 -0
- data/spec/defn/multiple_args_spec.rb +271 -0
- metadata +19 -7
- data/lib/fastruby/translator/call.rb +0 -2594
- data/lib/fastruby/translator/iter.rb +0 -2594
- data/lib/fastruby/translator.rb +0 -2594
@@ -0,0 +1,91 @@
|
|
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 FlowControlTranslator
|
23
|
+
|
24
|
+
register_translator_module self
|
25
|
+
|
26
|
+
def to_c_case(tree)
|
27
|
+
|
28
|
+
tmpvarname = "tmp" + rand(1000000).to_s;
|
29
|
+
|
30
|
+
code = tree[2..-2].map{|subtree|
|
31
|
+
|
32
|
+
# this subtree is a when
|
33
|
+
subtree[1][1..-1].map{|subsubtree|
|
34
|
+
c_calltree = s(:call, nil, :inline_c, s(:arglist, s(:str, tmpvarname), s(:false)))
|
35
|
+
calltree = s(:call, subsubtree, :===, s(:arglist, c_calltree))
|
36
|
+
"
|
37
|
+
if (RTEST(#{to_c_call(calltree, tmpvarname)})) {
|
38
|
+
return #{to_c(subtree[2])};
|
39
|
+
}
|
40
|
+
|
41
|
+
"
|
42
|
+
}.join("\n")
|
43
|
+
|
44
|
+
}.join("\n")
|
45
|
+
|
46
|
+
inline_block "
|
47
|
+
|
48
|
+
VALUE #{tmpvarname} = #{to_c tree[1]};
|
49
|
+
|
50
|
+
#{code};
|
51
|
+
|
52
|
+
return #{to_c tree[-1]};
|
53
|
+
"
|
54
|
+
end
|
55
|
+
|
56
|
+
def to_c_if(tree)
|
57
|
+
condition_tree = tree[1]
|
58
|
+
impl_tree = tree[2]
|
59
|
+
else_tree = tree[3]
|
60
|
+
|
61
|
+
inline_block "
|
62
|
+
if (RTEST(#{to_c condition_tree})) {
|
63
|
+
last_expression = #{to_c impl_tree};
|
64
|
+
}#{else_tree ?
|
65
|
+
" else {
|
66
|
+
last_expression = #{to_c else_tree};
|
67
|
+
}
|
68
|
+
" : ""
|
69
|
+
}
|
70
|
+
|
71
|
+
return last_expression;
|
72
|
+
"
|
73
|
+
end
|
74
|
+
|
75
|
+
def to_c_for(tree)
|
76
|
+
alter_tree = tree.dup
|
77
|
+
alter_tree[0] = :iter
|
78
|
+
alter_tree[1] = [:call, alter_tree[1], :each, [:arglist]]
|
79
|
+
to_c alter_tree
|
80
|
+
end
|
81
|
+
|
82
|
+
def to_c_while(tree)
|
83
|
+
inline_block("
|
84
|
+
while (#{to_c tree[1]}) {
|
85
|
+
#{to_c tree[2]};
|
86
|
+
}
|
87
|
+
return Qnil;
|
88
|
+
")
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
@@ -0,0 +1,584 @@
|
|
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 IterTranslator
|
23
|
+
|
24
|
+
register_translator_module IterTranslator
|
25
|
+
|
26
|
+
def to_c_iter(tree)
|
27
|
+
|
28
|
+
call_tree = tree[1]
|
29
|
+
args_tree = tree[2]
|
30
|
+
recv_tree = call_tree[1]
|
31
|
+
|
32
|
+
directive_code = directive(call_tree)
|
33
|
+
if directive_code
|
34
|
+
return directive_code
|
35
|
+
end
|
36
|
+
|
37
|
+
other_call_tree = call_tree.dup
|
38
|
+
other_call_tree[1] = s(:lvar, :arg)
|
39
|
+
|
40
|
+
mname = call_tree[2]
|
41
|
+
|
42
|
+
call_args_tree = call_tree[3]
|
43
|
+
|
44
|
+
caller_code = nil
|
45
|
+
|
46
|
+
recvtype = infer_type(recv_tree || s(:self))
|
47
|
+
|
48
|
+
address = nil
|
49
|
+
mobject = nil
|
50
|
+
len = nil
|
51
|
+
|
52
|
+
extra_inference = {}
|
53
|
+
|
54
|
+
if recvtype
|
55
|
+
|
56
|
+
inference_complete = true
|
57
|
+
signature = [recvtype]
|
58
|
+
|
59
|
+
call_args_tree[1..-1].each do |arg|
|
60
|
+
argtype = infer_type(arg)
|
61
|
+
if argtype
|
62
|
+
signature << argtype
|
63
|
+
else
|
64
|
+
inference_complete = false
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
if recvtype.respond_to? :fastruby_method and inference_complete
|
69
|
+
method_tree = nil
|
70
|
+
begin
|
71
|
+
method_tree = recvtype.instance_method(call_tree[2]).fastruby.tree
|
72
|
+
rescue NoMethodError
|
73
|
+
end
|
74
|
+
|
75
|
+
if method_tree
|
76
|
+
mobject = recvtype.build(signature, call_tree[2])
|
77
|
+
yield_signature = mobject.yield_signature
|
78
|
+
|
79
|
+
if not args_tree
|
80
|
+
elsif args_tree.first == :lasgn
|
81
|
+
if yield_signature[0]
|
82
|
+
extra_inference[args_tree.last] = yield_signature[0]
|
83
|
+
end
|
84
|
+
elsif args_tree.first == :masgn
|
85
|
+
yield_args = args_tree[1][1..-1].map(&:last)
|
86
|
+
(0...yield_signature.size-1).each do |i|
|
87
|
+
extra_inference[yield_args[i]] = yield_signature[i]
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
anonymous_impl = tree[3]
|
95
|
+
|
96
|
+
str_lvar_initialization = "#{@frame_struct} *pframe;
|
97
|
+
#{@locals_struct} *plocals;
|
98
|
+
pframe = (void*)param;
|
99
|
+
plocals = (void*)pframe->plocals;
|
100
|
+
"
|
101
|
+
|
102
|
+
str_arg_initialization = ""
|
103
|
+
|
104
|
+
str_impl = ""
|
105
|
+
|
106
|
+
with_extra_inference(extra_inference) do
|
107
|
+
|
108
|
+
on_block do
|
109
|
+
# if impl_tree is a block, implement the last node with a return
|
110
|
+
if anonymous_impl
|
111
|
+
if anonymous_impl[0] == :block
|
112
|
+
str_impl = anonymous_impl[1..-2].map{ |subtree|
|
113
|
+
to_c(subtree)
|
114
|
+
}.join(";")
|
115
|
+
|
116
|
+
if anonymous_impl[-1][0] != :return and anonymous_impl[-1][0] != :break and anonymous_impl[-1][0] != :next
|
117
|
+
str_impl = str_impl + ";last_expression = (#{to_c(anonymous_impl[-1])});"
|
118
|
+
else
|
119
|
+
str_impl = str_impl + ";#{to_c(anonymous_impl[-1])};"
|
120
|
+
end
|
121
|
+
else
|
122
|
+
if anonymous_impl[0] != :return and anonymous_impl[0] != :break and anonymous_impl[0] != :next
|
123
|
+
str_impl = str_impl + ";last_expression = (#{to_c(anonymous_impl)});"
|
124
|
+
else
|
125
|
+
str_impl = str_impl + ";#{to_c(anonymous_impl)};"
|
126
|
+
end
|
127
|
+
end
|
128
|
+
else
|
129
|
+
str_impl = "last_expression = Qnil;"
|
130
|
+
end
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
|
135
|
+
if not args_tree
|
136
|
+
str_arg_initialization = ""
|
137
|
+
elsif args_tree.first == :lasgn
|
138
|
+
str_arg_initialization = "plocals->#{args_tree[1]} = arg;"
|
139
|
+
elsif args_tree.first == :masgn
|
140
|
+
arguments = args_tree[1][1..-1].map(&:last)
|
141
|
+
|
142
|
+
(0..arguments.size-1).each do |i|
|
143
|
+
str_arg_initialization << "plocals->#{arguments[i]} = rb_ary_entry(arg,#{i});\n"
|
144
|
+
end
|
145
|
+
end
|
146
|
+
rb_funcall_caller_code = nil
|
147
|
+
|
148
|
+
if call_args_tree.size > 1
|
149
|
+
|
150
|
+
str_recv = "pframe->next_recv"
|
151
|
+
|
152
|
+
str_recv = "plocals->self" unless recv_tree
|
153
|
+
if call_args_tree.last[0] == :splat
|
154
|
+
rb_funcall_caller_code = proc { |name| "
|
155
|
+
static VALUE #{name}(VALUE param) {
|
156
|
+
// call to #{call_tree[2]}
|
157
|
+
|
158
|
+
#{str_lvar_initialization}
|
159
|
+
|
160
|
+
VALUE array = #{to_c call_args_tree.last[1]};
|
161
|
+
|
162
|
+
if (TYPE(array) != T_ARRAY) {
|
163
|
+
array = rb_ary_new4(1,&array);
|
164
|
+
}
|
165
|
+
|
166
|
+
int argc = #{call_args_tree.size-2};
|
167
|
+
VALUE argv[#{call_args_tree.size} + RARRAY(array)->len];
|
168
|
+
|
169
|
+
#{
|
170
|
+
i = -1
|
171
|
+
call_args_tree[1..-2].map {|arg|
|
172
|
+
i = i + 1
|
173
|
+
"argv[#{i}] = #{to_c arg}"
|
174
|
+
}.join(";\n")
|
175
|
+
};
|
176
|
+
|
177
|
+
int array_len = RARRAY(array)->len;
|
178
|
+
|
179
|
+
int i;
|
180
|
+
for (i=0; i<array_len;i++) {
|
181
|
+
argv[argc] = rb_ary_entry(array,i);
|
182
|
+
argc++;
|
183
|
+
}
|
184
|
+
|
185
|
+
return rb_funcall2(#{str_recv}, #{intern_num call_tree[2]}, argc, argv);
|
186
|
+
}
|
187
|
+
"
|
188
|
+
}
|
189
|
+
else
|
190
|
+
str_called_code_args = call_args_tree[1..-1].map{ |subtree| to_c subtree }.join(",")
|
191
|
+
rb_funcall_caller_code = proc { |name| "
|
192
|
+
static VALUE #{name}(VALUE param) {
|
193
|
+
// call to #{call_tree[2]}
|
194
|
+
|
195
|
+
#{str_lvar_initialization}
|
196
|
+
return rb_funcall(#{str_recv}, #{intern_num call_tree[2]}, #{call_args_tree.size-1}, #{str_called_code_args});
|
197
|
+
}
|
198
|
+
"
|
199
|
+
}
|
200
|
+
end
|
201
|
+
|
202
|
+
rb_funcall_caller_code_with_lambda = rb_funcall_caller_code
|
203
|
+
else
|
204
|
+
str_recv = "pframe->next_recv"
|
205
|
+
str_recv = "plocals->self" unless recv_tree
|
206
|
+
|
207
|
+
rb_funcall_caller_code = proc { |name| "
|
208
|
+
static VALUE #{name}(VALUE param) {
|
209
|
+
// call to #{call_tree[2]}
|
210
|
+
#{str_lvar_initialization}
|
211
|
+
return rb_funcall(#{str_recv}, #{intern_num call_tree[2]}, 0);
|
212
|
+
}
|
213
|
+
"
|
214
|
+
}
|
215
|
+
|
216
|
+
rb_funcall_caller_code_with_lambda = proc { |name| "
|
217
|
+
static VALUE #{name}(VALUE param) {
|
218
|
+
// call to #{call_tree[2]}
|
219
|
+
#{str_lvar_initialization}
|
220
|
+
VALUE ret = rb_funcall(#{str_recv}, #{intern_num call_tree[2]}, 0);
|
221
|
+
|
222
|
+
// freeze all stacks
|
223
|
+
struct FASTRUBYTHREADDATA* thread_data = rb_current_thread_data();
|
224
|
+
|
225
|
+
if (thread_data != 0) {
|
226
|
+
VALUE rb_stack_chunk = thread_data->rb_stack_chunk;
|
227
|
+
|
228
|
+
// add reference to stack chunk to lambda object
|
229
|
+
rb_ivar_set(ret,#{intern_num :_fastruby_stack_chunk},rb_stack_chunk);
|
230
|
+
|
231
|
+
// freeze the complete chain of stack chunks
|
232
|
+
while (rb_stack_chunk != Qnil) {
|
233
|
+
struct STACKCHUNK* stack_chunk;
|
234
|
+
Data_Get_Struct(rb_stack_chunk,struct STACKCHUNK,stack_chunk);
|
235
|
+
|
236
|
+
stack_chunk_freeze(stack_chunk);
|
237
|
+
|
238
|
+
rb_stack_chunk = rb_ivar_get(rb_stack_chunk,#{intern_num :_parent_stack_chunk});
|
239
|
+
}
|
240
|
+
}
|
241
|
+
|
242
|
+
return ret;
|
243
|
+
}
|
244
|
+
"
|
245
|
+
}
|
246
|
+
|
247
|
+
end
|
248
|
+
|
249
|
+
rb_funcall_block_code_with_lambda = proc { |name| "
|
250
|
+
static VALUE #{name}(VALUE arg, VALUE _plocals) {
|
251
|
+
// block for call to #{call_tree[2]}
|
252
|
+
VALUE last_expression = Qnil;
|
253
|
+
|
254
|
+
#{@frame_struct} frame;
|
255
|
+
#{@frame_struct} *pframe = (void*)&frame;
|
256
|
+
#{@locals_struct} *plocals = (void*)_plocals;
|
257
|
+
|
258
|
+
frame.plocals = plocals;
|
259
|
+
frame.parent_frame = 0;
|
260
|
+
frame.return_value = Qnil;
|
261
|
+
frame.rescue = 0;
|
262
|
+
frame.targetted = 0;
|
263
|
+
frame.thread_data = rb_current_thread_data();
|
264
|
+
|
265
|
+
// create a fake parent frame representing the lambda method frame and a fake locals scope
|
266
|
+
VALUE old_call_frame = ((typeof(plocals))(pframe->plocals))->call_frame;
|
267
|
+
((typeof(plocals))(pframe->plocals))->call_frame = LONG2FIX(pframe);
|
268
|
+
|
269
|
+
int aux = setjmp(frame.jmp);
|
270
|
+
if (aux != 0) {
|
271
|
+
if (aux == FASTRUBY_TAG_BREAK) {
|
272
|
+
return frame.return_value;
|
273
|
+
} else if (aux == FASTRUBY_TAG_NEXT) {
|
274
|
+
return pframe->thread_data->accumulator;
|
275
|
+
} else if (aux == FASTRUBY_TAG_REDO) {
|
276
|
+
// do nothing and let execute the block again
|
277
|
+
} else if (aux == FASTRUBY_TAG_RAISE) {
|
278
|
+
rb_funcall(((typeof(plocals))(pframe->plocals))->self, #{intern_num :raise}, 1, frame.thread_data->exception);
|
279
|
+
return Qnil;
|
280
|
+
} else {
|
281
|
+
if (aux == FASTRUBY_TAG_RETURN) {
|
282
|
+
if (plocals->targetted == 1) {
|
283
|
+
((typeof(plocals))(pframe->plocals))->call_frame = old_call_frame;
|
284
|
+
return ((typeof(plocals))(pframe->plocals))->return_value;
|
285
|
+
} else {
|
286
|
+
rb_raise(rb_eLocalJumpError, \"unexpected return\");
|
287
|
+
}
|
288
|
+
} else {
|
289
|
+
rb_raise(rb_eLocalJumpError, \"unexpected return\");
|
290
|
+
}
|
291
|
+
|
292
|
+
((typeof(plocals))(pframe->plocals))->call_frame = old_call_frame;
|
293
|
+
return frame.return_value;
|
294
|
+
|
295
|
+
}
|
296
|
+
}
|
297
|
+
|
298
|
+
#{str_arg_initialization}
|
299
|
+
#{str_impl}
|
300
|
+
|
301
|
+
((typeof(plocals))(pframe->plocals))->call_frame = old_call_frame;
|
302
|
+
return last_expression;
|
303
|
+
}
|
304
|
+
"
|
305
|
+
}
|
306
|
+
|
307
|
+
rb_funcall_block_code_proc_new = proc { |name| "
|
308
|
+
static VALUE #{name}(VALUE arg, VALUE _plocals) {
|
309
|
+
// block for call to #{call_tree[2]}
|
310
|
+
VALUE last_expression = Qnil;
|
311
|
+
|
312
|
+
#{@frame_struct} frame;
|
313
|
+
#{@frame_struct} *pframe = (void*)&frame;
|
314
|
+
#{@locals_struct} *plocals = (void*)_plocals;
|
315
|
+
|
316
|
+
frame.plocals = plocals;
|
317
|
+
frame.parent_frame = 0;
|
318
|
+
frame.return_value = Qnil;
|
319
|
+
frame.rescue = 0;
|
320
|
+
frame.targetted = 0;
|
321
|
+
frame.thread_data = rb_current_thread_data();
|
322
|
+
|
323
|
+
// create a fake parent frame representing the lambda method frame and a fake locals scope
|
324
|
+
VALUE old_call_frame = ((typeof(plocals))(pframe->plocals))->call_frame;
|
325
|
+
((typeof(plocals))(pframe->plocals))->call_frame = LONG2FIX(pframe);
|
326
|
+
|
327
|
+
int aux = setjmp(frame.jmp);
|
328
|
+
if (aux != 0) {
|
329
|
+
if (aux == FASTRUBY_TAG_NEXT) {
|
330
|
+
return pframe->thread_data->accumulator;
|
331
|
+
} else if (aux == FASTRUBY_TAG_REDO) {
|
332
|
+
// do nothing and let execute the block again
|
333
|
+
} else if (aux == FASTRUBY_TAG_RAISE) {
|
334
|
+
rb_funcall(((typeof(plocals))(pframe->plocals))->self, #{intern_num :raise}, 1, frame.thread_data->exception);
|
335
|
+
return Qnil;
|
336
|
+
} else {
|
337
|
+
if (plocals->targetted == 1) {
|
338
|
+
if (plocals->active == Qfalse) {
|
339
|
+
rb_raise(rb_eLocalJumpError,\"return from proc-closure\");
|
340
|
+
} else {
|
341
|
+
((typeof(plocals))(pframe->plocals))->call_frame = old_call_frame;
|
342
|
+
rb_jump_tag(aux);
|
343
|
+
}
|
344
|
+
} else {
|
345
|
+
rb_raise(rb_eLocalJumpError, \"unexpected return\");
|
346
|
+
}
|
347
|
+
}
|
348
|
+
}
|
349
|
+
|
350
|
+
#{str_arg_initialization}
|
351
|
+
#{str_impl}
|
352
|
+
|
353
|
+
((typeof(plocals))(pframe->plocals))->call_frame = old_call_frame;
|
354
|
+
|
355
|
+
return last_expression;
|
356
|
+
}
|
357
|
+
"
|
358
|
+
}
|
359
|
+
|
360
|
+
|
361
|
+
rb_funcall_block_code = proc { |name| "
|
362
|
+
static VALUE #{name}(VALUE arg, VALUE _plocals) {
|
363
|
+
// block for call to #{call_tree[2]}
|
364
|
+
VALUE last_expression = Qnil;
|
365
|
+
|
366
|
+
#{@frame_struct} frame;
|
367
|
+
#{@frame_struct} *pframe = (void*)&frame;
|
368
|
+
#{@locals_struct} *plocals = (void*)_plocals;
|
369
|
+
|
370
|
+
frame.plocals = plocals;
|
371
|
+
frame.parent_frame = 0;
|
372
|
+
frame.return_value = Qnil;
|
373
|
+
frame.rescue = 0;
|
374
|
+
frame.targetted = 0;
|
375
|
+
frame.thread_data = rb_current_thread_data();
|
376
|
+
|
377
|
+
int aux = setjmp(frame.jmp);
|
378
|
+
if (aux != 0) {
|
379
|
+
|
380
|
+
if (aux == FASTRUBY_TAG_NEXT) {
|
381
|
+
return pframe->thread_data->accumulator;
|
382
|
+
} else if (aux == FASTRUBY_TAG_REDO) {
|
383
|
+
// do nothing and let execute the block again
|
384
|
+
} else {
|
385
|
+
rb_jump_tag(aux);
|
386
|
+
return frame.return_value;
|
387
|
+
}
|
388
|
+
}
|
389
|
+
|
390
|
+
|
391
|
+
#{str_arg_initialization}
|
392
|
+
#{str_impl}
|
393
|
+
|
394
|
+
return last_expression;
|
395
|
+
}
|
396
|
+
"
|
397
|
+
}
|
398
|
+
|
399
|
+
|
400
|
+
fastruby_str_arg_initialization = ""
|
401
|
+
|
402
|
+
if not args_tree
|
403
|
+
fastruby_str_arg_initialization = ""
|
404
|
+
elsif args_tree.first == :lasgn
|
405
|
+
fastruby_str_arg_initialization = "plocals->#{args_tree[1]} = argv[0];"
|
406
|
+
elsif args_tree.first == :masgn
|
407
|
+
arguments = args_tree[1][1..-1].map(&:last)
|
408
|
+
|
409
|
+
(0..arguments.size-1).each do |i|
|
410
|
+
fastruby_str_arg_initialization << "plocals->#{arguments[i]} = #{i} < argc ? argv[#{i}] : Qnil;\n"
|
411
|
+
end
|
412
|
+
end
|
413
|
+
|
414
|
+
block_code = proc { |name| "
|
415
|
+
static VALUE #{name}(int argc, VALUE* argv, VALUE _locals, VALUE _parent_frame) {
|
416
|
+
// block for call to #{call_tree[2]}
|
417
|
+
VALUE last_expression = Qnil;
|
418
|
+
#{@frame_struct} frame;
|
419
|
+
#{@frame_struct} *pframe = (void*)&frame;
|
420
|
+
#{@frame_struct} *parent_frame = (void*)_parent_frame;
|
421
|
+
#{@locals_struct} *plocals;
|
422
|
+
|
423
|
+
frame.plocals = (void*)_locals;
|
424
|
+
frame.parent_frame = parent_frame;
|
425
|
+
frame.return_value = Qnil;
|
426
|
+
frame.rescue = 0;
|
427
|
+
frame.targetted = 0;
|
428
|
+
frame.thread_data = parent_frame->thread_data;
|
429
|
+
if (frame.thread_data == 0) frame.thread_data = rb_current_thread_data();
|
430
|
+
|
431
|
+
plocals = frame.plocals;
|
432
|
+
|
433
|
+
int aux = setjmp(frame.jmp);
|
434
|
+
if (aux != 0) {
|
435
|
+
if (pframe->targetted == 0) {
|
436
|
+
if (aux == FASTRUBY_TAG_NEXT) {
|
437
|
+
return pframe->thread_data->accumulator;
|
438
|
+
} else if (aux == FASTRUBY_TAG_REDO) {
|
439
|
+
// do nothing and let execute the block again
|
440
|
+
} else {
|
441
|
+
longjmp(((typeof(pframe))_parent_frame)->jmp,aux);
|
442
|
+
}
|
443
|
+
}
|
444
|
+
|
445
|
+
}
|
446
|
+
|
447
|
+
#{fastruby_str_arg_initialization}
|
448
|
+
#{str_impl}
|
449
|
+
|
450
|
+
return last_expression;
|
451
|
+
}
|
452
|
+
"
|
453
|
+
}
|
454
|
+
|
455
|
+
str_recv = "plocals->self"
|
456
|
+
|
457
|
+
if recv_tree
|
458
|
+
str_recv = to_c recv_tree
|
459
|
+
end
|
460
|
+
|
461
|
+
caller_code = nil
|
462
|
+
convention_global_name = add_global_name("int",0)
|
463
|
+
|
464
|
+
call_frame_struct_code = "
|
465
|
+
#{@block_struct} block;
|
466
|
+
#{@locals_struct} *plocals = (void*)param;
|
467
|
+
|
468
|
+
block.block_function_address = (void*)#{anonymous_function(&block_code)};
|
469
|
+
block.block_function_param = (void*)param;
|
470
|
+
|
471
|
+
// create a call_frame
|
472
|
+
#{@frame_struct} call_frame;
|
473
|
+
|
474
|
+
call_frame.parent_frame = (void*)pframe;
|
475
|
+
call_frame.plocals = plocals;
|
476
|
+
call_frame.return_value = Qnil;
|
477
|
+
call_frame.targetted = 0;
|
478
|
+
call_frame.thread_data = rb_current_thread_data();
|
479
|
+
|
480
|
+
VALUE old_call_frame = plocals->call_frame;
|
481
|
+
plocals->call_frame = LONG2FIX(&call_frame);
|
482
|
+
|
483
|
+
int aux = setjmp(call_frame.jmp);
|
484
|
+
if (aux != 0) {
|
485
|
+
#{@frame_struct}* pframe_ = (void*)pframe;
|
486
|
+
|
487
|
+
if (aux == FASTRUBY_TAG_RETRY ) {
|
488
|
+
// do nothing and let the call execute again
|
489
|
+
} else {
|
490
|
+
if (call_frame.targetted == 0) {
|
491
|
+
longjmp(pframe_->jmp,aux);
|
492
|
+
}
|
493
|
+
|
494
|
+
plocals->call_frame = old_call_frame;
|
495
|
+
return call_frame.return_value;
|
496
|
+
}
|
497
|
+
}
|
498
|
+
"
|
499
|
+
|
500
|
+
funcall_call_code = "
|
501
|
+
return #{
|
502
|
+
frame_call(
|
503
|
+
protected_block(inline_block("
|
504
|
+
|
505
|
+
pframe->next_recv = #{recv_tree ? to_c(recv_tree) : "plocals->self"};
|
506
|
+
|
507
|
+
NODE* node = rb_method_node(CLASS_OF(pframe->next_recv), #{intern_num mname});
|
508
|
+
void* caller_func;
|
509
|
+
void* block_func;
|
510
|
+
|
511
|
+
if (
|
512
|
+
node == #{@proc_node_gvar} ||
|
513
|
+
node == #{@lambda_node_gvar}
|
514
|
+
) {
|
515
|
+
|
516
|
+
caller_func = #{anonymous_function(&rb_funcall_caller_code_with_lambda)};
|
517
|
+
block_func = #{anonymous_function(&rb_funcall_block_code_with_lambda)};
|
518
|
+
} else if (node == #{@procnew_node_gvar} && pframe->next_recv == rb_cProc) {
|
519
|
+
caller_func = #{anonymous_function(&rb_funcall_caller_code_with_lambda)};
|
520
|
+
block_func = #{anonymous_function(&rb_funcall_block_code_proc_new)};
|
521
|
+
} else {
|
522
|
+
caller_func = #{anonymous_function(&rb_funcall_caller_code)};
|
523
|
+
block_func = #{anonymous_function(&rb_funcall_block_code)};
|
524
|
+
}
|
525
|
+
|
526
|
+
return rb_iterate(
|
527
|
+
caller_func,
|
528
|
+
(VALUE)pframe,
|
529
|
+
block_func,
|
530
|
+
(VALUE)plocals);
|
531
|
+
|
532
|
+
"), true)
|
533
|
+
)
|
534
|
+
};
|
535
|
+
"
|
536
|
+
|
537
|
+
if call_args_tree.size > 1 ? call_args_tree.last[0] == :splat : false
|
538
|
+
inline_block "
|
539
|
+
#{funcall_call_code}
|
540
|
+
"
|
541
|
+
else
|
542
|
+
|
543
|
+
if call_args_tree.size > 1
|
544
|
+
value_cast = ( ["VALUE"]*(call_tree[3].size) ).join(",") + ", VALUE, VALUE"
|
545
|
+
|
546
|
+
str_called_code_args = call_tree[3][1..-1].map{|subtree| to_c subtree}.join(",")
|
547
|
+
|
548
|
+
caller_code = proc { |name| "
|
549
|
+
static VALUE #{name}(VALUE param, VALUE pframe) {
|
550
|
+
// call to #{call_tree[2]}
|
551
|
+
#{call_frame_struct_code}
|
552
|
+
|
553
|
+
VALUE ret = ((VALUE(*)(#{value_cast}))#{encode_address(recvtype,signature,mname,call_tree,inference_complete,convention_global_name)})(#{str_recv}, (VALUE)&block, (VALUE)&call_frame, #{str_called_code_args});
|
554
|
+
plocals->call_frame = old_call_frame;
|
555
|
+
return ret;
|
556
|
+
}
|
557
|
+
"
|
558
|
+
}
|
559
|
+
|
560
|
+
else
|
561
|
+
caller_code = proc { |name| "
|
562
|
+
static VALUE #{name}(VALUE param, VALUE pframe) {
|
563
|
+
#{call_frame_struct_code}
|
564
|
+
|
565
|
+
// call to #{call_tree[2]}
|
566
|
+
VALUE ret = ((VALUE(*)(VALUE,VALUE,VALUE))#{encode_address(recvtype,signature,mname,call_tree,inference_complete,convention_global_name)})(#{str_recv}, (VALUE)&block, (VALUE)&call_frame);
|
567
|
+
plocals->call_frame = old_call_frame;
|
568
|
+
return ret;
|
569
|
+
}
|
570
|
+
"
|
571
|
+
}
|
572
|
+
end
|
573
|
+
|
574
|
+
inline_block "
|
575
|
+
if (#{convention_global_name}) {
|
576
|
+
return #{anonymous_function(&caller_code)}((VALUE)plocals, (VALUE)pframe);
|
577
|
+
} else {
|
578
|
+
#{funcall_call_code}
|
579
|
+
}
|
580
|
+
"
|
581
|
+
end
|
582
|
+
end
|
583
|
+
end
|
584
|
+
end
|