fastruby 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,903 @@
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 "inline"
23
+ require "set"
24
+
25
+ module FastRuby
26
+ class Context
27
+
28
+ attr_accessor :infer_lvar_map
29
+ attr_accessor :alt_method_name
30
+ attr_accessor :locals
31
+ attr_accessor :options
32
+ attr_accessor :infer_self
33
+ attr_reader :extra_code
34
+ attr_reader :yield_signature
35
+
36
+ def initialize
37
+ @infer_lvar_map = Hash.new
38
+ @extra_code = ""
39
+ @options = {}
40
+
41
+ extra_code << '#include "node.h"
42
+ '
43
+
44
+ extra_code << "static VALUE _rb_gvar_set(void* ge,VALUE value) {
45
+ rb_gvar_set((struct global_entry*)ge,value);
46
+ return value;
47
+ }
48
+ "
49
+
50
+ extra_code << "static VALUE _rb_ivar_set(VALUE recv,ID idvar, VALUE value) {
51
+ rb_ivar_set(recv,idvar,value);
52
+ return value;
53
+ }
54
+ "
55
+
56
+ extra_code << "static VALUE _lvar_assing(VALUE* destination,VALUE value) {
57
+ *destination = value;
58
+ return value;
59
+ }
60
+ "
61
+
62
+ end
63
+
64
+ def on_block
65
+ yield
66
+ end
67
+
68
+ def to_c(tree)
69
+ return "Qnil" unless tree
70
+ send("to_c_" + tree[0].to_s, tree);
71
+ end
72
+
73
+ def anonymous_function(method)
74
+
75
+ name = "anonymous" + rand(10000000).to_s
76
+ extra_code << method.call(name)
77
+
78
+ name
79
+ end
80
+
81
+ def to_c_dot2(tree)
82
+ "rb_range_new(#{to_c tree[1]}, #{to_c tree[2]},0)"
83
+ end
84
+
85
+ def to_c_attrasgn(tree)
86
+ to_c_call(tree)
87
+ end
88
+
89
+ def to_c_iter(tree)
90
+
91
+ call_tree = tree[1]
92
+ args_tree = tree[2]
93
+ recv_tree = call_tree[1]
94
+
95
+ directive_code = directive(call_tree)
96
+ if directive_code
97
+ return directive_code
98
+ end
99
+
100
+ other_call_tree = call_tree.dup
101
+ other_call_tree[1] = s(:lvar, :arg)
102
+
103
+ call_args_tree = call_tree[3]
104
+
105
+ caller_code = nil
106
+
107
+ str_lvar_initialization = @locals_struct + " *plocals;
108
+ plocals = (void*)param;"
109
+
110
+ recvtype = infer_type(recv_tree || s(:self))
111
+
112
+ address = nil
113
+ mobject = nil
114
+ len = nil
115
+
116
+ convention = :ruby
117
+
118
+ extra_inference = {}
119
+
120
+ if recvtype
121
+
122
+ inference_complete = true
123
+ signature = [recvtype]
124
+
125
+ call_args_tree[1..-1].each do |arg|
126
+ argtype = infer_type(arg)
127
+ if argtype
128
+ signature << argtype
129
+ else
130
+ inference_complete = false
131
+ end
132
+ end
133
+
134
+ convention = nil
135
+
136
+ if recvtype.respond_to? :method_tree and inference_complete
137
+
138
+ if recvtype.method_tree[call_tree[2]]
139
+ mobject = recvtype.build(signature, call_tree[2])
140
+ yield_signature = mobject.yield_signature
141
+
142
+ if not args_tree
143
+ elsif args_tree.first == :lasgn
144
+ if yield_signature[0]
145
+ extra_inference[args_tree.last] = yield_signature[0]
146
+ end
147
+ elsif args_tree.first == :masgn
148
+ yield_args = args_tree[1][1..-1].map(&:last)
149
+ (0...yield_signature.size-1).each do |i|
150
+ extra_inference[yield_args[i]] = yield_signature[i]
151
+ end
152
+ end
153
+
154
+ convention = :fastruby
155
+ else
156
+ mobject = recvtype.instance_method(call_tree[2])
157
+ convention = :cruby
158
+ end
159
+ else
160
+ mobject = recvtype.instance_method(call_tree[2])
161
+ convention = :cruby
162
+ end
163
+
164
+ address = getaddress(mobject)
165
+ len = getlen(mobject)
166
+
167
+ unless address
168
+ convention = :ruby
169
+ end
170
+
171
+ end
172
+
173
+ anonymous_impl = tree[3]
174
+
175
+ str_lvar_initialization = @locals_struct + " *plocals;
176
+ plocals = (void*)param;"
177
+
178
+ str_arg_initialization = ""
179
+
180
+ str_impl = ""
181
+
182
+ with_extra_inference(extra_inference) do
183
+ # if impl_tree is a block, implement the last node with a return
184
+ if anonymous_impl
185
+ if anonymous_impl[0] == :block
186
+ str_impl = anonymous_impl[1..-2].map{ |subtree|
187
+ to_c(subtree)
188
+ }.join(";")
189
+
190
+ if anonymous_impl[-1][0] != :return
191
+ str_impl = str_impl + ";last_expression = (#{to_c(anonymous_impl[-1])});"
192
+ else
193
+ str_impl = str_impl + ";#{to_c(anonymous_impl[-1])};"
194
+ end
195
+ else
196
+ if anonymous_impl[0] != :return
197
+ str_impl = str_impl + ";last_expression = (#{to_c(anonymous_impl)});"
198
+ else
199
+ str_impl = str_impl + ";#{to_c(anonymous_impl)};"
200
+ end
201
+ end
202
+ else
203
+ str_impl = "last_expression = Qnil;"
204
+ end
205
+
206
+ end
207
+
208
+ if convention == :ruby or convention == :cruby
209
+
210
+ if call_args_tree.size > 1
211
+
212
+ str_called_code_args = call_args_tree[1..-1].map{ |subtree| to_c subtree }.join(",")
213
+ str_recv = to_c recv_tree
214
+
215
+ str_recv = "plocals->self" unless recv_tree
216
+
217
+ caller_code = proc { |name| "
218
+ static VALUE #{name}(VALUE param) {
219
+ // call to #{call_tree[2]}
220
+
221
+ #{str_lvar_initialization}
222
+ return rb_funcall(#{str_recv}, #{call_tree[2].to_i}, #{call_args_tree.size-1}, #{str_called_code_args});
223
+ }
224
+ "
225
+ }
226
+
227
+ else
228
+ str_recv = to_c recv_tree
229
+ str_recv = "plocals->self" unless recv_tree
230
+
231
+ caller_code = proc { |name| "
232
+ static VALUE #{name}(VALUE param) {
233
+ // call to #{call_tree[2]}
234
+ #{str_lvar_initialization}
235
+ return rb_funcall(#{str_recv}, #{call_tree[2].to_i}, 0);
236
+ }
237
+ "
238
+ }
239
+ end
240
+
241
+ if not args_tree
242
+ str_arg_initialization = ""
243
+ elsif args_tree.first == :lasgn
244
+ str_arg_initialization = "plocals->#{args_tree[1]} = arg;"
245
+ elsif args_tree.first == :masgn
246
+ arguments = args_tree[1][1..-1].map(&:last)
247
+
248
+ (0..arguments.size-1).each do |i|
249
+ str_arg_initialization << "plocals->#{arguments[i]} = rb_ary_entry(arg,#{i});\n"
250
+ end
251
+ end
252
+
253
+ str_arg_initialization
254
+
255
+ block_code = proc { |name| "
256
+ static VALUE #{name}(VALUE arg, VALUE param) {
257
+ // block for call to #{call_tree[2]}
258
+ VALUE last_expression = Qnil;
259
+
260
+ #{str_lvar_initialization};
261
+ #{str_arg_initialization}
262
+ #{str_impl}
263
+
264
+ return last_expression;
265
+ }
266
+ "
267
+ }
268
+
269
+ "rb_iterate(#{anonymous_function(caller_code)}, (VALUE)#{locals_pointer}, #{anonymous_function(block_code)}, (VALUE)#{locals_pointer})"
270
+ elsif convention == :fastruby
271
+
272
+ str_arg_initialization = ""
273
+
274
+ if not args_tree
275
+ str_arg_initialization = ""
276
+ elsif args_tree.first == :lasgn
277
+ str_arg_initialization = "plocals->#{args_tree[1]} = argv[0];"
278
+ elsif args_tree.first == :masgn
279
+ arguments = args_tree[1][1..-1].map(&:last)
280
+
281
+ (0..arguments.size-1).each do |i|
282
+ str_arg_initialization << "plocals->#{arguments[i]} = #{i} < argc ? argv[#{i}] : Qnil;\n"
283
+ end
284
+ end
285
+
286
+ block_code = proc { |name| "
287
+ static VALUE #{name}(int argc, VALUE* argv, VALUE param) {
288
+ // block for call to #{call_tree[2]}
289
+ VALUE last_expression = Qnil;
290
+
291
+ #{str_lvar_initialization};
292
+ #{str_arg_initialization}
293
+ #{str_impl}
294
+
295
+ return last_expression;
296
+ }
297
+ "
298
+ }
299
+
300
+
301
+ str_recv = "plocals->self"
302
+
303
+ if recv_tree
304
+ str_recv = to_c recv_tree
305
+ end
306
+
307
+ if call_args_tree.size > 1
308
+ value_cast = ( ["VALUE"]*(call_tree[3].size) ).join(",")
309
+ value_cast = value_cast + ", VALUE" if convention == :fastruby
310
+
311
+ str_called_code_args = call_tree[3][1..-1].map{|subtree| to_c subtree}.join(",")
312
+
313
+ caller_code = proc { |name| "
314
+ static VALUE #{name}(VALUE param) {
315
+ #{@block_struct} block;
316
+
317
+ block.block_function_address = (void*)#{anonymous_function(block_code)};
318
+ block.block_function_param = (void*)param;
319
+
320
+ // call to #{call_tree[2]}
321
+
322
+ #{str_lvar_initialization}
323
+
324
+ return ((VALUE(*)(#{value_cast}))0x#{address.to_s(16)})(#{str_recv}, (VALUE)&block, #{str_called_code_args});
325
+ }
326
+ "
327
+ }
328
+
329
+ else
330
+ caller_code = proc { |name| "
331
+ static VALUE #{name}(VALUE param) {
332
+ #{@block_struct} block;
333
+
334
+ block.block_function_address = (void*)#{anonymous_function(block_code)};
335
+ block.block_function_param = (void*)param;
336
+
337
+ // call to #{call_tree[2]}
338
+ #{str_lvar_initialization}
339
+
340
+ return ((VALUE(*)(VALUE,VALUE))0x#{address.to_s(16)})(#{str_recv}, (VALUE)&block);
341
+ }
342
+ "
343
+ }
344
+ end
345
+
346
+ "#{anonymous_function(caller_code)}((VALUE)#{locals_pointer})"
347
+ end
348
+ end
349
+
350
+ def to_c_yield(tree)
351
+
352
+ block_code = proc { |name| "
353
+ static VALUE #{name}(VALUE locals_param, VALUE* block_args) {
354
+
355
+ #{@locals_struct} *plocals;
356
+ plocals = (void*)locals_param;
357
+
358
+ if (plocals->block_function_address == 0) {
359
+ rb_raise(rb_eLocalJumpError, \"no block given\");
360
+ } else {
361
+ return ((VALUE(*)(int,VALUE*,VALUE))plocals->block_function_address)(#{tree.size-1}, block_args, plocals->block_function_param);
362
+ }
363
+ }
364
+ "
365
+ }
366
+
367
+ new_yield_signature = tree[1..-1].map{|subtree| infer_type subtree}
368
+ # merge the new_yield_signature with the new
369
+ if @yield_signature
370
+ if new_yield_signature.size == @yield_signature.size
371
+ (0..new_yield_signature.size-1).each do |i|
372
+ if @yield_signature[i] != new_yield_signature[i]
373
+ @yield_signature[i] = nil
374
+ end
375
+ end
376
+ else
377
+ @yield_signature = new_yield_signature.map{|x| nil}
378
+ end
379
+ else
380
+ @yield_signature = new_yield_signature
381
+ end
382
+
383
+ if tree.size > 1
384
+ anonymous_function(block_code)+"((VALUE)#{locals_pointer}, (VALUE[]){#{tree[1..-1].map{|subtree| to_c subtree}.join(",")}})"
385
+ else
386
+ anonymous_function(block_code)+"((VALUE)#{locals_pointer}, (VALUE[]){})"
387
+ end
388
+ end
389
+
390
+ def to_c_block(tree)
391
+
392
+ str = ""
393
+ str = tree[1..-2].map{ |subtree|
394
+ to_c(subtree)
395
+ }.join(";")
396
+
397
+ if tree[-1][0] != :return
398
+ str = str + ";last_expression = #{to_c(tree[-1])};"
399
+ else
400
+ str = str + ";#{to_c(tree[-1])};"
401
+ end
402
+
403
+ caller_code = proc { |name| "
404
+ static VALUE #{name}(VALUE param) {
405
+ #{@locals_struct} *plocals = (void*)param;
406
+ VALUE last_expression;
407
+
408
+ #{str}
409
+
410
+ return last_expression;
411
+ }
412
+ "
413
+ }
414
+
415
+ anonymous_function(caller_code) + "((VALUE)#{locals_pointer})"
416
+ end
417
+
418
+ def to_c_return(tree)
419
+ "return #{to_c(tree[1])};\n"
420
+ end
421
+
422
+ def to_c_lit(tree)
423
+ "(VALUE)#{tree[1].internal_value}"
424
+ end
425
+
426
+ def to_c_nil(tree)
427
+ "Qnil"
428
+ end
429
+
430
+ def to_c_str(tree)
431
+ "(VALUE)#{tree[1].internal_value}"
432
+ end
433
+
434
+ def to_c_hash(tree)
435
+
436
+ hash_aset_code = ""
437
+ (0..(tree.size-3)/2).each do |i|
438
+ strkey = to_c tree[1 + i * 2]
439
+ strvalue = to_c tree[2 + i * 2]
440
+ hash_aset_code << "rb_hash_aset(hash, #{strkey}, #{strvalue});"
441
+ end
442
+
443
+ wrapper_func = proc { |name| "
444
+ static VALUE #{name}(VALUE value_params) {
445
+ #{@locals_struct} *plocals = (void*)value_params;
446
+ VALUE hash = rb_hash_new();
447
+ #{hash_aset_code}
448
+ return hash;
449
+ }
450
+ " }
451
+
452
+ anonymous_function(wrapper_func) + "((VALUE)#{locals_pointer})"
453
+ end
454
+
455
+ def to_c_array(tree)
456
+ if tree.size > 1
457
+ strargs = tree[1..-1].map{|subtree| to_c subtree}.join(",")
458
+ "rb_ary_new3(#{tree.size-1}, #{strargs})"
459
+ else
460
+ "rb_ary_new3(0)"
461
+ end
462
+ end
463
+
464
+ def to_c_defn(tree)
465
+ method_name = tree[1]
466
+ args_tree = tree[2]
467
+
468
+ impl_tree = tree[3][1]
469
+
470
+ @locals_struct = "struct {
471
+ #{@locals.map{|l| "VALUE #{l};\n"}.join}
472
+ #{args_tree[1..-1].map{|arg| "VALUE #{arg};\n"}.join};
473
+ void* block_function_address;
474
+ VALUE block_function_param;
475
+ }"
476
+
477
+ @block_struct = "struct {
478
+ void* block_function_address;
479
+ void* block_function_param;
480
+ }"
481
+
482
+ str_impl = ""
483
+ # if impl_tree is a block, implement the last node with a return
484
+ if impl_tree[0] == :block
485
+ str_impl = to_c impl_tree
486
+ else
487
+ if impl_tree[0] != :return
488
+ str_impl = str_impl + ";last_expression = #{to_c(impl_tree)};"
489
+ else
490
+ str_impl = str_impl + ";#{to_c(impl_tree)};"
491
+ end
492
+ end
493
+
494
+ strargs = if args_tree.size > 1
495
+ "VALUE block, #{args_tree[1..-1].map{|arg| "VALUE #{arg}" }.join(",") }"
496
+ else
497
+ "VALUE block"
498
+ end
499
+
500
+ "VALUE #{@alt_method_name || method_name}(#{strargs}) {
501
+ #{@locals_struct} locals;
502
+ #{@locals_struct} *plocals = (void*)&locals;
503
+ #{@block_struct} *pblock;
504
+ VALUE last_expression;
505
+
506
+ #{args_tree[1..-1].map { |arg|
507
+ "locals.#{arg} = #{arg};\n"
508
+ }.join("") }
509
+
510
+ locals.self = self;
511
+
512
+ pblock = (void*)block;
513
+ if (pblock) {
514
+ locals.block_function_address = pblock->block_function_address;
515
+ locals.block_function_param = (VALUE)pblock->block_function_param;
516
+ } else {
517
+ locals.block_function_address = 0;
518
+ locals.block_function_param = Qnil;
519
+ }
520
+
521
+ return #{str_impl};
522
+ }"
523
+ end
524
+
525
+ def locals_accessor
526
+ "plocals->"
527
+ end
528
+
529
+ def locals_pointer
530
+ "plocals"
531
+ end
532
+
533
+ def to_c_gvar(tree)
534
+ "rb_gvar_get((struct global_entry*)0x#{global_entry(tree[1]).to_s(16)})"
535
+ end
536
+
537
+ def to_c_gasgn(tree)
538
+ "_rb_gvar_set((void*)0x#{global_entry(tree[1]).to_s(16)}, #{to_c tree[2]})"
539
+ end
540
+
541
+ def to_c_ivar(tree)
542
+ "rb_ivar_get(#{locals_accessor}self,#{tree[1].to_i})"
543
+ end
544
+
545
+ def to_c_iasgn(tree)
546
+ "_rb_ivar_set(#{locals_accessor}self,#{tree[1].to_i},#{to_c tree[2]})"
547
+ end
548
+
549
+ def to_c_lasgn(tree)
550
+ if options[:validate_lvar_types]
551
+ klass = @infer_lvar_map[tree[1]]
552
+ if klass
553
+
554
+ verify_type_function = proc { |name| "
555
+ static VALUE #{name}(VALUE arg) {
556
+ if (CLASS_OF(arg)!=#{klass.internal_value}) rb_raise(#{TypeMismatchAssignmentException.internal_value}, \"Illegal assignment at runtime (type mismatch)\");
557
+ return arg;
558
+ }
559
+ "
560
+ }
561
+
562
+
563
+ "_lvar_assing(&#{locals_accessor}#{tree[1]}, #{anonymous_function(verify_type_function)}(#{to_c tree[2]}))"
564
+ else
565
+ "_lvar_assing(&#{locals_accessor}#{tree[1]},#{to_c tree[2]})"
566
+ end
567
+ else
568
+ "_lvar_assing(&#{locals_accessor}#{tree[1]},#{to_c tree[2]})"
569
+ end
570
+ end
571
+
572
+ def to_c_lvar(tree)
573
+ locals_accessor + tree[1].to_s
574
+ end
575
+
576
+ def to_c_self(tree)
577
+ locals_accessor + "self"
578
+ end
579
+
580
+ def to_c_false(tree)
581
+ "Qfalse"
582
+ end
583
+
584
+ def to_c_true(tree)
585
+ "Qtrue"
586
+ end
587
+
588
+ def to_c_and(tree)
589
+ "(RTEST(#{to_c tree[1]}) && RTEST(#{to_c tree[2]})) ? Qtrue : Qfalse"
590
+ end
591
+
592
+ def to_c_or(tree)
593
+ "(RTEST(#{to_c tree[1]}) || RTEST(#{to_c tree[2]})) ? Qtrue : Qfalse"
594
+ end
595
+
596
+ def to_c_not(tree)
597
+ "RTEST(#{to_c tree[1]}) ? Qfalse : Qtrue"
598
+ end
599
+
600
+ def to_c_if(tree)
601
+ condition_tree = tree[1]
602
+ impl_tree = tree[2]
603
+ else_tree = tree[3]
604
+ code = "if (RTEST(#{to_c condition_tree})) {
605
+ last_expression = #{to_c impl_tree};
606
+ }
607
+ "
608
+
609
+ if (else_tree)
610
+ code = code + " else {
611
+ last_expression = #{to_c else_tree};
612
+ }
613
+ "
614
+ end
615
+
616
+ caller_code = proc { |name| "
617
+ static VALUE #{name}(VALUE param) {
618
+ #{@locals_struct} *plocals = (void*)param;
619
+ VALUE last_expression = Qnil;
620
+
621
+ #{code};
622
+
623
+ return last_expression;
624
+ }
625
+ "
626
+ }
627
+
628
+ anonymous_function(caller_code) + "((VALUE)#{locals_pointer})"
629
+ end
630
+
631
+ def to_c_call(tree)
632
+ recv = tree[1]
633
+ mname = tree[2]
634
+ args = tree[3]
635
+
636
+ directive_code = directive(tree)
637
+ if directive_code
638
+ return directive_code
639
+ end
640
+
641
+ strargs = args[1..-1].map{|arg| to_c arg}.join(",")
642
+
643
+ argnum = args.size - 1
644
+
645
+ recv = recv || s(:self)
646
+
647
+ recvtype = infer_type(recv)
648
+
649
+ if recvtype
650
+
651
+ address = nil
652
+ mobject = nil
653
+
654
+ inference_complete = true
655
+ signature = [recvtype]
656
+
657
+ args[1..-1].each do |arg|
658
+ argtype = infer_type(arg)
659
+ if argtype
660
+ signature << argtype
661
+ else
662
+ inference_complete = false
663
+ end
664
+ end
665
+
666
+ convention = nil
667
+
668
+ if recvtype.respond_to? :method_tree and inference_complete
669
+
670
+ if recvtype.method_tree[tree[2]]
671
+ mobject = recvtype.build(signature, tree[2])
672
+ convention = :fastruby
673
+ else
674
+ mobject = recvtype.instance_method(tree[2])
675
+ convention = :cruby
676
+ end
677
+ else
678
+ mobject = recvtype.instance_method(tree[2])
679
+ convention = :cruby
680
+ end
681
+
682
+ address = getaddress(mobject)
683
+ len = getlen(mobject)
684
+
685
+ extraargs = ""
686
+ extraargs = ", Qfalse" if convention == :fastruby
687
+
688
+ if address then
689
+ if argnum == 0
690
+ value_cast = "VALUE"
691
+ value_cast = value_cast + ", VALUE" if convention == :fastruby
692
+
693
+ if convention == :fastruby
694
+ "((VALUE(*)(#{value_cast}))0x#{address.to_s(16)})(#{to_c recv}, Qfalse)"
695
+ else
696
+
697
+ str_incall_args = nil
698
+ if len == -1
699
+ str_incall_args = "0, (VALUE[]){}, recv"
700
+ value_cast = "int,VALUE*,VALUE"
701
+ elsif len == -2
702
+ str_incall_args = "recv, rb_ary_new4(#{})"
703
+ value_cast = "VALUE,VALUE"
704
+ else
705
+ str_incall_args = "recv"
706
+ end
707
+
708
+ wrapper_func = proc { |name| "
709
+ static VALUE #{name}(VALUE recv) {
710
+ // call to #{recvtype}##{mname}
711
+ if (rb_block_given_p()) {
712
+ // no passing block, recall
713
+ return rb_funcall(recv, #{tree[2].to_i}, 0);
714
+ } else {
715
+ return ((VALUE(*)(#{value_cast}))0x#{address.to_s(16)})(#{str_incall_args});
716
+ }
717
+ }
718
+ " }
719
+
720
+ anonymous_function(wrapper_func) + "(#{to_c(recv)})"
721
+
722
+ end
723
+ else
724
+ value_cast = ( ["VALUE"]*(args.size) ).join(",")
725
+ value_cast = value_cast + ", VALUE" if convention == :fastruby
726
+
727
+ wrapper_func = nil
728
+ if convention == :fastruby
729
+ "((VALUE(*)(#{value_cast}))0x#{address.to_s(16)})(#{to_c recv}, Qfalse, #{strargs})"
730
+ else
731
+
732
+ str_incall_args = nil
733
+ if len == -1
734
+ str_incall_args = "#{argnum}, (VALUE[]){#{ (1..argnum).map{|x| "_arg"+x.to_s }.join(",")}}, recv"
735
+ value_cast = "int,VALUE*,VALUE"
736
+ elsif len == -2
737
+ str_incall_args = "recv, rb_ary_new4(#{ (1..argnum).map{|x| "_arg"+x.to_s }.join(",")})"
738
+ value_cast = "VALUE,VALUE"
739
+ else
740
+ str_incall_args = "recv, #{ (1..argnum).map{|x| "_arg"+x.to_s }.join(",")}"
741
+ end
742
+
743
+ wrapper_func = proc { |name| "
744
+ static VALUE #{name}(VALUE recv, #{ (1..argnum).map{|x| "VALUE _arg"+x.to_s }.join(",")} ) {
745
+ // call to #{recvtype}##{mname}
746
+ if (rb_block_given_p()) {
747
+ // no passing block, recall
748
+ return rb_funcall(recv, #{tree[2].to_i}, #{argnum}, #{ (1..argnum).map{|x| "_arg"+x.to_s }.join(",")});
749
+ } else {
750
+ return ((VALUE(*)(#{value_cast}))0x#{address.to_s(16)})(#{str_incall_args});
751
+ }
752
+ }
753
+ " }
754
+
755
+ anonymous_function(wrapper_func) + "(#{to_c(recv)}, #{strargs})"
756
+ end
757
+ end
758
+ else
759
+
760
+ if argnum == 0
761
+ "rb_funcall(#{to_c recv}, #{tree[2].to_i}, 0)"
762
+ else
763
+ "rb_funcall(#{to_c recv}, #{tree[2].to_i}, #{argnum}, #{strargs} )"
764
+ end
765
+ end
766
+
767
+ else
768
+ if argnum == 0
769
+ "rb_funcall(#{to_c recv}, #{tree[2].to_i}, 0)"
770
+ else
771
+ "rb_funcall(#{to_c recv}, #{tree[2].to_i}, #{argnum}, #{strargs} )"
772
+ end
773
+ end
774
+ end
775
+
776
+ def to_c_while(tree)
777
+ caller_code = proc { |name| "
778
+ static VALUE #{name}(VALUE param) {
779
+ #{@locals_struct} *plocals = (void*)param;
780
+ VALUE last_expression;
781
+
782
+ while (#{to_c tree[1]}) {
783
+ #{to_c tree[2]};
784
+ }
785
+
786
+ return Qnil;
787
+ }
788
+ "
789
+ }
790
+
791
+ anonymous_function(caller_code) + "((VALUE)#{locals_pointer})"
792
+ end
793
+
794
+ def infer_type(recv)
795
+ if recv[0] == :call
796
+ if recv[2] == :infer
797
+ eval(recv[3].last.last.to_s)
798
+ end
799
+ elsif recv[0] == :lvar
800
+ @infer_lvar_map[recv[1]]
801
+ elsif recv[0] == :self
802
+ @infer_self
803
+ elsif recv[0] == :str or recv[0] == :lit
804
+ recv[1].class
805
+ else
806
+ nil
807
+ end
808
+ end
809
+
810
+ def with_extra_inference(extra_inference)
811
+ previous_infer_lvar_map = @infer_lvar_map
812
+ begin
813
+ @infer_lvar_map = @infer_lvar_map.merge(extra_inference)
814
+ yield
815
+ ensure
816
+ @infer_lvar_map = previous_infer_lvar_map
817
+ end
818
+ end
819
+
820
+ def directive(tree)
821
+ recv = tree[1]
822
+ mname = tree[2]
823
+ args = tree[3]
824
+
825
+ if mname == :infer
826
+ return to_c(recv)
827
+ elsif mname == :lvar_type
828
+ lvar_name = args[1][1] || args[1][2]
829
+ lvar_type = eval(args[2][1].to_s)
830
+
831
+ @infer_lvar_map[lvar_name] = lvar_type
832
+ return ""
833
+ elsif mname == :block_given?
834
+ return "#{locals_accessor}block_function_address == 0 ? Qfalse : Qtrue"
835
+ elsif mname == :inline_c
836
+ code = args[1][1]
837
+
838
+ caller_code = proc { |name| "
839
+ static VALUE #{name}(VALUE param) {
840
+ #{@locals_struct} *plocals = (void*)param;
841
+ #{code};
842
+ return Qnil;
843
+ }
844
+ "
845
+ }
846
+
847
+ return anonymous_function(caller_code)+"((VALUE)plocals)"
848
+ else
849
+ nil
850
+ end
851
+ end
852
+
853
+ inline :C do |builder|
854
+ builder.include "<node.h>"
855
+ builder.c "VALUE getaddress(VALUE method) {
856
+ struct METHOD {
857
+ VALUE klass, rklass;
858
+ VALUE recv;
859
+ ID id, oid;
860
+ int safe_level;
861
+ NODE *body;
862
+ };
863
+
864
+ struct METHOD *data;
865
+ Data_Get_Struct(method, struct METHOD, data);
866
+
867
+ if (nd_type(data->body) == NODE_CFUNC) {
868
+ return INT2FIX(data->body->nd_cfnc);
869
+ }
870
+
871
+ return Qnil;
872
+ }"
873
+
874
+ builder.c "VALUE getlen(VALUE method) {
875
+ struct METHOD {
876
+ VALUE klass, rklass;
877
+ VALUE recv;
878
+ ID id, oid;
879
+ int safe_level;
880
+ NODE *body;
881
+ };
882
+
883
+ struct METHOD *data;
884
+ Data_Get_Struct(method, struct METHOD, data);
885
+
886
+ if (nd_type(data->body) == NODE_CFUNC) {
887
+ return INT2FIX(data->body->nd_argc);
888
+ }
889
+
890
+ return Qnil;
891
+ }"
892
+
893
+ builder.c "VALUE global_entry(VALUE global_id) {
894
+ ID id = SYM2ID(global_id);
895
+ struct global_entry* entry;
896
+
897
+ entry = rb_global_entry(id);
898
+ return INT2FIX(entry);
899
+ }
900
+ "
901
+ end
902
+ end
903
+ end