ruby2cext 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,12 @@
1
+
2
+ class String
3
+ C_STRLIT_MAP = (0..255).map { |b| b.chr.inspect[1..-2] }.freeze
4
+ def to_c_strlit
5
+ # this might be a bit slow, but #inspect escapes ruby specific stuff,
6
+ # that generates warnings in C (e.g. '#$' => "\#$")
7
+ map = C_STRLIT_MAP
8
+ res = ""
9
+ each_byte { |b| res << map[b] }
10
+ "\"#{res}\""
11
+ end
12
+ end
@@ -0,0 +1,84 @@
1
+
2
+ require "ruby2cext/str_to_c_strlit"
3
+ require "ruby2cext/error"
4
+
5
+ module Ruby2CExtension
6
+
7
+ module Tools
8
+ # keeps track of used symbols and provides global variables that hold the corresponding ID
9
+ class SymbolManager
10
+ def initialize
11
+ @syms = {}
12
+ end
13
+
14
+ # returns the var name for sym
15
+ def get(sym)
16
+ idx = (@syms[sym] ||= @syms.size)
17
+ "sym[#{idx}] /* #{sym.to_s.gsub(/[^\w<=>+\-*\/!?@$|&~.]/, "_").gsub("*/", "__")} */"
18
+ end
19
+
20
+ def to_c_code(init_fun_name = "init_syms")
21
+ res = []
22
+ res << "static ID sym[#{@syms.size}];" unless @syms.empty?
23
+ res << "static void #{init_fun_name}() {"
24
+ @syms.sort_by { |sym, idx| idx }.each { |sym, idx|
25
+ res << "sym[#{idx}] = rb_intern(#{sym.to_s.to_c_strlit});"
26
+ }
27
+ res << "}"
28
+ res.join("\n")
29
+ end
30
+ end
31
+
32
+ class GlobalManager
33
+ def initialize
34
+ @cnt = 0
35
+ @src = []
36
+ @reusable = {}
37
+ end
38
+
39
+ # returns the var name for sym
40
+ def get(str, allow_reuse, register_gc)
41
+ if allow_reuse && (name = @reusable[str])
42
+ return name
43
+ end
44
+ name = "global[#{@cnt}]"
45
+ @cnt += 1
46
+ @src << "#{name} = #{str};"
47
+ @src << "rb_global_variable(&(#{name}));" if register_gc
48
+ if allow_reuse
49
+ @reusable[str] = name
50
+ end
51
+ name
52
+ end
53
+
54
+ def to_c_code(init_fun_name = "init_globals")
55
+ res = []
56
+ res << "static VALUE global[#{@cnt}];" if @cnt > 0
57
+ res << "static void #{init_fun_name}() {"
58
+ res.concat(@src)
59
+ res << "}"
60
+ res.join("\n")
61
+ end
62
+ end
63
+
64
+ class UniqueNames
65
+ def initialize
66
+ @prefix_cnt = Hash.new(0)
67
+ end
68
+ def get(prefix)
69
+ "#{prefix}_#{@prefix_cnt[prefix]+=1}"
70
+ end
71
+ end
72
+
73
+ module EnsureNodeTypeMixin
74
+ def ensure_node_type(node, expected_types)
75
+ expected_types = [expected_types] unless Array === expected_types
76
+ unless node && expected_types.index(node.first)
77
+ raise Ruby2CExtError, "unexpected node type: expected #{expected_types.join(" or ")}, found #{node.inspect}"
78
+ end
79
+ end
80
+ end
81
+
82
+ end
83
+
84
+ end
@@ -0,0 +1,22 @@
1
+
2
+ module Ruby2CExtension
3
+
4
+ VERSION = "0.2.0"
5
+
6
+ FULL_VERSION_STRING = "Ruby2CExtension #{VERSION} (ruby #{RUBY_VERSION} (#{RUBY_RELEASE_DATE}) [#{RUBY_PLATFORM}])"
7
+
8
+ SUPPORTED_RUBY_VERSIONS = {
9
+ "1.8.4" => ["2005-12-24"],
10
+ "1.8.5" => ["2006-08-25", "2006-12-04", "2006-12-25", "2007-03-13", "2007-06-07"],
11
+ "1.8.6" => ["2007-03-13", "2007-06-07"],
12
+ }
13
+
14
+ if (dates = SUPPORTED_RUBY_VERSIONS[RUBY_VERSION])
15
+ unless dates.include? RUBY_RELEASE_DATE
16
+ warn "Ruby2CExtension warning: ruby #{RUBY_VERSION} (#{RUBY_RELEASE_DATE}) is an unknown release of Ruby #{RUBY_VERSION}, there might be problems"
17
+ end
18
+ else
19
+ warn "Ruby2CExtension warning: ruby #{RUBY_VERSION} (#{RUBY_RELEASE_DATE}) is not supported by Ruby2CExtension #{VERSION}"
20
+ end
21
+
22
+ end
@@ -0,0 +1,116 @@
1
+ # some benchmarks
2
+
3
+ require "benchmark"
4
+
5
+ def fib(n)
6
+ if n < 2
7
+ n
8
+ else
9
+ fib(n - 1) + fib(n - 2)
10
+ end
11
+ end
12
+
13
+ def mkmatrix(rows, cols)
14
+ count = 1
15
+ mx = Array.new(rows)
16
+ (0 .. (rows - 1)).each do |bi|
17
+ row = Array.new(cols, 0)
18
+ (0 .. (cols - 1)).each do |j|
19
+ row[j] = count
20
+ count += 1
21
+ end
22
+ mx[bi] = row
23
+ end
24
+ mx
25
+ end
26
+
27
+ def mmult(rows, cols, m1, m2)
28
+ m3 = Array.new(rows)
29
+ (0 .. (rows - 1)).each do |bi|
30
+ row = Array.new(cols, 0)
31
+ (0 .. (cols - 1)).each do |j|
32
+ val = 0
33
+ (0 .. (cols - 1)).each do |k|
34
+ val += m1.at(bi).at(k) * m2.at(k).at(j)
35
+ end
36
+ row[j] = val
37
+ end
38
+ m3[bi] = row
39
+ end
40
+ m3
41
+ end
42
+
43
+ def sqrt(x)
44
+ x = x.to_f
45
+ average = lambda { |a, b| (a+b)/2 }
46
+ impr = lambda { |g| average[g, x/g] }
47
+ good_en = lambda { |g| (g*g - x).abs < 0.001 }
48
+ try = lambda { |g| good_en[g] ? g : try[impr[g]] }
49
+ try[1.0]
50
+ end
51
+
52
+
53
+ Benchmark.bm(10) { |bmx|
54
+ bmx.report("times") { 3000000.times{|e| e + e } }
55
+ bmx.report("fib") { fib 30 }
56
+ bmx.report("array") {
57
+ n = 2000
58
+ x = Array.new(n)
59
+ y = Array.new(n, 0)
60
+ n.times{|bi| x[bi] = bi + 1 }
61
+ (0 .. 999).each do |e|
62
+ (n-1).step(0,-1) do |bi|
63
+ y[bi] += x.at(bi)
64
+ end
65
+ end
66
+ }
67
+ bmx.report("matrix") {
68
+ n = 40
69
+ size = 30
70
+ m1 = mkmatrix(size, size)
71
+ m2 = mkmatrix(size, size)
72
+ mm = Array.new
73
+ n.times do
74
+ mm = mmult(size, size, m1, m2)
75
+ end
76
+ }
77
+ bmx.report("while") {
78
+ i = 3000000
79
+ while i > 0
80
+ break if i == 5
81
+ i -= 1
82
+ next if i % 100 == 0
83
+ redo if (i-=1) % 100 == 1
84
+ end
85
+ }
86
+ bmx.report("sqrt") {
87
+ i = 40000
88
+ while (i-=1) > 0
89
+ sqrt 2
90
+ end
91
+ }
92
+ bmx.report("3 [] alloc") {
93
+ i = 40000
94
+ while (i-=1) > 0
95
+ [[], []]
96
+ end
97
+ }
98
+ bmx.report("const cache") {
99
+ 50000.times {
100
+ a = Array
101
+ a = Object::Array
102
+ a = ::Array
103
+ }
104
+ }
105
+ bmx.report("method calls") {
106
+ max = 2000
107
+ z = x = 0
108
+ while (x+=1) <= max
109
+ y = 0
110
+ while (y+=1) <= max
111
+ z = (x+y-z) % 32000
112
+ end
113
+ end
114
+ }
115
+ bmx.report("") { }
116
+ }
@@ -0,0 +1,37 @@
1
+
2
+ require "ruby2cext/eval2c"
3
+
4
+ $e2c = Ruby2CExtension::Eval2C.new
5
+
6
+ $e2c.toplevel_eval("p __FILE__")
7
+
8
+ 3.times { $e2c.toplevel_eval("p 'hello'") }
9
+
10
+ class A
11
+ $e2c.module_eval(self, %{
12
+ def initialize(x)
13
+ @x = x
14
+ end
15
+ def foo(y)
16
+ @x + y
17
+ end
18
+ })
19
+ end
20
+
21
+ p A.new(5).foo(6)
22
+
23
+ p $e2c.instance_eval("4321", "reverse")
24
+
25
+ p $e2c.compile_to_proc("|a,b| a+b").call(2, 3)
26
+
27
+ class B
28
+ def m1; m2; end
29
+ protected
30
+ def m2; m3; end
31
+ private
32
+ def m3; :m3; end
33
+
34
+ $e2c.compile_methods(self, :m1, :m2, :m3)
35
+ end
36
+
37
+ p B.new.m1
data/testfiles/test.rb ADDED
@@ -0,0 +1,615 @@
1
+ # this file contains code that uses many different node types and everything in
2
+ # here works with Ruby2CExtension
3
+
4
+ BEGIN {puts "begin1"}
5
+ BEGIN {puts "begin2"}
6
+
7
+ p self
8
+ puts
9
+ p 1,1.2,(p 23;-1),:sym,1...1,1..1
10
+ p [1,2],"oij\0iuj","",[1,[2,[3,4]]]
11
+ begin
12
+ p 1,*[2,3]
13
+ end while false
14
+ p({:a=>[1], :b=>[2]}.values_at(:a, :b))
15
+ p [1,2,3].index(2)
16
+ a=b="hello"
17
+ puts a, b + " you"
18
+ p(@a=7)
19
+ p($a=6)
20
+ xx=$a=$b=@c=@d=xxx=5
21
+ p [$a,$b,@c,@d,xx,xxx]
22
+ for a in 0..1
23
+ a = (a == 0 ? :a : :b)
24
+ unless a == :b
25
+ puts "a"
26
+ else
27
+ puts "not a"
28
+ end
29
+ end
30
+ p(if puts
31
+ else
32
+ end)
33
+ def m(a)
34
+ p a
35
+ end
36
+ m 1 + 2
37
+ m [1,2,3].first
38
+ m 2.between?(1, 5)
39
+ p method(:m)
40
+
41
+ p [1111111111111222222333345342323, /ab/i, /cd/m, /xx/n]
42
+
43
+ __send__(:p, true.__id__, false.__send__(:inspect), "abc".__send__(:[], 1), 2.equal?(3), nil.nil?, 1.nil?)
44
+
45
+ def m1(a,b=[],*c)
46
+ p a,b,c
47
+ end
48
+ m1(1,2,3,4,5)
49
+ m1 3
50
+ def m2(*)
51
+ p "STAR"
52
+ end
53
+ m2 1,2,3
54
+
55
+ a="hello"
56
+ def a.a
57
+ p self
58
+ end
59
+ a.a
60
+
61
+ public
62
+
63
+ def fib(n)
64
+ if n < 2
65
+ n
66
+ else
67
+ fib(n - 1) + fib(n - 2)
68
+ end
69
+ end
70
+
71
+ p fib(10)
72
+
73
+ case
74
+ when 1 == 1
75
+ p "woo"
76
+ when *[false, true]
77
+ p (1..3).inspect
78
+ else
79
+ p "uhh"
80
+ end
81
+
82
+ for a in 0...7
83
+ case a
84
+ when true, false
85
+ p "bool"
86
+ when nil
87
+ p "nil"
88
+ when 0
89
+ p "null"
90
+ when 3, *[1,2]
91
+ p "1 2 3"
92
+ when 4, 5
93
+ p "4 5"
94
+ else
95
+ p 6
96
+ end
97
+ end
98
+
99
+ case true
100
+ when false
101
+ p "false"
102
+ when true
103
+ p "true"
104
+ end
105
+
106
+ case 2.0
107
+ when 1, nil
108
+ p 1
109
+ when 2
110
+ p 2
111
+ when 3
112
+ p 3
113
+ end
114
+
115
+ case "a"
116
+ when /a/
117
+ p "good"
118
+ else
119
+ p "bad"
120
+ end
121
+
122
+ a = 1,3
123
+ p a
124
+ p [__FILE__, __LINE__]
125
+
126
+ a = [1,nil,3]
127
+
128
+ a[0]+=2
129
+ a[1]||=4
130
+ a[2]&&=5
131
+
132
+ p a
133
+
134
+ a = Object.new
135
+ def a.method_missing(*args) p args; end
136
+
137
+ a[1,*[2,3]]
138
+ a[1,*[2,3]]=4
139
+ a[1,*[2,3]]||=4
140
+
141
+ class AliasTest
142
+ def foo
143
+ p "afoo"
144
+ end
145
+
146
+ alias afoo foo
147
+ undef foo
148
+ end
149
+
150
+ $at = AliasTest.new
151
+ alias $aat $at
152
+ $aat.afoo
153
+
154
+ a = Struct.new(:aa).new
155
+
156
+ a.aa=3
157
+ a.aa+=2
158
+ p a.aa
159
+ a.aa||=raise
160
+ p a.aa
161
+ a.aa&&=8
162
+ p a.aa
163
+
164
+ Object::AAA=5
165
+ BBB=6
166
+ p [AAA,BBB,::AAA,::BBB,Object::AAA,Object::Object::BBB]
167
+
168
+ p [:"a#{1+2}b#{"123".inspect}", "str#{:sym}xx", /a#{2}b#{3}c/, /a#{2}b#{3}c/o, `echo #{2+3}`, `echo 23`.chomp, /null\000null/]
169
+
170
+ def ct
171
+ def argv
172
+ ::ARGV
173
+ end
174
+ end
175
+
176
+ ct
177
+ p argv
178
+ ct
179
+
180
+ class AA < String
181
+ def rev
182
+ reverse
183
+ end
184
+ end
185
+ p AA.new("abc").rev
186
+
187
+ class A
188
+ @@var = :A
189
+ C = :CA
190
+ end
191
+
192
+ class B
193
+ @@var = :B
194
+ C = :CB
195
+
196
+ a = A.new
197
+ class ::A
198
+ p [@@var, C] # => [:A, :CA]
199
+ def foo
200
+ [@@var, C]
201
+ end
202
+ end
203
+ def a.bar
204
+ [@@var, C]
205
+ end
206
+ class << a
207
+ p [@@var, C] # => [:B, :CB]
208
+ def baz
209
+ [@@var, C]
210
+ end
211
+ end
212
+ p a.foo # => [:A, :CA]
213
+ p a.bar # => [:B, :CB]
214
+ p a.baz # => [:B, :CB]
215
+ p [@@var, ::A::C, C, class << a;C;end] # => [:B, :CA, :CB, :CB]
216
+ class << a
217
+ @@var = :ASing # this changes B's @@var
218
+ C = :CASing # this creates a new C for a's sing. class
219
+ end
220
+ p [@@var, ::A::C, C, class << a;C;end] # => [:ASing, :CA, :CB, :CASing]
221
+ p a.foo # => [:A, :CA]
222
+ p a.bar # => [:ASing, :CB]
223
+ p a.baz # => [:ASing, :CASing]
224
+ end
225
+
226
+ class F; FF = 3;end
227
+ FF = 4
228
+ class G < F; p FF; end # should be 3, not 4
229
+
230
+ def pt
231
+ p Proc.new[]
232
+ end
233
+ pt { 'Proc.new ok!' }
234
+
235
+ a,@b,$c,(D,*e),*f = [1,2,3,[4,5,6,7],8,9,10]
236
+ p [a,@b,$c,D,e,f]
237
+ a,((@b,$c),(DDD,*e)),*f = [1,[[2,3],[4,5,6,7]],8,9,10]
238
+ p [a,@b,$c,DDD,e,f]
239
+ a,b = 2
240
+ p [a,b]
241
+ *b=1,2
242
+ p b
243
+
244
+ a=[1,2,3]
245
+ a[5],a[7]=4, 6
246
+ p a
247
+ class << a
248
+ attr_accessor :c, :d
249
+ end
250
+ a.c,a.d=7,8
251
+ p [a.c,a.d]
252
+
253
+ p [1,2,3].map { |a| a+1 }
254
+
255
+ def yield_t(a)
256
+ yield a, a+1
257
+ end
258
+
259
+ p(yield_t(23) { |a, b| a+b })
260
+
261
+ p "abc".instance_eval { reverse }
262
+ p proc { |xx| xx }[24]
263
+
264
+ END { p "END" }
265
+ def end_t
266
+ at_exit { p "at_exit" }
267
+ end
268
+ end_t
269
+ end_t
270
+
271
+ class SupA
272
+ def test(*arg)
273
+ p "SupA#test", arg
274
+ yield 23
275
+ end
276
+ end
277
+ class SupB < SupA
278
+ def test(*a)
279
+ p a
280
+ super
281
+ super()
282
+ super(a)
283
+ super { |b| p b+1 }
284
+ super() { |b| p b+2 }
285
+ super(a) { |b| p b+3 }
286
+ end
287
+ end
288
+ SupB.new.test { |a| p a }
289
+ SupB.new.test(23) { |a| p a }
290
+
291
+ for i in 1..9
292
+ p i
293
+ end
294
+
295
+ def sqrt(x)
296
+ x = x.to_f
297
+ average = lambda { |a, b| (a+b)/2 }
298
+ impr = lambda { |g| average[g, x/g] }
299
+ good_en = lambda { |g| (g*g - x).abs < 0.001 }
300
+ try = lambda { |g| good_en[g] ? g : try[impr[g]] }
301
+ try[1.0]
302
+ end
303
+
304
+ p sqrt(2)
305
+
306
+
307
+ def my_while(cond)
308
+ if cond
309
+ yield
310
+ retry
311
+ end
312
+ end
313
+
314
+ i=3
315
+ my_while((i-=1)>0) { p i }
316
+
317
+ p (11..20).map { |i| (i%4==0)..(i%3==0) ? i : nil }
318
+ p (11..20).map { |i| (i%4==0)...(i%3==0) ? i : nil }
319
+
320
+ "a" =~ /(a)/
321
+ p [
322
+ defined? ""=~//,
323
+ defined? yield,
324
+ defined? self,
325
+ defined? nil,
326
+ defined? true,
327
+ defined? false,
328
+ defined? a=5,
329
+ defined? a,
330
+ defined? $a,
331
+ defined? $udef,
332
+ defined? @c,
333
+ defined? @udef,
334
+ defined? A,
335
+ defined? Udef,
336
+ defined? @@udef,
337
+ defined? ::A,
338
+ defined? ::Udef,
339
+ defined? $1,
340
+ defined? $9,
341
+ defined? $',
342
+ ]
343
+
344
+ class AAAAAA
345
+ xx=5
346
+ proc { |yy|
347
+ begin
348
+ @@a||=xx
349
+ @@a||=yy
350
+ @a||=5
351
+ @a||=6
352
+ $f||=5
353
+ $f||=6
354
+ a||=5
355
+ a||=6
356
+ p [@@a, @a, $f, a]
357
+ @@a&&=5
358
+ @@a&&=6
359
+ @a&&=5
360
+ @a&&=6
361
+ $f&&=5
362
+ $f&&=6
363
+ a&&=5
364
+ a&&=6
365
+ p [@@a, @a, $f, a]
366
+ ensure
367
+ p "in ensure"
368
+ end
369
+ }[6]
370
+ end
371
+
372
+ class AEx < RuntimeError;end
373
+ class BEx < RuntimeError;end
374
+ class CEx < RuntimeError;end
375
+
376
+ ex = AEx
377
+ p(begin
378
+ p "in body"
379
+ ex && raise(ex.new)
380
+ p "not raised"
381
+ rescue TypeError, AEx
382
+ p "in AEx"
383
+ ex = BEx
384
+ retry
385
+ rescue *[TypeError, BEx] => b
386
+ p "in BEx #{b}"
387
+ ex = CEx
388
+ retry
389
+ rescue
390
+ p "in rescue"
391
+ ex = nil
392
+ retry
393
+ else
394
+ "res"
395
+ ensure
396
+ p "in ensure"
397
+ end)
398
+
399
+ ex = AEx
400
+ begin
401
+ begin
402
+ p "in body"
403
+ raise ex
404
+ rescue AEx
405
+ p "in AEx"
406
+ ex = BEx
407
+ retry
408
+ end
409
+ rescue BEx
410
+ p "in BEx"
411
+ else
412
+ p "in else: BUG!"
413
+ end
414
+
415
+ begin
416
+ begin
417
+ raise
418
+ rescue 1
419
+ 2
420
+ end
421
+ rescue => e
422
+ p e
423
+ end
424
+
425
+ def cf1
426
+ begin
427
+ return 5
428
+ ensure
429
+ puts "ensure"
430
+ end
431
+ 6
432
+ end
433
+ p cf1
434
+
435
+ def cf2
436
+ begin
437
+ while true
438
+ begin
439
+ return 5555
440
+ ensure
441
+ puts "ensure"
442
+ end
443
+ end
444
+ ensure
445
+ puts "ensure"
446
+ end
447
+ 6
448
+ end
449
+ p cf2
450
+
451
+ def cf22
452
+ begin
453
+ while true
454
+ begin
455
+ break 5555
456
+ ensure
457
+ puts "ensure"
458
+ end
459
+ end
460
+ ensure
461
+ puts "ensure"
462
+ end + 6
463
+ end
464
+ p cf22
465
+
466
+ def cf3
467
+ 1.instance_eval {
468
+ begin
469
+ break
470
+ ensure
471
+ puts "ensure"
472
+ end
473
+ }
474
+ end
475
+ p cf3
476
+
477
+ def cf4
478
+ i = 0
479
+ 5.times {
480
+ begin
481
+ break if i == 3
482
+ i+=1
483
+ puts "xxx"
484
+ begin
485
+ redo
486
+ ensure
487
+ puts "ensure"
488
+ while true
489
+ break
490
+ end
491
+ end
492
+ ensure
493
+ puts "ensure"
494
+ end
495
+ }
496
+ i
497
+ end
498
+ p cf4
499
+
500
+ def cf5
501
+ i = 0
502
+ 5.instance_eval {
503
+ begin
504
+ next
505
+ ensure
506
+ puts "ensure"
507
+ end
508
+ }
509
+ end
510
+ p cf5
511
+
512
+ def cf6
513
+ i = 0
514
+ 5.instance_eval {
515
+ begin
516
+ next 24
517
+ rescue
518
+ puts "bug"
519
+ end
520
+ }
521
+ end
522
+ p cf6
523
+
524
+ def cf61
525
+ i = 0
526
+ 5.instance_eval {
527
+ begin
528
+ raise
529
+ rescue
530
+ next 24
531
+ end
532
+ }
533
+ end
534
+ p cf61
535
+
536
+ def cf7
537
+ loop {
538
+ begin
539
+ break
540
+ rescue
541
+ puts "bug"
542
+ ensure
543
+ puts "ensure"
544
+ end
545
+ }
546
+ 23
547
+ end
548
+ p cf7
549
+
550
+ def cf71
551
+ loop {
552
+ begin
553
+ raise
554
+ rescue
555
+ break
556
+ ensure
557
+ puts "ensure"
558
+ end
559
+ }
560
+ 23
561
+ end
562
+ p cf71
563
+
564
+ def cf8
565
+ while true
566
+ begin
567
+ return 1234
568
+ rescue
569
+ puts "bug"
570
+ ensure
571
+ puts "ensure"
572
+ end
573
+ end
574
+ 23
575
+ end
576
+ p cf8
577
+
578
+ def cf81
579
+ while true
580
+ begin
581
+ raise
582
+ rescue
583
+ return 1234
584
+ ensure
585
+ puts "ensure"
586
+ end
587
+ end
588
+ 23
589
+ end
590
+ p cf81
591
+
592
+ def cf9
593
+ i = 0
594
+ 5.times {
595
+ begin
596
+ break if i == 3
597
+ i+=1
598
+ puts "xxx"
599
+ begin
600
+ raise
601
+ rescue
602
+ while true
603
+ puts "yyy"
604
+ break
605
+ end
606
+ redo
607
+ end
608
+ ensure
609
+ puts "ensure"
610
+ end
611
+ }
612
+ i
613
+ end
614
+ p cf9
615
+