cgen 0.16.0
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/.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
|