rubber-generate 0.0.5

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/README.md ADDED
@@ -0,0 +1,58 @@
1
+ Rubber C Binder v0.0.5
2
+ Template language for generating Ruby bindings for C libraries
3
+ by Geoff Youngs <g@intersect-uk.co.uk>
4
+
5
+ Introduction
6
+ ~~~~~~~~~~~~
7
+ A simple ruby-style bindings generator for Ruby. It allows bindings to
8
+ be laid out in a Ruby style, documentation to be included inline and
9
+ explicit type casts within C code. It's somewhere between SWIG and pyrex.
10
+
11
+ It also allows features extconf.rb creation, including checks for headers,
12
+ pkg-config etc. The modules it creates currently depend on Ruby/GTK, but
13
+ it is planned to remove this dependency unless they genuinely require Ruby/GTK.
14
+
15
+ Other features include custom named type-maps, pre/post code inclusion within
16
+ functions and some rudimentary understanding of C code.
17
+
18
+
19
+ Dependencies
20
+ ~~~~~~~~~~~~
21
+ Ruby 1.8
22
+ Doesn't require any modules which aren't in the Ruby 1.8.0 distribution.
23
+ Ruby 1.6
24
+ Has not been tested. Requires at least the StringScanner (C version) and
25
+ StringIO modules. (See raa.ruby-lang.org for 'strscan' and 'stringio')
26
+
27
+
28
+ Example
29
+ ~~~~~~~
30
+ Sample file:
31
+ vte/vte.cr
32
+
33
+ Usage:
34
+ $ ruby rubber.rb vte.cr
35
+
36
+ Which should generate
37
+ vte.c <- Source code for extension
38
+ vte.rd <- RD documentation from vte.cr
39
+ extconf.rb <- Config script
40
+
41
+ Running extconf.rb should then allow installation of the extension as normal.
42
+
43
+
44
+ Installation
45
+ ~~~~~~~~~~~~
46
+ There is currently no installation. Rubber will automatically look for it's
47
+ libraries in the normal path or in the directory where the 'real' rubber script
48
+ resides. (So the rubber.rb can be symlinked from where you unpacked it to
49
+ a directory in your path).
50
+
51
+ When rubber matures then it will come with a proper install.rb setup.
52
+
53
+
54
+ Credits
55
+ ~~~~~~~
56
+ Rubber was created by Geoff Youngs
57
+
58
+ Contributors: Vincent Isambart
@@ -0,0 +1,54 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ if FileTest.symlink?(__FILE__)
4
+ file = File::readlink(__FILE__)
5
+ else
6
+ file = __FILE__
7
+ end
8
+
9
+ require 'rbconfig'
10
+ require 'ftools'
11
+
12
+ dir = File::dirname(file)
13
+ $:.unshift(dir)
14
+ #puts dir
15
+ require 'strscan'
16
+ #require 'rubygems'
17
+ #require_gem 'rubber'
18
+ require 'rubber/codegen'
19
+ require 'rubber/mkextconf'
20
+ require 'rubber/scanner'
21
+ require 'rubber/types'
22
+ require 'rubber/autord'
23
+
24
+
25
+ args = ARGV.select { |i| i[0] != ?- }
26
+ switches = ARGV.select { |i| i[0] == ?- }
27
+ (args.size > 0 && args || Dir.glob('*.cr')).each { |file|
28
+
29
+ file = File.expand_path(file)
30
+ File.mkpath(Config::CONFIG['sitearch'])
31
+ Dir.chdir(Config::CONFIG['sitearch']) do
32
+
33
+
34
+ scanner = Rubber::CRScanner.new(file)
35
+ scanner.scan(nil)
36
+
37
+ out = File.open(scanner.ext + ".c", 'w')
38
+ doc = File.open(scanner.ext + ".rd", 'w')
39
+
40
+ extconf = File.open('extconf.rb', 'w')
41
+ Rubber.generate_extconf(scanner, extconf)
42
+ Rubber.generate_c_source(scanner, out)
43
+ Rubber.generate_rd(scanner, doc)
44
+
45
+
46
+ doc.close
47
+ out.close
48
+ extconf.close
49
+
50
+ system('ruby','extconf.rb') if switches.include?('--configure')
51
+ system('make') if switches.include?("--build")
52
+ end
53
+ }
54
+ #out.close
@@ -0,0 +1,10 @@
1
+ module Rubber
2
+ def self.generate_rd(scanner, io)
3
+ if scanner.doc
4
+ io.write(scanner.doc + "\n\n")
5
+ end
6
+ scanner.stack.first.classes.each { |c|
7
+ c.doc_rd(io)
8
+ }
9
+ end
10
+ end
@@ -0,0 +1,131 @@
1
+ require 'rubber/struct'
2
+ module Rubber
3
+ def generate_c_source(scanner, io)
4
+ mod = scanner.stack.first # Pseudo root module for file
5
+ if scanner.options.gnu
6
+ io.puts "#define _GNU_SOURCE 1"
7
+ end
8
+ io.puts "/* Includes */"
9
+ io.puts "#include <ruby.h>"
10
+ io.puts "#include <stdlib.h>"
11
+ io.puts "#include <stdio.h>"
12
+ io.puts "#include <string.h>"
13
+ if scanner.incs
14
+ scanner.incs.each { |i| io.puts "#include #{i.inspect}"}
15
+ end
16
+ io.puts "\n/* Setup types */"
17
+ io.puts "/* Try not to clash with other definitions of bool... */"
18
+ io.puts "typedef int rubber_bool;"
19
+ io.puts "#define bool rubber_bool"
20
+ io.puts "\n/* Prototypes */"
21
+ io.puts '#include "rbglib.h"' if scanner.options.glib?
22
+
23
+ if scanner.options.glib? and scanner.options.gtk?
24
+ io.write <<-EOI
25
+ #include "rbgtk.h"
26
+
27
+ #if defined(G_PLATFORM_WIN32) && !defined(RUBY_GTK2_STATIC_COMPILATION)
28
+ # ifdef RUBY_GTK2_COMPILATION
29
+ # define RUBY_GTK2_VAR __declspec(dllexport)
30
+ # else
31
+ # define RUBY_GTK2_VAR extern __declspec(dllimport)
32
+ # endif
33
+ #else
34
+ # define RUBY_GTK2_VAR extern
35
+ #endif
36
+
37
+ RUBY_GTK2_VAR VALUE mGtk;
38
+ RUBY_GTK2_VAR VALUE mGdk;
39
+
40
+ #define RBGTK_INITIALIZE(obj,gtkobj)\
41
+ (rbgtk_initialize_gtkobject(obj, GTK_OBJECT(gtkobj)))
42
+ EOI
43
+ end
44
+
45
+
46
+ mod.classes.each { |c|
47
+ c.declare(io)
48
+ }
49
+ if scanner.raw
50
+ io.puts("\n/* Inline C code */")
51
+ io.write(scanner.raw)
52
+ end
53
+ io.puts "\n/* Code */"
54
+ mod.classes.each { |c|
55
+ c.code(io)
56
+ }
57
+ io.puts "/* Init */"
58
+ io.puts "void"
59
+ io.puts "Init_#{scanner.ext}(void)"
60
+ io.puts "{"
61
+ io.puts scanner.pre_init_code if scanner.pre_init_code
62
+ mod.classes.each { |c|
63
+ c.register(io)
64
+ }
65
+ io.puts scanner.post_init_code if scanner.post_init_code
66
+ io.puts "}"
67
+
68
+ end
69
+ module_function :generate_c_source
70
+
71
+ module RegisterChildren
72
+ attr_reader :child_names
73
+ def register_children(io)
74
+ @child_names = {}
75
+ contents.each { |f|
76
+ f.register(io, @child_names.has_key?(f.name))
77
+ if @child_names.has_key?(f.name)
78
+ puts "#{self.cname} has duplicate definitiion of #{f.name}"
79
+ else
80
+ @child_names[f.name]= f
81
+ end
82
+ }
83
+ if respond_to?(:register_aliases)
84
+ register_aliases(io)
85
+ end
86
+ end
87
+ def cname
88
+ if parent && parent.child_names && parent.child_names[name] && parent.child_names[name] != self
89
+ parent.child_names[name].cname
90
+ else
91
+ default_cname()
92
+ end
93
+ end
94
+ end
95
+
96
+
97
+ class C_RootModule
98
+ define_members({:classes => []}, {:methods => []}, {:functions => []}, {:constants => []}, {:includes => []})
99
+ attr_reader :child_names
100
+ def cname
101
+ p "RootModule cName req'd.", caller
102
+ nil
103
+ end
104
+ end
105
+
106
+ require 'rubber/codegen/module'
107
+ require 'rubber/codegen/class'
108
+ require 'rubber/codegen/param'
109
+ require 'rubber/codegen/function'
110
+
111
+ # Constants
112
+ require 'rubber/codegen/string'
113
+ require 'rubber/codegen/integer'
114
+ require 'rubber/codegen/float'
115
+
116
+ # Special
117
+ require 'rubber/codegen/struct'
118
+ require 'rubber/codegen/enum'
119
+ require 'rubber/codegen/flags'
120
+ # needs int derivative
121
+ require 'rubber/codegen/genum'
122
+ require 'rubber/codegen/gflags'
123
+ require 'rubber/codegen/gboxed'
124
+ require 'rubber/codegen/ginterface'
125
+ require 'rubber/codegen/gobject'
126
+
127
+ # Utils
128
+ require 'rubber/codegen/gcrefpool'
129
+
130
+
131
+ end # m Rubber
@@ -0,0 +1,79 @@
1
+ require 'rubber/codegen/module'
2
+
3
+ module Rubber
4
+
5
+ class C_Class < C_Module
6
+ define_members :name, :superclass, :methods, :functions, :constants, :ctype, {:classes => []}, :includes, :parent
7
+ attr_accessor :pre_func, :post_func, :doc, :pre_only, :pre_except, :post_only, :post_except
8
+ attr_reader :child_names
9
+
10
+ def fullname()
11
+ if parent and parent.respond_to?(:fullname)
12
+ "#{parent.fullname}::#{name}"
13
+ else
14
+ name
15
+ end
16
+ end
17
+ def doc_rd(io)
18
+ id = fullname()
19
+ id += " < #{superclass}" if superclass
20
+ depth = (fullname.gsub(/[^:]/,'').size >> 1)
21
+ io.puts "=#{'=' * depth} class #{id}"
22
+ io.puts @doc if @doc
23
+ contents.each { |f| f.doc_rd(io) }
24
+ end
25
+ def get_root(); is_root? ? self : parent.get_root; end
26
+ def is_root?()
27
+ not parent.respond_to?(:fullname)
28
+ end
29
+ def code(io)
30
+ contents .each { |f| f.code(io) }
31
+ end
32
+ def declare(io)
33
+ io.puts "static VALUE #{cname};";
34
+ contents .each { |f| f.declare(io) }
35
+ end
36
+ def register(io, already_defined=false)
37
+ if parent.child_names && parent.child_names[name]
38
+ io.puts " c#{name} = #{cname};"
39
+ else
40
+ if parent and parent.cname
41
+ io.puts " #{cname} = rb_define_class_under(#{parent.cname}, #{name.inspect}, #{Rubber::find_class(superclass) || 'rb_cObject'});"
42
+ else
43
+ io.puts " #{cname} = rb_define_class(#{name.inspect}, #{Rubber::find_class(superclass) || 'rb_cObject'});"
44
+ end
45
+ end
46
+ register_children(io)
47
+ end
48
+ include RegisterChildren
49
+ def default_cname
50
+ "c"+name
51
+ end
52
+ def check_wrap_ok(io, fn, where)
53
+ case where
54
+ when :pre
55
+ code = @pre_func
56
+ only = @pre_only
57
+ except = @pre_except
58
+ when :post
59
+ code = @post_func
60
+ only = @post_only
61
+ except = @post_except
62
+ end
63
+ if code && ! fn.singleton
64
+ return if only && ! only.empty? && ! only.include?(fn.name)
65
+ return if except && except.include?(fn.name)
66
+ io.puts code
67
+ end
68
+ end
69
+ def pre_func(io, func)
70
+ #io.puts @pre_func unless @pre_func.nil? or func.singleton
71
+ check_wrap_ok(io, func, :pre)
72
+ end
73
+ def post_func(io, func)
74
+ #io.puts @post_func unless @post_func.nil? or func.singleton
75
+ check_wrap_ok(io, func, :post)
76
+ end
77
+ end
78
+
79
+ end # Rubber
@@ -0,0 +1,231 @@
1
+ module Rubber
2
+
3
+ class C_Enum
4
+ define_members :name, :args, :parent
5
+ attr_reader :child_names
6
+ @@declared_base = false
7
+ @@declared_register = false
8
+ def init()
9
+ ($custom_maps[name] ||= {})["VALUE"] = "enum_#{name}_to_ruby((%%))"
10
+ ($custom_maps["VALUE"] ||= {})[name] = "enum_ruby_to_#{name}((%%))"
11
+ STDERR.puts "Auto-adding custom map for #{name}"
12
+ @splits = strip_prefixes(args)
13
+ @strip = args.first.length - @splits.first.length
14
+ end
15
+ def code(io)
16
+ end
17
+ def declare(io)
18
+ io.puts "static VALUE #{cname};"
19
+ unless @@declared_base
20
+ @@declared_base = true
21
+ io.puts "
22
+
23
+ static VALUE enumBaseClass;
24
+
25
+ typedef struct {
26
+ int value;
27
+ char *name;
28
+ char *fullname;
29
+ } EnumData;
30
+
31
+ static VALUE make_enum_value(VALUE klass, int value, char *name, char *fullname)
32
+ {
33
+ EnumData *data = NULL;
34
+
35
+ data = ALLOC(EnumData);
36
+ data->value = value;
37
+ data->name = name;
38
+ data->fullname = fullname;
39
+
40
+ return Data_Wrap_Struct(klass, NULL, free, data);
41
+ }
42
+ static int value_to_int(VALUE value, VALUE klass)
43
+ {
44
+ switch (TYPE(value))
45
+ {
46
+ case T_FIXNUM:
47
+ case T_FLOAT:
48
+ return NUM2INT(value);
49
+ break;
50
+ case T_DATA:
51
+ if (rb_obj_is_kind_of(value, enumBaseClass))
52
+ {
53
+ EnumData *data = NULL;
54
+
55
+ if ((klass != Qnil) && (!rb_obj_is_kind_of(value, klass)))
56
+ {
57
+ rb_raise(rb_eTypeError, \"Wrong type of enum %s (%s required)\", rb_obj_classname(value), rb_class2name(klass));
58
+ }
59
+
60
+ Data_Get_Struct(value, EnumData, data);
61
+ return data->value;
62
+ }
63
+ break;
64
+ }
65
+ return 0;
66
+
67
+ }
68
+
69
+ static VALUE rubber_enum_inspect(VALUE value)
70
+ {
71
+ EnumData *data = NULL;
72
+ volatile VALUE str = rb_str_new(\"#<\", 2);
73
+ char number[16] = \"\";
74
+
75
+ Data_Get_Struct(value, EnumData, data);
76
+
77
+ rb_str_cat2(str, rb_obj_classname(value));
78
+ rb_str_cat2(str, \" - \");
79
+ rb_str_cat2(str, data->name);
80
+ rb_str_cat2(str, \"(\");
81
+ sprintf(number, \"%i\", data->value);
82
+ rb_str_cat2(str, number);
83
+ rb_str_cat2(str, \")>\");
84
+
85
+ return str;
86
+ }
87
+
88
+ static VALUE rubber_enum_to_s(VALUE value)
89
+ {
90
+ EnumData *data = NULL;
91
+
92
+ Data_Get_Struct(value, EnumData, data);
93
+
94
+ return rb_str_new2(data->fullname);
95
+ }
96
+ static VALUE rubber_enum_name(VALUE value)
97
+ {
98
+ EnumData *data = NULL;
99
+
100
+ Data_Get_Struct(value, EnumData, data);
101
+
102
+ return rb_str_new2(data->name);
103
+ }
104
+
105
+ static VALUE rubber_enum_cmp(VALUE value, VALUE other)
106
+ {
107
+ VALUE a,b;
108
+ a = rb_funcall(value, rb_intern(\"to_i\"), 0);
109
+ b = rb_funcall(other, rb_intern(\"to_i\"), 0);
110
+ return rb_num_coerce_cmp(a, b);
111
+ }
112
+
113
+ static VALUE rubber_enum_to_i(VALUE value)
114
+ {
115
+ EnumData *data = NULL;
116
+
117
+ Data_Get_Struct(value, EnumData, data);
118
+
119
+ return INT2FIX(data->value);
120
+ }
121
+
122
+ static VALUE rubber_enum_coerce(VALUE value, VALUE other)
123
+ {
124
+ EnumData *data = NULL;
125
+
126
+ Data_Get_Struct(value, EnumData, data);
127
+
128
+ switch(TYPE(other))
129
+ {
130
+ case T_FIXNUM:
131
+ case T_BIGNUM:
132
+ return INT2FIX(data->value);
133
+ case T_FLOAT:
134
+ return rb_float_new(data->value);
135
+ default:
136
+ return Qnil;
137
+ }
138
+ }
139
+
140
+ "
141
+ end
142
+ args.each do |arg|
143
+ io.puts "static VALUE #{default_cname}_#{arg} = Qnil;"
144
+ end
145
+ io.puts "typedef int #{name};
146
+ #ifdef __GNUC__
147
+ // No point in declaring these unless we're using GCC
148
+ // They're ahead of any code that uses them anyway.
149
+ static VALUE enum_#{name}_to_ruby(int value)
150
+ __attribute__ ((unused))
151
+ ;
152
+ static int enum_ruby_to_#{name}(VALUE val)
153
+ __attribute__ ((unused))
154
+ ;
155
+ #endif
156
+
157
+ "
158
+ io.puts "static VALUE enum_#{name}_to_ruby(int value) { switch(value) {"
159
+ args.each do |arg|
160
+ io.puts " case #{arg}: return #{default_cname}_#{arg};"
161
+ end
162
+ io.puts "}; return Qnil; }"
163
+ io.puts "static int enum_ruby_to_#{name}(VALUE val) { return value_to_int(val, #{cname}); }"
164
+ end
165
+ include RegisterChildren
166
+ def default_cname
167
+ "enum"+name
168
+ end
169
+ def doc_rd(io)
170
+ depth = (fullname.gsub(/[^:]/,'').size >> 1)
171
+ io.puts "=#{'=' * depth} enum #{fullname}"
172
+ end
173
+ def get_root(); is_root? ? self : parent.get_root; end; def is_root?()
174
+ not parent.respond_to?(:fullname)
175
+ end
176
+ def fullname()
177
+ if parent and parent.respond_to?(:fullname)
178
+ "#{parent.fullname}::#{name}"
179
+ else
180
+ name
181
+ end
182
+ end
183
+ def same_prefix(arr)
184
+ for i in arr
185
+ return false if arr.first.first != i.first
186
+ end
187
+ return true
188
+ end
189
+ def strip_prefixes(arr)
190
+ splits = arr.collect { |i| i.strip.split(/_/) }
191
+ while (same_prefix(splits))
192
+ splits.each { |i| i.shift }
193
+ end
194
+ splits.collect!{|i| i.join('_') }
195
+ splits
196
+ end
197
+ def get_root(); is_root? ? self : parent.get_root; end;
198
+ def is_root?()
199
+ not parent.respond_to?(:fullname)
200
+ end
201
+ def register(io, already_defined=false)
202
+ unless @@declared_register
203
+ @@declared_register = true
204
+ io.puts " enumBaseClass = rb_define_class(\"Enum\", rb_cObject);"
205
+ io.puts ' rb_define_method(enumBaseClass, "inspect", rubber_enum_inspect, 0);'
206
+ io.puts ' rb_define_method(enumBaseClass, "to_i", rubber_enum_to_i, 0);'
207
+ io.puts ' rb_define_method(enumBaseClass, "coerce", rubber_enum_coerce, 1);'
208
+ io.puts ' rb_define_method(enumBaseClass, "to_s", rubber_enum_to_s, 0);'
209
+ io.puts ' rb_define_method(enumBaseClass, "to_str", rubber_enum_to_s, 0);'
210
+ io.puts ' rb_define_method(enumBaseClass, "fullname", rubber_enum_to_s, 0);'
211
+ io.puts ' rb_define_method(enumBaseClass, "name", rubber_enum_name, 0);'
212
+ io.puts ' rb_define_method(enumBaseClass, "<=>", rubber_enum_cmp, 0);'
213
+ io.puts ' '
214
+ end
215
+ if parent
216
+ io.puts " #{cname} = rb_define_class_under(#{parent.cname}, #{name.inspect}, enumBaseClass);"
217
+ else
218
+ io.puts " #{cname} = rb_define_class(#{name.inspect}, enumBaseClass);"
219
+ end
220
+
221
+ args.each do |arg|
222
+ uniq = arg[@strip..-1]
223
+ uniq.sub!(/\A[^a-zA-Z]/,'')
224
+ io.puts " #{default_cname}_#{arg} = make_enum_value(#{cname}, #{arg}, #{uniq.downcase.gsub(/_/,'-').inspect}, #{arg.inspect});"
225
+ io.puts " rb_obj_freeze(#{default_cname}_#{arg});"
226
+ io.puts " rb_define_const(#{cname}, #{uniq.upcase.inspect}, #{default_cname}_#{arg});"
227
+ end
228
+ end
229
+ end
230
+
231
+ end # Rubber