rubber-generate 0.0.5

Sign up to get free protection for your applications and to get access to all the features.
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