cgen 0.16.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +5 -0
- data/History.txt +199 -0
- data/README.txt +34 -0
- data/examples/bench.rb +14 -0
- data/examples/complex.rb +63 -0
- data/examples/complex2.rb +48 -0
- data/examples/cshadow-example.rb +55 -0
- data/examples/cshadow-point.rb +58 -0
- data/examples/ctest.rb +34 -0
- data/examples/ctest2.rb +32 -0
- data/examples/ctest3.rb +179 -0
- data/examples/ctest4.rb +18 -0
- data/examples/ctest5.rb +27 -0
- data/examples/example-ruby-talk-30April2004.rb +65 -0
- data/examples/fixed-array.rb +221 -0
- data/examples/inherit-example.rb +26 -0
- data/examples/inherit-example.txt +80 -0
- data/examples/instance-eval.rb +66 -0
- data/examples/ivset.rb +55 -0
- data/examples/marshal-test.rb +19 -0
- data/examples/matrix.rb +91 -0
- data/examples/modular-def.rb +87 -0
- data/examples/objattr.rb +46 -0
- data/examples/opaque-struct-test.rb +36 -0
- data/examples/sample.rb +184 -0
- data/examples/struct.rb +103 -0
- data/examples/test.rb +24 -0
- data/examples/yaml.rb +56 -0
- data/install.rb +1015 -0
- data/lib/cgen/attribute.rb +414 -0
- data/lib/cgen/cgen.rb +2041 -0
- data/lib/cgen/cshadow.rb +1037 -0
- data/lib/cgen/inherit.rb +46 -0
- data/rakefile +42 -0
- data/tasks/ann.rake +80 -0
- data/tasks/bones.rake +20 -0
- data/tasks/gem.rake +201 -0
- data/tasks/git.rake +40 -0
- data/tasks/notes.rake +27 -0
- data/tasks/post_load.rake +34 -0
- data/tasks/rdoc.rake +51 -0
- data/tasks/rubyforge.rake +55 -0
- data/tasks/setup.rb +292 -0
- data/tasks/spec.rake +54 -0
- data/tasks/svn.rake +47 -0
- data/tasks/test.rake +40 -0
- data/tasks/zentest.rake +36 -0
- data/test/test-attribute.rb +430 -0
- data/test/test-cgen.rb +127 -0
- data/test/test-cshadow.rb +289 -0
- data/test/test.rb +17 -0
- metadata +123 -0
@@ -0,0 +1,26 @@
|
|
1
|
+
require 'cgen/cshadow'
|
2
|
+
|
3
|
+
class Parent
|
4
|
+
include CShadow
|
5
|
+
|
6
|
+
shadow_attr_accessor :ruby_str => String
|
7
|
+
shadow_attr_accessor :c_int => "int c_int"
|
8
|
+
end
|
9
|
+
|
10
|
+
class Child < Parent
|
11
|
+
shadow_attr_accessor :obj => Object # VALUE type
|
12
|
+
end
|
13
|
+
|
14
|
+
Parent.commit
|
15
|
+
# we're done adding attrs and methods, so make.
|
16
|
+
|
17
|
+
x = Child.new
|
18
|
+
x.ruby_str = "foo"
|
19
|
+
x.obj = [1,2,3]
|
20
|
+
x.c_int = 3
|
21
|
+
|
22
|
+
p x
|
23
|
+
# ==> #<Child:0xb7ba96f4 ruby_str="foo", c_int=3, obj=[1, 2, 3]>
|
24
|
+
|
25
|
+
CShadow.allow_yaml
|
26
|
+
y x
|
@@ -0,0 +1,80 @@
|
|
1
|
+
|
2
|
+
The generated code looks, in part, as follows. Note that CGenerator/CShadow produces quite readable C code. In the Parent.h header file we have:
|
3
|
+
|
4
|
+
typedef struct Parent_Shadow {
|
5
|
+
VALUE self;
|
6
|
+
VALUE ruby_str; // String;
|
7
|
+
int c_int;
|
8
|
+
} Parent_Shadow;
|
9
|
+
|
10
|
+
typedef struct Child_Shadow {
|
11
|
+
|
12
|
+
/* Parent_Shadow members */
|
13
|
+
VALUE self;
|
14
|
+
VALUE ruby_str; // String;
|
15
|
+
int c_int;
|
16
|
+
|
17
|
+
VALUE obj; // Object;
|
18
|
+
} Child_Shadow;
|
19
|
+
|
20
|
+
Again, members are duplicated, which would be awful if you wanted to manually maintain the code, but who wants to do that :-)
|
21
|
+
|
22
|
+
In the Parent.c file, we have:
|
23
|
+
|
24
|
+
void mark_Parent_Shadow(Parent_Shadow *shadow)
|
25
|
+
{
|
26
|
+
rb_gc_mark((void *)shadow->self);
|
27
|
+
rb_gc_mark((void *)shadow->ruby_str);
|
28
|
+
}
|
29
|
+
|
30
|
+
void mark_Child_Shadow(Child_Shadow *shadow)
|
31
|
+
{
|
32
|
+
rb_gc_mark((void *)shadow->self);
|
33
|
+
rb_gc_mark((void *)shadow->ruby_str);
|
34
|
+
rb_gc_mark((void *)shadow->obj);
|
35
|
+
}
|
36
|
+
|
37
|
+
and similarly for the free functions, persistence functions, etc. The #new method generated by CShadow is where rb_obj_call_init() gets called. Note that initialization of shadow attributes is customizable.
|
38
|
+
|
39
|
+
VALUE new_module_Child_singleton_method(int argc, VALUE *argv, VALUE self)
|
40
|
+
{
|
41
|
+
VALUE object;
|
42
|
+
Child_Shadow *shadow;
|
43
|
+
|
44
|
+
object = Data_Make_Struct(self,
|
45
|
+
Child_Shadow,
|
46
|
+
mark_Child_Shadow,
|
47
|
+
free_Child_Shadow,
|
48
|
+
shadow);
|
49
|
+
shadow->self = object;
|
50
|
+
|
51
|
+
shadow->ruby_str = Qnil;
|
52
|
+
shadow->obj = Qnil;
|
53
|
+
|
54
|
+
rb_obj_call_init(object, argc, argv);
|
55
|
+
|
56
|
+
return object;
|
57
|
+
}
|
58
|
+
|
59
|
+
The #ruby_str= method only needs to be defined for Parent, because, of course, Ruby itself handles inheritance of methods. Note the type checking, which is done for the ruby_str member but not for the obj member.
|
60
|
+
|
61
|
+
VALUE ruby__str_equals_module_Parent_method(int argc, VALUE *argv, VALUE self)
|
62
|
+
{
|
63
|
+
VALUE arg;
|
64
|
+
Parent_Shadow *shadow;
|
65
|
+
|
66
|
+
rb_scan_args(argc, argv, "1", &arg);
|
67
|
+
|
68
|
+
if (!NIL_P(arg) &&
|
69
|
+
rb_obj_is_kind_of(arg, module_String) != Qtrue)
|
70
|
+
rb_raise(module_TypeError,
|
71
|
+
"argument arg declared String but passed %s.",
|
72
|
+
STR2CSTR(rb_funcall(
|
73
|
+
rb_funcall(arg, ID_type, 0),
|
74
|
+
ID_to__s, 0)));
|
75
|
+
|
76
|
+
Data_Get_Struct(self, Parent_Shadow, shadow);
|
77
|
+
shadow->ruby_str = arg;
|
78
|
+
return arg;
|
79
|
+
}
|
80
|
+
|
@@ -0,0 +1,66 @@
|
|
1
|
+
require 'cgen/cshadow'
|
2
|
+
|
3
|
+
class A
|
4
|
+
include CShadow
|
5
|
+
|
6
|
+
define_c_method :instance_eval_proc do
|
7
|
+
c_array_args {
|
8
|
+
required :pr
|
9
|
+
typecheck :pr => Proc
|
10
|
+
}
|
11
|
+
body %{
|
12
|
+
printf("instance_eval_proc\\n");
|
13
|
+
}
|
14
|
+
returns "rb_iterate(my_instance_eval, shadow->self, call_block, pr)"
|
15
|
+
end
|
16
|
+
|
17
|
+
fn = shadow_library_source_file.define :my_instance_eval
|
18
|
+
fn.instance_eval do
|
19
|
+
arguments "VALUE obj"
|
20
|
+
return_type "VALUE"
|
21
|
+
body %{
|
22
|
+
printf("my_instance_eval\\n");
|
23
|
+
}
|
24
|
+
returns "rb_obj_instance_eval(0, 0, obj)"
|
25
|
+
end
|
26
|
+
|
27
|
+
fn = shadow_library_source_file.define :call_block
|
28
|
+
fn.instance_eval do
|
29
|
+
arguments "VALUE arg1", "VALUE block"
|
30
|
+
return_type "VALUE"
|
31
|
+
body %{
|
32
|
+
printf("call_block\\n");
|
33
|
+
}
|
34
|
+
returns "rb_funcall(block, #{declare_symbol :call}, 0)"
|
35
|
+
end
|
36
|
+
|
37
|
+
end
|
38
|
+
|
39
|
+
Dir.chdir "tmp" do
|
40
|
+
A.commit
|
41
|
+
end
|
42
|
+
|
43
|
+
a = A.new
|
44
|
+
pr = proc { "self is %p" % self }
|
45
|
+
|
46
|
+
p a.instance_eval(&pr)
|
47
|
+
puts '---'
|
48
|
+
p a.instance_eval_proc(pr)
|
49
|
+
|
50
|
+
__END__
|
51
|
+
|
52
|
+
|
53
|
+
|
54
|
+
static VALUE my_instance_eval(VALUE obj)
|
55
|
+
{
|
56
|
+
return rb_obj_instance_eval(0, 0, obj);
|
57
|
+
}
|
58
|
+
|
59
|
+
static VALUE call_block(VALUE arg1, VALUE block)
|
60
|
+
{
|
61
|
+
return rb_funcall(block, ID_call, 0);
|
62
|
+
}
|
63
|
+
|
64
|
+
//...
|
65
|
+
rb_iterate(my_instance_eval, obj, call_block, pr);
|
66
|
+
|
data/examples/ivset.rb
ADDED
@@ -0,0 +1,55 @@
|
|
1
|
+
class Foo
|
2
|
+
def initialize
|
3
|
+
@a = 1
|
4
|
+
@b = 2
|
5
|
+
end
|
6
|
+
|
7
|
+
def inc_iv
|
8
|
+
[:@a, :@b].each { |iv|
|
9
|
+
eval "#{iv} += 1"
|
10
|
+
}
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
require 'cgen/cshadow'
|
15
|
+
|
16
|
+
class Bar
|
17
|
+
include CShadow
|
18
|
+
|
19
|
+
def initialize
|
20
|
+
@a = 1
|
21
|
+
@b = 2
|
22
|
+
end
|
23
|
+
|
24
|
+
def inc_iv
|
25
|
+
[:@a, :@b].each { |iv|
|
26
|
+
iv = iv
|
27
|
+
set_iv(iv, get_iv(iv) + 1)
|
28
|
+
}
|
29
|
+
end
|
30
|
+
|
31
|
+
define_method :set_iv do
|
32
|
+
arguments :attr, :value
|
33
|
+
body %{
|
34
|
+
rb_ivar_set(shadow->self, rb_to_id(attr), value);
|
35
|
+
}
|
36
|
+
returns %{shadow->self}
|
37
|
+
end
|
38
|
+
private :set_iv
|
39
|
+
|
40
|
+
define_method :get_iv do
|
41
|
+
arguments :attr
|
42
|
+
returns %{rb_ivar_get(shadow->self, rb_to_id(attr))}
|
43
|
+
end
|
44
|
+
private :get_iv
|
45
|
+
|
46
|
+
def inspect
|
47
|
+
"<Bar: a = #{@a}, b = #{@b}>"
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
Bar.commit # write to .c files, make, and require
|
52
|
+
|
53
|
+
bar = Bar.new
|
54
|
+
bar.inc_iv
|
55
|
+
p bar
|
@@ -0,0 +1,19 @@
|
|
1
|
+
require 'cgen/cshadow'
|
2
|
+
|
3
|
+
class MarshalTest
|
4
|
+
include CShadow
|
5
|
+
|
6
|
+
shadow_attr_accessor :x => Object
|
7
|
+
end
|
8
|
+
|
9
|
+
Dir.mkdir "tmp" rescue SystemCallError
|
10
|
+
Dir.chdir "tmp"
|
11
|
+
|
12
|
+
MarshalTest.commit
|
13
|
+
|
14
|
+
mt = MarshalTest.new
|
15
|
+
|
16
|
+
mt.x = "foo"
|
17
|
+
p mt.x
|
18
|
+
|
19
|
+
p Marshal.dump mt
|
data/examples/matrix.rb
ADDED
@@ -0,0 +1,91 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'cgen/cshadow'
|
4
|
+
|
5
|
+
class MyMatrix
|
6
|
+
include CShadow
|
7
|
+
|
8
|
+
shadow_attr_reader :rows => "int rows", :cols => "int cols"
|
9
|
+
shadow_attr :matrix => "double *matrix"
|
10
|
+
|
11
|
+
define_c_method(:initialize) {
|
12
|
+
c_array_args {
|
13
|
+
required :rows, :cols
|
14
|
+
typecheck :rows => Fixnum, :cols => Fixnum
|
15
|
+
}
|
16
|
+
declare :size => "int size"
|
17
|
+
body %{
|
18
|
+
shadow->rows = FIX2INT(rows);
|
19
|
+
shadow->cols = FIX2INT(cols);
|
20
|
+
|
21
|
+
if (shadow->rows <= 0)
|
22
|
+
rb_raise(#{declare_class ArgumentError}, "Rows must be positive.");
|
23
|
+
if (shadow->cols <= 0)
|
24
|
+
rb_raise(#{declare_class ArgumentError}, "Cols must be positive.");
|
25
|
+
|
26
|
+
size = shadow->rows * shadow->cols;
|
27
|
+
shadow->matrix = ALLOC_N(double, size);
|
28
|
+
memset(shadow->matrix, 0, size * sizeof(double));
|
29
|
+
}
|
30
|
+
}
|
31
|
+
|
32
|
+
define_c_method(:[]) {
|
33
|
+
arguments :i, :j
|
34
|
+
declare :ii => "int ii", :jj => "int jj"
|
35
|
+
body %{
|
36
|
+
ii = NUM2INT(i);
|
37
|
+
jj = NUM2INT(j);
|
38
|
+
|
39
|
+
if (ii < 0 || ii >= shadow->rows)
|
40
|
+
rb_raise(#{declare_class IndexError},
|
41
|
+
"Row index %d out of range [0, %d]",
|
42
|
+
ii, shadow->rows - 1);
|
43
|
+
|
44
|
+
if (jj < 0 || jj >= shadow->cols)
|
45
|
+
rb_raise(#{declare_class IndexError},
|
46
|
+
"Column index %d out of range [0, %d]",
|
47
|
+
jj, shadow->cols - 1);
|
48
|
+
}
|
49
|
+
returns "rb_float_new(shadow->matrix[ii * shadow->cols + jj])"
|
50
|
+
}
|
51
|
+
|
52
|
+
define_c_method(:[]=) {
|
53
|
+
arguments :i, :j, :x
|
54
|
+
declare :ii => "int ii", :jj => "int jj", :xx => "double xx"
|
55
|
+
body %{
|
56
|
+
ii = NUM2INT(i);
|
57
|
+
jj = NUM2INT(j);
|
58
|
+
xx = NUM2DBL(x);
|
59
|
+
|
60
|
+
if (ii < 0 || ii >= shadow->rows)
|
61
|
+
rb_raise(#{declare_class IndexError},
|
62
|
+
"Row index %d out of range 0..%d",
|
63
|
+
ii, shadow->rows - 1);
|
64
|
+
|
65
|
+
if (jj < 0 || jj >= shadow->cols)
|
66
|
+
rb_raise(#{declare_class IndexError},
|
67
|
+
"Column index %d out of range 0..%d",
|
68
|
+
jj, shadow->cols - 1);
|
69
|
+
|
70
|
+
shadow->matrix[ii * shadow->cols + jj] = xx;
|
71
|
+
}
|
72
|
+
returns "x"
|
73
|
+
}
|
74
|
+
end
|
75
|
+
|
76
|
+
require 'ftools'
|
77
|
+
dir = File.join("tmp", RUBY_VERSION)
|
78
|
+
File.mkpath dir
|
79
|
+
Dir.chdir dir
|
80
|
+
|
81
|
+
MyMatrix.commit
|
82
|
+
|
83
|
+
m = MyMatrix.new 5, 2
|
84
|
+
m[3,1] = 8.2e+13
|
85
|
+
puts m[3,1]
|
86
|
+
puts m[3,0]
|
87
|
+
begin
|
88
|
+
puts m[3,2]
|
89
|
+
rescue IndexError
|
90
|
+
puts "Caught an IndexError: m[3,2] is out of range."
|
91
|
+
end
|
@@ -0,0 +1,87 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
# This example shows how to factor out definitions into a module. The
|
4
|
+
# only additional library code needed is the following:
|
5
|
+
|
6
|
+
module ModuleMethodSaver
|
7
|
+
def method_missing(meth, *args, &block)
|
8
|
+
@saved ||= []
|
9
|
+
@saved << [meth, args, block]
|
10
|
+
end
|
11
|
+
|
12
|
+
def included(m)
|
13
|
+
if @saved
|
14
|
+
@saved.each do |meth, args, block|
|
15
|
+
m.send(meth, *args, &block)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
|
22
|
+
require 'cgen/cshadow'
|
23
|
+
|
24
|
+
module ComplexStuff
|
25
|
+
extend ModuleMethodSaver
|
26
|
+
|
27
|
+
shadow_attr_accessor :re => "double re", :im => "double im"
|
28
|
+
|
29
|
+
def initialize re, im
|
30
|
+
self.re = re
|
31
|
+
self.im = im
|
32
|
+
end
|
33
|
+
|
34
|
+
define_c_method(:abs) {
|
35
|
+
include "<math.h>"
|
36
|
+
returns "rb_float_new(sqrt(pow(shadow->re, 2) + pow(shadow->im, 2)))"
|
37
|
+
}
|
38
|
+
|
39
|
+
define_c_method(:mul!) {
|
40
|
+
arguments :other
|
41
|
+
declare :other_shadow => "MyComplex_Shadow *other_shadow"
|
42
|
+
declare :new_re => "double new_re", :new_im => "double new_im"
|
43
|
+
body %{
|
44
|
+
switch (TYPE(other)) {
|
45
|
+
case T_FIXNUM: shadow->re *= FIX2INT(other);
|
46
|
+
shadow->im *= FIX2INT(other); break;
|
47
|
+
case T_FLOAT: shadow->re *= NUM2DBL(other);
|
48
|
+
shadow->im *= NUM2DBL(other); break;
|
49
|
+
default:
|
50
|
+
if (rb_obj_is_kind_of(other, #{declare_class MyComplex}) ==
|
51
|
+
Qtrue) {
|
52
|
+
Data_Get_Struct(other, MyComplex_Shadow, other_shadow);
|
53
|
+
new_re = shadow->re * other_shadow->re -
|
54
|
+
shadow->im * other_shadow->im;
|
55
|
+
new_im = shadow->re * other_shadow->im +
|
56
|
+
shadow->im * other_shadow->re;
|
57
|
+
shadow->re = new_re;
|
58
|
+
shadow->im = new_im;
|
59
|
+
}
|
60
|
+
else
|
61
|
+
rb_raise(#{declare_class ArgumentError},
|
62
|
+
"Argument to mul! is not numeric.");
|
63
|
+
}
|
64
|
+
}
|
65
|
+
returns "self"
|
66
|
+
}
|
67
|
+
end
|
68
|
+
|
69
|
+
class MyComplex < Numeric
|
70
|
+
include CShadow
|
71
|
+
include ComplexStuff
|
72
|
+
end
|
73
|
+
|
74
|
+
require 'ftools'
|
75
|
+
dir = File.join("tmp", RUBY_VERSION)
|
76
|
+
File.mkpath dir
|
77
|
+
Dir.chdir dir
|
78
|
+
|
79
|
+
MyComplex.commit
|
80
|
+
|
81
|
+
z = MyComplex.new 5, 1.3
|
82
|
+
puts z.abs
|
83
|
+
z.mul! 10
|
84
|
+
p [z.re, z.im]
|
85
|
+
w = MyComplex.new 7.9, -1.2
|
86
|
+
z.mul! w
|
87
|
+
p [z.re, z.im]
|
data/examples/objattr.rb
ADDED
@@ -0,0 +1,46 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'cgen/cshadow'
|
4
|
+
|
5
|
+
SAME_LIBRARY = true
|
6
|
+
|
7
|
+
class A
|
8
|
+
include CShadow
|
9
|
+
shadow_attr_accessor :obj => Object, :sym => Symbol
|
10
|
+
end
|
11
|
+
|
12
|
+
class B
|
13
|
+
include CShadow
|
14
|
+
|
15
|
+
if SAME_LIBRARY
|
16
|
+
shadow_library A # in the same lib as A
|
17
|
+
shadow_library_file 'B' # but in a different file
|
18
|
+
else
|
19
|
+
# different lib, but connected with a '#include'
|
20
|
+
shadow_library_include_file.include '../A/A.h'
|
21
|
+
end
|
22
|
+
|
23
|
+
shadow_attr_accessor :a => [A]
|
24
|
+
|
25
|
+
def initialize
|
26
|
+
self.a = A.new
|
27
|
+
self.a.sym = :something
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
require 'ftools'
|
32
|
+
dir = File.join("tmp", RUBY_VERSION)
|
33
|
+
File.mkpath dir
|
34
|
+
Dir.chdir dir
|
35
|
+
|
36
|
+
A.commit
|
37
|
+
unless SAME_LIBRARY
|
38
|
+
B.commit
|
39
|
+
end
|
40
|
+
|
41
|
+
p B.new.a.sym
|
42
|
+
|
43
|
+
A.shadow_library.make 'distclean'
|
44
|
+
unless SAME_LIBRARY
|
45
|
+
B.shadow_library.make 'distclean'
|
46
|
+
end
|