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 +58 -0
- data/bin/rubber-generate +54 -0
- data/lib/rubber/autord.rb +10 -0
- data/lib/rubber/codegen.rb +131 -0
- data/lib/rubber/codegen/class.rb +79 -0
- data/lib/rubber/codegen/enum.rb +231 -0
- data/lib/rubber/codegen/flags.rb +229 -0
- data/lib/rubber/codegen/float.rb +41 -0
- data/lib/rubber/codegen/function.rb +268 -0
- data/lib/rubber/codegen/gboxed.rb +30 -0
- data/lib/rubber/codegen/gcrefpool.rb +53 -0
- data/lib/rubber/codegen/genum.rb +33 -0
- data/lib/rubber/codegen/gflags.rb +38 -0
- data/lib/rubber/codegen/ginterface.rb +25 -0
- data/lib/rubber/codegen/gobject.rb +42 -0
- data/lib/rubber/codegen/integer.rb +41 -0
- data/lib/rubber/codegen/module.rb +63 -0
- data/lib/rubber/codegen/param.rb +92 -0
- data/lib/rubber/codegen/string.rb +41 -0
- data/lib/rubber/codegen/struct.rb +63 -0
- data/lib/rubber/mkextconf.rb +95 -0
- data/lib/rubber/scanner.rb +419 -0
- data/lib/rubber/struct.rb +52 -0
- data/lib/rubber/types.rb +222 -0
- metadata +85 -0
@@ -0,0 +1,30 @@
|
|
1
|
+
require 'rubber/codegen/class'
|
2
|
+
|
3
|
+
module Rubber
|
4
|
+
|
5
|
+
class C_GBoxed < C_Class
|
6
|
+
attr_accessor :gparent_class, :flag_nocopy, :c_type_name
|
7
|
+
def register(io, already_defined=false)
|
8
|
+
io.puts " #{cname} = G_DEF_CLASS(#{superclass}, #{name.inspect}, #{parent.cname});"
|
9
|
+
io.puts " rbgobj_boxed_not_copy_obj(#{superclass});" if self.flag_nocopy
|
10
|
+
|
11
|
+
register_children(io)
|
12
|
+
end
|
13
|
+
def doc_rd(io)
|
14
|
+
id = fullname()
|
15
|
+
id += " < #{gparent_class} " if gparent_class
|
16
|
+
depth = (fullname.gsub(/[^:]/,'').size >> 1)
|
17
|
+
io.puts "=#{'=' * depth} class #{id}"
|
18
|
+
io.puts @doc if @doc
|
19
|
+
contents.each { |f| f.doc_rd(io) }
|
20
|
+
end
|
21
|
+
def default_type
|
22
|
+
c_type_name && (c_type_name + ' *') || 'gpointer'
|
23
|
+
end
|
24
|
+
def pre_func(io, func)
|
25
|
+
io.puts " #{default_type} _self = ((#{default_type})RVAL2BOXED(self, #{superclass}));" if func.text =~ /_self/
|
26
|
+
super(io, func)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
end # Rubber
|
@@ -0,0 +1,53 @@
|
|
1
|
+
module Rubber
|
2
|
+
|
3
|
+
class C_GCRefPool
|
4
|
+
define_members :name
|
5
|
+
def code(io)
|
6
|
+
io.puts "static void _#{cname}_add(VALUE val)
|
7
|
+
{
|
8
|
+
if (#{cname} == Qnil)
|
9
|
+
{
|
10
|
+
#{cname} = rb_ary_new3(1, val);
|
11
|
+
}
|
12
|
+
else
|
13
|
+
{
|
14
|
+
rb_ary_push(#{cname}, val);
|
15
|
+
}
|
16
|
+
}
|
17
|
+
|
18
|
+
static void _#{cname}_del(VALUE val)
|
19
|
+
{
|
20
|
+
if (#{cname} == Qnil)
|
21
|
+
{
|
22
|
+
rb_warn(\"Trying to remove object from empty GC queue #{name}\");
|
23
|
+
return;
|
24
|
+
}
|
25
|
+
rb_ary_delete(#{cname}, val);
|
26
|
+
// If nothing is referenced, don't keep an empty array in the pool...
|
27
|
+
if (RARRAY(#{cname})->len == 0)
|
28
|
+
#{cname} = Qnil;
|
29
|
+
}
|
30
|
+
"
|
31
|
+
end
|
32
|
+
def declare(io)
|
33
|
+
io.puts "static VALUE #{cname} = Qnil;"
|
34
|
+
io.puts "static void _#{cname}_add(VALUE val);"
|
35
|
+
io.puts "static void _#{cname}_del(VALUE val);"
|
36
|
+
io.puts "#define #{name.upcase}_ADD(val) _#{cname}_add(val)"
|
37
|
+
io.puts "#define #{name.upcase}_DEL(val) _#{cname}_del(val)"
|
38
|
+
end
|
39
|
+
include RegisterChildren
|
40
|
+
def default_cname
|
41
|
+
"_gcpool_"+name
|
42
|
+
end
|
43
|
+
def doc_rd(io)
|
44
|
+
# No doc
|
45
|
+
end
|
46
|
+
def fullname()
|
47
|
+
end
|
48
|
+
def register(io, already_defined=false)
|
49
|
+
io.puts "rb_gc_register_address(&#{cname});"
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
end # Rubber
|
@@ -0,0 +1,33 @@
|
|
1
|
+
require 'rubber/codegen/enum'
|
2
|
+
|
3
|
+
module Rubber
|
4
|
+
|
5
|
+
class C_GEnum < C_Enum
|
6
|
+
define_members :name, :g_type, :prefix, :parent
|
7
|
+
def init()
|
8
|
+
($custom_maps[name] ||= {})["VALUE"] = "GENUM2RVAL(%%, #{g_type})"
|
9
|
+
($custom_maps["VALUE"] ||= {})[name] = "RVAL2GENUM(%%, #{g_type})"
|
10
|
+
end
|
11
|
+
def code(io)
|
12
|
+
end
|
13
|
+
def declare(io)
|
14
|
+
end
|
15
|
+
include RegisterChildren
|
16
|
+
def default_cname
|
17
|
+
"enum"+name
|
18
|
+
end
|
19
|
+
def get_root(); is_root? ? self : parent.get_root; end; def is_root?()
|
20
|
+
not parent.respond_to?(:fullname)
|
21
|
+
end
|
22
|
+
def doc_rd(io)
|
23
|
+
depth = (fullname.gsub(/[^:]/,'').size >> 1)
|
24
|
+
io.puts "=#{'=' * depth} enum #{fullname}"
|
25
|
+
end
|
26
|
+
def register(io, already_defined=false)
|
27
|
+
io.puts " G_DEF_CLASS(#{g_type}, #{name.inspect}, #{get_root.cname});"
|
28
|
+
io.puts " G_DEF_CONSTANTS(#{parent.cname}, #{g_type}, #{prefix.inspect});"
|
29
|
+
# strip = args.first.length - splits.first.length
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
end # Rubber
|
@@ -0,0 +1,38 @@
|
|
1
|
+
require 'rubber/codegen/enum'
|
2
|
+
|
3
|
+
module Rubber
|
4
|
+
|
5
|
+
class C_GFlags < C_Enum
|
6
|
+
define_members :name, :g_type, :prefix, :parent
|
7
|
+
def init()
|
8
|
+
($custom_maps[name] ||= {})["VALUE"] = "GFLAGS2RVAL(%%, #{g_type})"
|
9
|
+
($custom_maps["VALUE"] ||= {})[name] = "RVAL2GFLAGS(%%, #{g_type})"
|
10
|
+
gt = g_type.dup
|
11
|
+
gt.sub!("#{$1}_TYPE","#{$1}") if gt =~ /\A([A-Z]+)_TYPE/ # Strip TYPE bit
|
12
|
+
tc = gt.downcase.capitalize.gsub(/_[a-z]/){ |i| i[1..1].upcase}
|
13
|
+
#p tc
|
14
|
+
($custom_maps["VALUE"] ||= {})[tc] = "RVAL2GFLAGS(%%, #{g_type})"
|
15
|
+
end
|
16
|
+
def code(io)
|
17
|
+
end
|
18
|
+
def declare(io)
|
19
|
+
end
|
20
|
+
include RegisterChildren
|
21
|
+
def default_cname
|
22
|
+
"flags"+name
|
23
|
+
end
|
24
|
+
def doc_rd(io)
|
25
|
+
depth = (fullname.gsub(/[^:]/,'').size >> 1)
|
26
|
+
io.puts "=#{'=' * depth} flags #{fullname}"
|
27
|
+
end
|
28
|
+
def get_root(); is_root? ? self : parent.get_root; end; def is_root?()
|
29
|
+
not parent.respond_to?(:fullname)
|
30
|
+
end
|
31
|
+
def register(io, already_defined=false)
|
32
|
+
io.puts " G_DEF_CLASS(#{g_type}, #{name.inspect}, #{get_root.cname});"
|
33
|
+
io.puts " G_DEF_CONSTANTS(#{parent.cname}, #{g_type}, #{prefix.inspect});"
|
34
|
+
# strip = args.first.length - splits.first.length
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
end # Rubber
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require 'rubber/codegen/class'
|
2
|
+
|
3
|
+
module Rubber
|
4
|
+
|
5
|
+
class C_GInterface < C_Class
|
6
|
+
attr_accessor :gparent_class
|
7
|
+
def register(io, already_defined=false)
|
8
|
+
io.puts " #{cname} = G_DEF_INTERFACE(#{superclass}, #{name.inspect}, #{parent.cname});"
|
9
|
+
register_children(io)
|
10
|
+
end
|
11
|
+
def doc_rd(io)
|
12
|
+
id = fullname()
|
13
|
+
id += " < #{gparent_class} " if gparent_class
|
14
|
+
depth = (fullname.gsub(/[^:]/,'').size >> 1)
|
15
|
+
io.puts "=#{'=' * depth} interface #{id}"
|
16
|
+
io.puts @doc if @doc
|
17
|
+
contents.each { |f| f.doc_rd(io) }
|
18
|
+
end
|
19
|
+
def pre_func(io, func)
|
20
|
+
io.puts " GObject *_self = RVAL2GOBJ(self);" if func.text =~ /_self/
|
21
|
+
super(io, func)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
end # Rubber
|
@@ -0,0 +1,42 @@
|
|
1
|
+
require 'rubber/codegen/class'
|
2
|
+
|
3
|
+
module Rubber
|
4
|
+
|
5
|
+
class C_GObject < C_Class
|
6
|
+
attr_accessor :gparent_class, :c_type_name
|
7
|
+
def init()
|
8
|
+
@c_type_name ||= 'GObject' # Default
|
9
|
+
end
|
10
|
+
# def c_type
|
11
|
+
# fullname.sub(/::/,'')+' *'
|
12
|
+
# end
|
13
|
+
def register(io, already_defined=false)
|
14
|
+
if parent.child_names && parent.child_names[name]
|
15
|
+
io.puts " c#{name} = #{cname};"
|
16
|
+
else
|
17
|
+
io.puts " #{cname} = G_DEF_CLASS(#{superclass}, #{name.inspect}, #{parent.cname});"
|
18
|
+
end
|
19
|
+
io.puts @signal_marshals if defined?(@signal_marshals)
|
20
|
+
register_children(io)
|
21
|
+
end
|
22
|
+
def doc_rd(io)
|
23
|
+
id = fullname()
|
24
|
+
id += " < #{gparent_class} " if gparent_class
|
25
|
+
depth = (fullname.gsub(/[^:]/,'').size >> 1)
|
26
|
+
io.puts "=#{'=' * depth} class #{id}"
|
27
|
+
io.puts @doc if @doc
|
28
|
+
contents.each { |f| f.doc_rd(io) }
|
29
|
+
end
|
30
|
+
def feature_signal_marshal(signal,func_name)
|
31
|
+
@signal_marshals ||= ""
|
32
|
+
@signal_marshals << " G_DEF_SIGNAL_FUNC(#{cname}, #{signal.inspect}, #{func_name});\n"
|
33
|
+
end
|
34
|
+
def pre_func(io, func)
|
35
|
+
if func.text =~ /_self/
|
36
|
+
io.puts " #{@c_type_name} *_self = ((#{@c_type_name}*)RVAL2GOBJ(self));"
|
37
|
+
end
|
38
|
+
super(io, func)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
end # Rubber
|
@@ -0,0 +1,41 @@
|
|
1
|
+
module Rubber
|
2
|
+
|
3
|
+
class C_Integer
|
4
|
+
define_members :name, :number, :parent
|
5
|
+
def code(io)
|
6
|
+
end
|
7
|
+
def declare(io)
|
8
|
+
#io.puts "static VALUE #{cname};"
|
9
|
+
end
|
10
|
+
include RegisterChildren
|
11
|
+
def default_cname
|
12
|
+
#"enum"+name
|
13
|
+
end
|
14
|
+
def doc_rd(io)
|
15
|
+
depth = (fullname.gsub(/[^:]/,'').size >> 1)
|
16
|
+
io.puts "=#{'=' * depth} #{fullname}"
|
17
|
+
end
|
18
|
+
def get_root(); is_root? ? self : parent.get_root; end; def is_root?()
|
19
|
+
not parent.respond_to?(:fullname)
|
20
|
+
end
|
21
|
+
def fullname()
|
22
|
+
if parent and parent.respond_to?(:fullname)
|
23
|
+
"#{parent.fullname}::#{name}"
|
24
|
+
else
|
25
|
+
name
|
26
|
+
end
|
27
|
+
end
|
28
|
+
def get_root(); is_root? ? self : parent.get_root; end;
|
29
|
+
def is_root?()
|
30
|
+
not parent.respond_to?(:fullname)
|
31
|
+
end
|
32
|
+
def register(io, already_defined=false)
|
33
|
+
if parent
|
34
|
+
io.puts " rb_define_const(#{parent.cname}, #{name.inspect}, INT2NUM(#{number}));"
|
35
|
+
else
|
36
|
+
raise "No parent for string constant #{name}"
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
end # Rubber
|
@@ -0,0 +1,63 @@
|
|
1
|
+
module Rubber
|
2
|
+
|
3
|
+
class C_Module
|
4
|
+
define_members :name, :classes, :methods, :functions, :constants, :includes, :parent
|
5
|
+
attr_accessor :doc, :child_names
|
6
|
+
def contents()
|
7
|
+
(functions + methods + classes)
|
8
|
+
end
|
9
|
+
def code(io)
|
10
|
+
contents .each { |f| f.code(io) }
|
11
|
+
end
|
12
|
+
def declare(io)
|
13
|
+
io.puts "static VALUE #{cname};" unless external?
|
14
|
+
contents .each { |f| f.declare(io) }
|
15
|
+
end
|
16
|
+
include RegisterChildren
|
17
|
+
def default_cname
|
18
|
+
"m"+name
|
19
|
+
end
|
20
|
+
def doc_rd(io)
|
21
|
+
depth = (fullname.gsub(/[^:]/,'').size >> 1)
|
22
|
+
io.puts "=#{'=' * depth} module #{fullname}"
|
23
|
+
io.puts @doc if @doc
|
24
|
+
contents .each { |f| f.doc_rd(io) }
|
25
|
+
end
|
26
|
+
def get_root(); is_root? ? self : parent.get_root; end
|
27
|
+
def is_root?()
|
28
|
+
not parent.respond_to?(:fullname)
|
29
|
+
end
|
30
|
+
def fullname()
|
31
|
+
if is_root?
|
32
|
+
name
|
33
|
+
else
|
34
|
+
#p parent
|
35
|
+
"#{parent.fullname}::#{name}"
|
36
|
+
end
|
37
|
+
end
|
38
|
+
def external? # ie. *defined* externally...
|
39
|
+
cname == 'mGtk' || cname == 'mGdk' || cname == "mGLib"
|
40
|
+
end
|
41
|
+
def add_alias(from, to)
|
42
|
+
(@aliases ||= []) << [from, to]
|
43
|
+
end
|
44
|
+
def register_aliases(io)
|
45
|
+
if @aliases
|
46
|
+
@aliases.each do |from,to|
|
47
|
+
io.puts " rb_define_alias(#{cname},#{from.inspect},#{to.inspect});"
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
def register(io, already_defined=false)
|
52
|
+
unless external?
|
53
|
+
if parent and not parent.kind_of?(C_RootModule)
|
54
|
+
io.puts " #{cname} = rb_define_module_under(#{parent.cname}, #{name.inspect});"
|
55
|
+
else
|
56
|
+
io.puts " #{cname} = rb_define_module(#{name.inspect});"
|
57
|
+
end
|
58
|
+
end
|
59
|
+
register_children(io)
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
end # Rubber
|
@@ -0,0 +1,92 @@
|
|
1
|
+
module Rubber
|
2
|
+
|
3
|
+
class C_Param
|
4
|
+
define_members :name, :ctype, :default, :block, :rest, :rtype
|
5
|
+
RUBY_NATIVE_TYPES = %w|T_NIL T_OBJECT T_CLASS T_MODULE T_FLOAT T_STRING T_REGEXP T_ARRAY T_FIXNUM T_HASH T_STRUCT T_BIGNUM T_FILE T_TRUE T_FALSE T_DATA T_SYMBOL|
|
6
|
+
RUBY_NATIVE_NAMES = %w|Nil Object Class Module Float String Regexp Array Fixnum Hash Struct Bignum File True False Data Symbol|
|
7
|
+
|
8
|
+
def initialize(str)
|
9
|
+
r = StringScanner.new(str)
|
10
|
+
@ctype = r.scan(/[a-z_A-Z0-9|]+\s[*]*/) || 'VALUE'
|
11
|
+
@ctype.squeeze!(' ') if @ctype
|
12
|
+
@ctype.strip! if @ctype
|
13
|
+
if RUBY_NATIVE_TYPES.include?(@ctype)
|
14
|
+
@rtype = @ctype
|
15
|
+
@ctype = 'VALUE'
|
16
|
+
elsif (types = @ctype.split(/\|/)).size > 1
|
17
|
+
types.each { |i| i.strip! }
|
18
|
+
if RUBY_NATIVE_TYPES.include?(types.first)
|
19
|
+
@ctype = "VALUE"
|
20
|
+
@rtype = types
|
21
|
+
end
|
22
|
+
end
|
23
|
+
r.skip(/\s*/)
|
24
|
+
@rest = (r.skip(/\*/) and true)
|
25
|
+
@block = (r.skip(/\&/) and true)
|
26
|
+
@name = r.scan(/[A-Za-z0-9_]+/)
|
27
|
+
r.skip(/\s*/)
|
28
|
+
if r.scan(/=(.*)/)
|
29
|
+
@default= r[1].strip
|
30
|
+
end
|
31
|
+
end
|
32
|
+
#include RegisterChildren
|
33
|
+
def cname()
|
34
|
+
if auto_convert?
|
35
|
+
"__v_#{name}"
|
36
|
+
else
|
37
|
+
name
|
38
|
+
end
|
39
|
+
end
|
40
|
+
def auto_convert?
|
41
|
+
ctype and ctype != "VALUE"
|
42
|
+
end
|
43
|
+
def init_value()
|
44
|
+
if @block and not @default
|
45
|
+
"rb_block_proc()"
|
46
|
+
else
|
47
|
+
"Qnil"
|
48
|
+
end
|
49
|
+
end
|
50
|
+
def check_type(io)
|
51
|
+
case @rtype
|
52
|
+
when String
|
53
|
+
io.puts " Check_Type(#{cname}, #{@rtype});"
|
54
|
+
when Array
|
55
|
+
io.puts " if (! (" + @rtype.collect { |type| "(TYPE(#{cname}) == #{type})" }.join(' || ') + ") )"
|
56
|
+
io.puts " rb_raise(rb_eArgError, \"#{name} argument must be one of #{@rtype.collect {|i| RUBY_NATIVE_NAMES[RUBY_NATIVE_TYPES.index(i)]}.join(', ') }\");"
|
57
|
+
end
|
58
|
+
end
|
59
|
+
def declare(io,fn)
|
60
|
+
if auto_convert?
|
61
|
+
io.puts " VALUE #{cname} = #{init_value};" if fn.multi
|
62
|
+
io.puts " #{ctype} #{name}; #{ctype} __orig_#{name};"
|
63
|
+
else
|
64
|
+
io.puts " VALUE #{cname} = #{init_value};" if fn.multi
|
65
|
+
end
|
66
|
+
end
|
67
|
+
def to_str()
|
68
|
+
"#{ctype} #{name} #{default ? ' = ' + default : ''}"
|
69
|
+
end
|
70
|
+
NICE_CNAMES= {'char*'=> 'String', 'long'=>'Integer', 'int'=>'Integer', 'uint'=>'Unsigned Integer', 'ulong'=>'Unsigned Integer', 'bool'=>'Boolean'}
|
71
|
+
def ruby_def()
|
72
|
+
if @rtype.kind_of?(String)
|
73
|
+
type = RUBY_NATIVE_NAMES[RUBY_NATIVE_TYPES.index(rtype)] + ' '
|
74
|
+
elsif @rtype.kind_of?(Array)
|
75
|
+
types = @rtype.dup
|
76
|
+
types.delete('T_NIL') # Don't mention nil option
|
77
|
+
type = types.collect { |rtype| RUBY_NATIVE_NAMES[RUBY_NATIVE_TYPES.index(rtype)] }.join(' or ') + ' '
|
78
|
+
elsif ctype and ctype != 'VALUE'
|
79
|
+
if NICE_CNAMES.has_key?(ctype)
|
80
|
+
type = NICE_CNAMES[ctype]
|
81
|
+
else
|
82
|
+
type = ctype
|
83
|
+
end
|
84
|
+
type += ' '
|
85
|
+
else
|
86
|
+
type = ''
|
87
|
+
end
|
88
|
+
"#{type}#{name}"
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
end # Rubber
|
@@ -0,0 +1,41 @@
|
|
1
|
+
module Rubber
|
2
|
+
|
3
|
+
class C_String
|
4
|
+
define_members :name, :string, :parent
|
5
|
+
def code(io)
|
6
|
+
end
|
7
|
+
def declare(io)
|
8
|
+
#io.puts "static VALUE #{cname};"
|
9
|
+
end
|
10
|
+
include RegisterChildren
|
11
|
+
def default_cname
|
12
|
+
#"enum"+name
|
13
|
+
end
|
14
|
+
def doc_rd(io)
|
15
|
+
depth = (fullname.gsub(/[^:]/,'').size >> 1)
|
16
|
+
io.puts "=#{'=' * depth} #{fullname}"
|
17
|
+
end
|
18
|
+
def get_root(); is_root? ? self : parent.get_root; end; def is_root?()
|
19
|
+
not parent.respond_to?(:fullname)
|
20
|
+
end
|
21
|
+
def fullname()
|
22
|
+
if parent and parent.respond_to?(:fullname)
|
23
|
+
"#{parent.fullname}::#{name}"
|
24
|
+
else
|
25
|
+
name
|
26
|
+
end
|
27
|
+
end
|
28
|
+
def get_root(); is_root? ? self : parent.get_root; end;
|
29
|
+
def is_root?()
|
30
|
+
not parent.respond_to?(:fullname)
|
31
|
+
end
|
32
|
+
def register(io, already_defined=false)
|
33
|
+
if parent
|
34
|
+
io.puts " rb_define_const(#{parent.cname}, #{name.inspect}, rb_str_new2(#{string}));"
|
35
|
+
else
|
36
|
+
raise "No parent for string constant #{name}"
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
end # Rubber
|