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.
Files changed (52) hide show
  1. data/.gitignore +5 -0
  2. data/History.txt +199 -0
  3. data/README.txt +34 -0
  4. data/examples/bench.rb +14 -0
  5. data/examples/complex.rb +63 -0
  6. data/examples/complex2.rb +48 -0
  7. data/examples/cshadow-example.rb +55 -0
  8. data/examples/cshadow-point.rb +58 -0
  9. data/examples/ctest.rb +34 -0
  10. data/examples/ctest2.rb +32 -0
  11. data/examples/ctest3.rb +179 -0
  12. data/examples/ctest4.rb +18 -0
  13. data/examples/ctest5.rb +27 -0
  14. data/examples/example-ruby-talk-30April2004.rb +65 -0
  15. data/examples/fixed-array.rb +221 -0
  16. data/examples/inherit-example.rb +26 -0
  17. data/examples/inherit-example.txt +80 -0
  18. data/examples/instance-eval.rb +66 -0
  19. data/examples/ivset.rb +55 -0
  20. data/examples/marshal-test.rb +19 -0
  21. data/examples/matrix.rb +91 -0
  22. data/examples/modular-def.rb +87 -0
  23. data/examples/objattr.rb +46 -0
  24. data/examples/opaque-struct-test.rb +36 -0
  25. data/examples/sample.rb +184 -0
  26. data/examples/struct.rb +103 -0
  27. data/examples/test.rb +24 -0
  28. data/examples/yaml.rb +56 -0
  29. data/install.rb +1015 -0
  30. data/lib/cgen/attribute.rb +414 -0
  31. data/lib/cgen/cgen.rb +2041 -0
  32. data/lib/cgen/cshadow.rb +1037 -0
  33. data/lib/cgen/inherit.rb +46 -0
  34. data/rakefile +42 -0
  35. data/tasks/ann.rake +80 -0
  36. data/tasks/bones.rake +20 -0
  37. data/tasks/gem.rake +201 -0
  38. data/tasks/git.rake +40 -0
  39. data/tasks/notes.rake +27 -0
  40. data/tasks/post_load.rake +34 -0
  41. data/tasks/rdoc.rake +51 -0
  42. data/tasks/rubyforge.rake +55 -0
  43. data/tasks/setup.rb +292 -0
  44. data/tasks/spec.rake +54 -0
  45. data/tasks/svn.rake +47 -0
  46. data/tasks/test.rake +40 -0
  47. data/tasks/zentest.rake +36 -0
  48. data/test/test-attribute.rb +430 -0
  49. data/test/test-cgen.rb +127 -0
  50. data/test/test-cshadow.rb +289 -0
  51. data/test/test.rb +17 -0
  52. 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
+
@@ -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
@@ -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]
@@ -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