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,63 @@
|
|
1
|
+
require 'rubber/codegen/class'
|
2
|
+
|
3
|
+
module Rubber
|
4
|
+
|
5
|
+
class C_Struct < C_Class
|
6
|
+
define_members :name, :args, :parent
|
7
|
+
attr_reader :child_names
|
8
|
+
def init
|
9
|
+
@functions = []
|
10
|
+
@classes = []
|
11
|
+
@methods = []
|
12
|
+
end
|
13
|
+
def declare(io)
|
14
|
+
io.puts "static VALUE #{cname};"
|
15
|
+
end
|
16
|
+
include RegisterChildren
|
17
|
+
def default_cname
|
18
|
+
"struct"+name
|
19
|
+
end
|
20
|
+
def doc_rd(io)
|
21
|
+
depth = (fullname.gsub(/[^:]/,'').size >> 1)
|
22
|
+
io.puts "=#{'=' * depth} enum #{fullname}"
|
23
|
+
end
|
24
|
+
def get_root(); is_root? ? self : parent.get_root; end; def is_root?()
|
25
|
+
not parent.respond_to?(:fullname)
|
26
|
+
end
|
27
|
+
def fullname()
|
28
|
+
if parent and parent.respond_to?(:fullname)
|
29
|
+
"#{parent.fullname}::#{name}"
|
30
|
+
else
|
31
|
+
name
|
32
|
+
end
|
33
|
+
end
|
34
|
+
def same_prefix(arr)
|
35
|
+
for i in arr
|
36
|
+
return false if arr.first.first != i.first
|
37
|
+
end
|
38
|
+
return true
|
39
|
+
end
|
40
|
+
def strip_prefixes(arr)
|
41
|
+
splits = arr.collect { |i| i.strip.split(/_/) }
|
42
|
+
while (same_prefix(splits))
|
43
|
+
splits.each { |i| i.shift }
|
44
|
+
end
|
45
|
+
splits.collect!{|i| i.join('_') }
|
46
|
+
splits
|
47
|
+
end
|
48
|
+
def get_root(); is_root? ? self : parent.get_root; end;
|
49
|
+
def is_root?()
|
50
|
+
not parent.respond_to?(:fullname)
|
51
|
+
end
|
52
|
+
def register(io, already_defined=false)
|
53
|
+
io.puts " #{cname} = rb_struct_define(#{name.inspect}, #{args.map{|m|m[0]==?" && m || m.inspect}.join(', ')}, NULL);"
|
54
|
+
if parent
|
55
|
+
io.puts " rb_define_const(#{parent.cname}, #{name.inspect}, #{cname});"
|
56
|
+
else
|
57
|
+
#io.puts " rb_define_const(#{parent.cname}, #{name.inspect}, #{cname});"
|
58
|
+
end
|
59
|
+
register_children(io)
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
end # Rubber
|
@@ -0,0 +1,95 @@
|
|
1
|
+
|
2
|
+
module Rubber
|
3
|
+
def generate_extconf(scanner, io)
|
4
|
+
if true
|
5
|
+
io.puts "require 'mkmf'"
|
6
|
+
io.puts "require 'mkmf-gnome2'" if scanner.pkgs
|
7
|
+
#io.puts "$defs ||= []"
|
8
|
+
|
9
|
+
if scanner.inc_dirs
|
10
|
+
io.puts "$CFLAGS += "+scanner.inc_dirs.collect { |i| " '-I#{i}'"}.join().inspect
|
11
|
+
end
|
12
|
+
if scanner.lib_dirs
|
13
|
+
io.puts "$LDFLAGS += "+scanner.lib_dirs.collect { |i| " '-L#{i}'"}.join().inspect
|
14
|
+
end
|
15
|
+
if scanner.defs
|
16
|
+
io.puts "$CFLAGS += "+scanner.defs.collect { |i| " '-D#{i}'"}.join().inspect
|
17
|
+
end
|
18
|
+
scanner.pkgs.each { |pkg| io.puts "PKGConfig.have_package(#{pkg.inspect}) or exit(-1)" } if scanner.pkgs
|
19
|
+
|
20
|
+
if scanner.incs
|
21
|
+
scanner.incs.each { |i| io.puts "have_header(#{i.inspect}) or exit(-1)"}
|
22
|
+
end
|
23
|
+
if scanner.libs
|
24
|
+
scanner.libs.each { |i| io.puts "have_library(#{i.inspect}) or exit(-1)\n$LIBS += \" -l#{i}\""}
|
25
|
+
end
|
26
|
+
io.write <<-EOB
|
27
|
+
|
28
|
+
STDOUT.print("checking for new allocation framework... ") # for ruby-1.7
|
29
|
+
if Object.respond_to? :allocate
|
30
|
+
STDOUT.print "yes\n"
|
31
|
+
$defs << "-DHAVE_OBJECT_ALLOCATE"
|
32
|
+
else
|
33
|
+
STDOUT.print "no\n"
|
34
|
+
end
|
35
|
+
|
36
|
+
top = File.expand_path(File.dirname(__FILE__) + '/..') # XXX
|
37
|
+
$CFLAGS += " " + ['glib/src'].map{|d|
|
38
|
+
"-I" + File.join(top, d)
|
39
|
+
}.join(" ")
|
40
|
+
|
41
|
+
have_func("rb_define_alloc_func") # for ruby-1.8
|
42
|
+
|
43
|
+
#set_output_lib('libruby-#{scanner.ext}.a')
|
44
|
+
if /cygwin|mingw/ =~ RUBY_PLATFORM
|
45
|
+
top = "../.."
|
46
|
+
[
|
47
|
+
["glib/src", "ruby-glib2"],
|
48
|
+
].each{|d,l|
|
49
|
+
$LDFLAGS << sprintf(" -L%s/%s", top, d)
|
50
|
+
$libs << sprintf(" -l%s", l)
|
51
|
+
}
|
52
|
+
end
|
53
|
+
begin
|
54
|
+
srcdir = File.expand_path(File.dirname($0))
|
55
|
+
|
56
|
+
begin
|
57
|
+
|
58
|
+
obj_ext = "."+$OBJEXT
|
59
|
+
|
60
|
+
$libs = $libs.split(/\s/).uniq.join(' ')
|
61
|
+
$source_files = Dir.glob(sprintf("%s/*.c", srcdir)).map{|fname|
|
62
|
+
fname[0, srcdir.length+1] = ''
|
63
|
+
fname
|
64
|
+
}
|
65
|
+
$objs = $source_files.collect do |item|
|
66
|
+
item.gsub(/\.c$/, obj_ext)
|
67
|
+
end
|
68
|
+
|
69
|
+
#
|
70
|
+
# create Makefile
|
71
|
+
#
|
72
|
+
$defs << "-DRUBY_#{scanner.ext.upcase}_COMPILATION"
|
73
|
+
# $CFLAGS << $defs.join(' ')
|
74
|
+
create_makefile(#{scanner.ext.inspect}, srcdir)
|
75
|
+
raise Interrupt if not FileTest.exist? "Makefile"
|
76
|
+
|
77
|
+
File.open("Makefile", "a") do |mfile|
|
78
|
+
$source_files.each do |e|
|
79
|
+
mfile.print sprintf("%s: %s\n", e.gsub(/\.c$/, obj_ext), e)
|
80
|
+
end
|
81
|
+
end
|
82
|
+
ensure
|
83
|
+
#Dir.chdir ".."
|
84
|
+
end
|
85
|
+
|
86
|
+
#create_top_makefile()
|
87
|
+
rescue Interrupt
|
88
|
+
print " [error] " + $!.to_s + "\n"
|
89
|
+
end
|
90
|
+
|
91
|
+
EOB
|
92
|
+
end
|
93
|
+
end
|
94
|
+
module_function :generate_extconf
|
95
|
+
end
|
@@ -0,0 +1,419 @@
|
|
1
|
+
require 'rubber/struct'
|
2
|
+
module Rubber
|
3
|
+
class ScanState
|
4
|
+
define_members(:in_code, :in_class, :in_func, :braces)
|
5
|
+
end
|
6
|
+
|
7
|
+
class Options
|
8
|
+
attr_accessor :gtk, :glib, :gnu
|
9
|
+
alias :gtk? :gtk
|
10
|
+
alias :glib? :glib
|
11
|
+
def []=(name,val)
|
12
|
+
instance_variable_set("@"+name,val)
|
13
|
+
end
|
14
|
+
def [](name)
|
15
|
+
instance_variable_get("@"+name)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
class CRScanner
|
20
|
+
attr_reader :file, :functions, :nested_functions, :classes, :calls, :allocs, :stack, :ext, :pkgs, :incs, :doc, :raw, :libs, :defs, :pre_init_code, :post_init_code, :inc_dirs, :lib_dirs
|
21
|
+
attr_reader :options
|
22
|
+
def initialize(file)
|
23
|
+
@file = file
|
24
|
+
@ext = File::basename(file).gsub(/\..*$/, '')
|
25
|
+
@nested_functions = {}
|
26
|
+
@functions = {}
|
27
|
+
@modules = {}
|
28
|
+
@classes = {}
|
29
|
+
@calls = []
|
30
|
+
@allocs = []
|
31
|
+
@options = Options.new
|
32
|
+
# Default settings
|
33
|
+
@options.glib= true
|
34
|
+
@options.gtk= true
|
35
|
+
@options.gnu= false
|
36
|
+
end
|
37
|
+
def scan_args()
|
38
|
+
args = []
|
39
|
+
return args unless @str.peep(1) == '('
|
40
|
+
brackets = 1
|
41
|
+
arg = ''
|
42
|
+
@str.get_byte # Get first bracket
|
43
|
+
until @str.peep(1) == ')' and brackets == 1
|
44
|
+
brackets += 1 if @str.peep(1) == '('
|
45
|
+
brackets -= 1 if @str.peep(1) == ')'
|
46
|
+
if brackets == 1 and @str.peep(1) == ','
|
47
|
+
@str.pos = @str.pos + 1
|
48
|
+
arg.strip!
|
49
|
+
args.push arg unless arg.empty?
|
50
|
+
arg = ''
|
51
|
+
else
|
52
|
+
arg += @str.get_byte
|
53
|
+
end
|
54
|
+
end
|
55
|
+
@str.get_byte # Get last bracket
|
56
|
+
arg.strip!
|
57
|
+
args.push arg unless arg.empty?
|
58
|
+
args
|
59
|
+
end
|
60
|
+
def stack()
|
61
|
+
#p @stack
|
62
|
+
@stack
|
63
|
+
end
|
64
|
+
attr_accessor :state
|
65
|
+
def scan(fp)
|
66
|
+
_scan(fp)
|
67
|
+
rescue Exception
|
68
|
+
off,ind = 0,0
|
69
|
+
for line in @lines
|
70
|
+
off += line.size
|
71
|
+
break if off > @str.pos
|
72
|
+
ind += 1
|
73
|
+
end
|
74
|
+
p @state, @str, ind
|
75
|
+
raise
|
76
|
+
end
|
77
|
+
def _scan(fp)
|
78
|
+
@lines = IO.readlines(@file)
|
79
|
+
@str = StringScanner.new(@lines.join)
|
80
|
+
tokens = []
|
81
|
+
@state = ScanState.new(0,0,false,0)
|
82
|
+
@stack = [C_RootModule.new]
|
83
|
+
func = nil
|
84
|
+
until @str.empty?
|
85
|
+
######## Doc
|
86
|
+
if @str.skip(/=begin([ \t][^\n]*)?\n/) # skip =begin/=end blocks
|
87
|
+
lines = @str.scan_until(/\n=end([ \t].*)?/).split("\n")
|
88
|
+
lines.pop
|
89
|
+
if state.in_func
|
90
|
+
(func.doc ||= "") << lines.join("\n")
|
91
|
+
elsif @class and not @class.kind_of?(C_RootModule)
|
92
|
+
(@class.doc ||= "") << lines.join("\n")
|
93
|
+
else
|
94
|
+
(@doc ||= "") << lines.join("\n")
|
95
|
+
end
|
96
|
+
|
97
|
+
######## Config
|
98
|
+
|
99
|
+
elsif @str.skip(/%\{/) # Scan raw
|
100
|
+
raw = @str.scan_until(/%\}/)
|
101
|
+
raw[-2..-1] = ""
|
102
|
+
(@raw ||= "") << raw
|
103
|
+
elsif @str.skip(/%pre_init\{/) # Scan raw
|
104
|
+
raw = @str.scan_until(/%\}/)
|
105
|
+
raw[-2..-1] = ""
|
106
|
+
(@pre_init_code ||= "") << raw
|
107
|
+
elsif @str.skip(/%post_init\{/) # Scan raw
|
108
|
+
raw = @str.scan_until(/%\}/)
|
109
|
+
raw[-2..-1] = ""
|
110
|
+
(@post_init_code ||= "") << raw
|
111
|
+
elsif @str.skip(/\s+/) # skip
|
112
|
+
func.text += " " if state.in_func
|
113
|
+
elsif @str.skip(/%name */) # Extension name
|
114
|
+
@ext = @str.scan(/[a-zA-Z0-9]+/)
|
115
|
+
elsif @str.skip(/%pkg-config\s*([-a-z.0-9+]+)/) # pkg-config library
|
116
|
+
@pkgs ||= []
|
117
|
+
@pkgs << @str[1]
|
118
|
+
elsif @str.skip(/%include_dir\s+(.+)\n/) # Include dirs
|
119
|
+
@inc_dirs ||= []
|
120
|
+
@inc_dirs << @str[1].strip
|
121
|
+
elsif @str.skip(/%lib_dir\s+(.+)\n/) # Library dir
|
122
|
+
@lib_dirs ||= []
|
123
|
+
@lib_dirs << @str[1].strip
|
124
|
+
elsif @str.skip(/%include\s+(.+)\n/) # Include file
|
125
|
+
@incs ||= []
|
126
|
+
@incs << @str[1].strip
|
127
|
+
elsif @str.skip(/%option +([a-z]+)=(yes|no)\n/) # Option
|
128
|
+
case @str[1]
|
129
|
+
when 'glib','gtk','gnu'
|
130
|
+
@options[@str[1]] = (@str[2] == 'yes')
|
131
|
+
else
|
132
|
+
raise "Unknown option #{@str[1]}"
|
133
|
+
end
|
134
|
+
elsif @str.skip(/%lib\s+(.+)\n/) # Skip single-line comment
|
135
|
+
@libs ||= []
|
136
|
+
@libs << @str[1].strip
|
137
|
+
elsif @str.skip(/%define\s+(.+)\n/) # Skip single-line comment
|
138
|
+
@defs ||= []
|
139
|
+
@defs << @str[1].strip
|
140
|
+
elsif @str.skip(/%equiv[a-z]*\s+([^=\n]+)=([^=\n]+)\n/) # Skip single-line comment
|
141
|
+
$equivalents[@str[1].gsub(/ /,'').strip] = @str[2].gsub(/ /,'').strip
|
142
|
+
elsif @str.skip(/%map\s+([^->]+?)\>([^:]+):([^@\n]+) *@? *(.*)\n/) # Skip single-line comment
|
143
|
+
from, to, code = *[@str[1], @str[2], @str[3]].collect { |i| i.strip }
|
144
|
+
free_code = @str[4]
|
145
|
+
from.gsub!(/ /,'')
|
146
|
+
to.gsub!(/ /,'')
|
147
|
+
puts "Mapping #{from} -> #{to}"
|
148
|
+
($custom_maps[from] ||= {})[to] = code
|
149
|
+
$custom_frees[to] = free_code
|
150
|
+
elsif state.in_class > 0 and state.in_func == false and @str.skip(/%flag\s+([a-z0-9_A-Z]+)/)
|
151
|
+
flag = ("flag_"+@str[1]+"=").intern
|
152
|
+
if stack.last.respond_to?(flag)
|
153
|
+
stack.last.__send__(flag, true)
|
154
|
+
else
|
155
|
+
raise "%flags directive cannot be used here (#{stack.last.class} doesn't respond to #{flag})"
|
156
|
+
end
|
157
|
+
elsif state.in_class > 0 and state.in_func == false and @str.skip(/%feature\s+([a-z0-9_A-Z]+)/)
|
158
|
+
flag = ("feature_"+@str[1]).intern
|
159
|
+
@str.skip(/\s+/)
|
160
|
+
args = []
|
161
|
+
if @str.skip(/\(/)
|
162
|
+
args = @str.scan_until(/\)/)[0..-2].split(/, */).map { |i| i.strip }
|
163
|
+
end
|
164
|
+
@str.skip(/;/)
|
165
|
+
if stack.last.respond_to?(flag)
|
166
|
+
stack.last.__send__(flag, *args)
|
167
|
+
else
|
168
|
+
raise "%feature '#{@str[1]}' directive cannot be used here (#{stack.last.class} doesn't support it)"
|
169
|
+
end
|
170
|
+
elsif @str.skip(/%/) # Skip single-line comment
|
171
|
+
@str.skip_until(/\n/)
|
172
|
+
|
173
|
+
|
174
|
+
####### Comments
|
175
|
+
|
176
|
+
elsif state.in_func == false and @str.skip(/#.*/) # Comment
|
177
|
+
|
178
|
+
elsif state.in_func == false and @str.skip(/\/\/.*/) # Comment
|
179
|
+
|
180
|
+
elsif state.in_func == false and @str.skip(/\/\*(.|\n)*\*\//) # Multi-line Comment
|
181
|
+
|
182
|
+
|
183
|
+
|
184
|
+
####### Code
|
185
|
+
|
186
|
+
elsif txt = @str.scan(/['"]/) #' Skip quoted string
|
187
|
+
txt += @str.scan_until(/(^|[^\\])#{txt}/) # Skip until unescaped quote
|
188
|
+
func.text += txt if state.in_func
|
189
|
+
elsif state.in_func == false and @str.skip(/module(?= )/x) # Module defn
|
190
|
+
@str.skip(/\s+/)
|
191
|
+
name = @str.scan(/[A-Z][a-z_0-9A-Z]*/)
|
192
|
+
@classes[name] = C_Module.new(name, [], [], [])
|
193
|
+
@classes[name].parent = stack.last
|
194
|
+
stack.last.classes.push(@classes[name])
|
195
|
+
stack.push(@class = @classes[name])
|
196
|
+
puts "module "+ @class.fullname + "-#{@class.name}"
|
197
|
+
state.in_class += 1
|
198
|
+
elsif state.in_func == false and @str.skip(/class(?= )/x) # Class defn
|
199
|
+
@str.skip(/\s+/)
|
200
|
+
name = @str.scan(/[A-Z][a-z_0-9A-Z]*/)
|
201
|
+
superclass = nil
|
202
|
+
@str.skip(/\s*/)
|
203
|
+
if @str.skip(/</)
|
204
|
+
@str.skip(/\s*/)
|
205
|
+
superclass = @str.scan(/[A-Z][a-z_0-9A-Z]*/)
|
206
|
+
end
|
207
|
+
@classes[name] = C_Class.new(name, superclass, [], [], [])
|
208
|
+
@classes[name].parent = stack.last
|
209
|
+
stack.last.classes.push(@classes[name])
|
210
|
+
stack.push(@class = @classes[name])
|
211
|
+
puts "class "+ @class.fullname
|
212
|
+
state.in_class += 1
|
213
|
+
|
214
|
+
elsif state.in_func == false and @str.skip(/struct(?= )/x) # Ruby Struct
|
215
|
+
@str.skip(/\s+/)
|
216
|
+
name = @str.scan(/[A-Z][a-z_0-9A-Z]*/)
|
217
|
+
@str.skip(/\s+/)
|
218
|
+
if @str.skip(/\(/)
|
219
|
+
args = @str.scan_until(/\)/)[0..-2].split(/, */).collect { |i| i.strip }
|
220
|
+
end
|
221
|
+
# NB. struct Name(arg0...argN)
|
222
|
+
if @str.skip(/\s*;/)
|
223
|
+
stack.last.classes.push(C_Struct.new(name, args, stack.last))
|
224
|
+
else
|
225
|
+
@classes[name] = C_Struct.new(name, args, stack.last)
|
226
|
+
stack.last.classes.push(@classes[name])
|
227
|
+
stack.push(@class = @classes[name])
|
228
|
+
puts "struct "+ @class.fullname
|
229
|
+
state.in_class += 1
|
230
|
+
end
|
231
|
+
elsif state.in_func == false and @str.skip(/gcpool(?= )/x) # GC Pool
|
232
|
+
@str.skip(/\s+/)
|
233
|
+
name = @str.scan(/[a-z_0-9A-Z]*/)
|
234
|
+
puts "GCPool #{name}"
|
235
|
+
stack.first.classes.push(C_GCRefPool.new(name))
|
236
|
+
|
237
|
+
elsif state.in_func == false and @str.skip(/(enum)(?= )/x) # C Enum as module wrapper
|
238
|
+
what = @str[1]
|
239
|
+
@str.skip(/\s+/)
|
240
|
+
name = @str.scan(/[A-Z][a-z_0-9A-Z]*/)
|
241
|
+
@str.skip(/\s+/)
|
242
|
+
if @str.skip(/\(/)
|
243
|
+
args = @str.scan_until(/\)/)[0..-2].split(/, */).collect { |i| i.strip }
|
244
|
+
end
|
245
|
+
if what == "flags"
|
246
|
+
stack.last.classes.push(C_Flags.new(name, args, stack.last))
|
247
|
+
else
|
248
|
+
stack.last.classes.push(C_Enum.new(name, args, stack.last))
|
249
|
+
end
|
250
|
+
|
251
|
+
elsif state.in_func == false and @str.skip(/(genum|gflags)(?= )/x) # C GEnum as module wrapper
|
252
|
+
what = @str[1]
|
253
|
+
@str.skip(/\s+/)
|
254
|
+
name = @str.scan(/[A-Z][a-z_0-9A-Z]*/)
|
255
|
+
@str.skip(/\s+/)
|
256
|
+
g_type = @str.scan(/[A-Z][_0-9A-Z]*/)
|
257
|
+
@str.skip(/\s+/)
|
258
|
+
prefix = @str.scan(/[A-Z][_0-9A-Z]*/)
|
259
|
+
@str.skip(/\s*;/)
|
260
|
+
if what == "gflags"
|
261
|
+
stack.last.classes.push(C_GFlags.new(name, g_type, prefix, stack.last))
|
262
|
+
else
|
263
|
+
stack.last.classes.push(C_GEnum.new(name, g_type, prefix, stack.last))
|
264
|
+
end
|
265
|
+
|
266
|
+
elsif state.in_func == false and @str.skip(/(gobject|ginterface|gboxed)(?= )/x) # Class defn
|
267
|
+
type=@str[1]
|
268
|
+
@str.skip(/\s+/)
|
269
|
+
name = @str.scan(/[A-Z][a-z_0-9A-Z]*/)
|
270
|
+
superclass = nil
|
271
|
+
@str.skip(/\s*/)
|
272
|
+
if @str.skip(/\</)
|
273
|
+
@str.skip(/\s*/)
|
274
|
+
gtype = @str.scan(/[A-Z_]+/)
|
275
|
+
end
|
276
|
+
@str.skip(/\s*/)
|
277
|
+
if @str.skip(/:/)
|
278
|
+
@str.skip(/\s*/)
|
279
|
+
gparent_class = @str.scan(/[A-Z_:a-z0-9]+/)
|
280
|
+
end
|
281
|
+
case type
|
282
|
+
when "gobject"
|
283
|
+
@classes[name] = C_GObject.new(name, gtype, [], [], [])
|
284
|
+
when "ginterface"
|
285
|
+
@classes[name] = C_GInterface.new(name, gtype, [], [], [])
|
286
|
+
when "gboxed"
|
287
|
+
@classes[name] = C_GBoxed.new(name, gtype, [], [], [])
|
288
|
+
else
|
289
|
+
raise "#{name} is not a GObject or GInterface..."
|
290
|
+
end
|
291
|
+
@classes[name].gparent_class = gparent_class
|
292
|
+
@classes[name].parent = stack.last
|
293
|
+
stack.last.classes.push(@classes[name])
|
294
|
+
stack.push(@class = @classes[name])
|
295
|
+
puts "class "+ @class.fullname
|
296
|
+
state.in_class += 1
|
297
|
+
elsif @str.scan(/@type\s+([A-Za-z_0-9]+)/)
|
298
|
+
type = @str[1]
|
299
|
+
prev = stack.last
|
300
|
+
if prev.is_a?(C_GObject)
|
301
|
+
# p c_type, self
|
302
|
+
puts "Converting #{type}* to & from VALUE"
|
303
|
+
prev.c_type_name = type
|
304
|
+
($custom_maps[type+'*'] ||= {})["VALUE"] = "GOBJ2RVAL(%%)"
|
305
|
+
($custom_maps["VALUE"] ||= {})[type+'*'] = "RVAL2GOBJ(%%)"
|
306
|
+
elsif prev.is_a?(C_GBoxed)
|
307
|
+
prev.c_type_name = type
|
308
|
+
|
309
|
+
($custom_maps[type+'*'] ||= {})["VALUE"] = "BOXED2RVAL(%%, #{prev.superclass})"
|
310
|
+
($custom_maps["VALUE"] ||= {})[type+'*'] = "RVAL2BOXED(%%, #{prev.superclass})"
|
311
|
+
else
|
312
|
+
# Invalid type directive
|
313
|
+
end
|
314
|
+
elsif @str.skip(/end(?=\s)/x)
|
315
|
+
last = stack.pop
|
316
|
+
puts "#{last.class} - #{last.name}"
|
317
|
+
case last
|
318
|
+
when C_Module, C_Class, C_Enum, C_Flags, C_Struct, C_GObject, C_GInterface, C_GBoxed
|
319
|
+
state.in_class -= 1
|
320
|
+
@class = stack.last
|
321
|
+
when C_Function
|
322
|
+
state.in_func = false
|
323
|
+
else
|
324
|
+
STDERR.puts "Remaining code: #{@str.rest}"
|
325
|
+
STDERR.puts "Defined Classes: #{@classes.keys.join(', ')}"
|
326
|
+
p stack
|
327
|
+
raise "Invalid stack entry #{last.class}"
|
328
|
+
end
|
329
|
+
elsif @str.skip(/alias\s+:([A-Za-z0-9_]*[\[\]]{0,2}[?!=]?)\s+:([A-Za-z0-9_]*[\[\]]{0,2}[?!=]?)/) # Alias
|
330
|
+
@class.add_alias(@str[1], @str[2]) if @class.respond_to?(:add_alias)
|
331
|
+
elsif @str.skip(/(pre|post)_func\s+do/)
|
332
|
+
where = @str[1]
|
333
|
+
str = @str.scan_until(/\bend/)#[0,-4]
|
334
|
+
unless str
|
335
|
+
raise "Invalid #{where}_func definition: #{@str.peek(200).inspect}"
|
336
|
+
end
|
337
|
+
str = str[0..-4].strip
|
338
|
+
except = only = nil
|
339
|
+
@str.skip(/\s*/)
|
340
|
+
if @str.skip(/,\s*:(only|except)\s*=\>\s*(\[[^\]]+\])/)
|
341
|
+
if @str[1] == 'only'
|
342
|
+
only = eval(@str[2]).map{|i|i.to_s}
|
343
|
+
else
|
344
|
+
except = eval(@str[2]).map{|i|i.to_s}
|
345
|
+
end
|
346
|
+
end
|
347
|
+
if where == 'pre'
|
348
|
+
@class.pre_func = str
|
349
|
+
@class.pre_only = only if only
|
350
|
+
@class.pre_except = except if except
|
351
|
+
else
|
352
|
+
@class.post_func = str
|
353
|
+
@class.post_only = only if only
|
354
|
+
@class.post_except = except if except
|
355
|
+
end
|
356
|
+
elsif @str.skip(/pre_func\s+(.*)/) # Pre func code
|
357
|
+
@class.pre_func= @str[1] if @class.respond_to?(:pre_func)
|
358
|
+
elsif @str.skip(/post_func\s+(.*)/) # Post func code
|
359
|
+
@class.post_func= @str[1] if @class.respond_to?(:post_func)
|
360
|
+
elsif @str.skip(/def(?=\s+)/x) # Function defn
|
361
|
+
@str.skip(/\s+/)
|
362
|
+
if @str.scan(/([a-zA-Z_* ]+):/)
|
363
|
+
returntype = @str[1]
|
364
|
+
else
|
365
|
+
returntype = 'VALUE'
|
366
|
+
end
|
367
|
+
prename = ''
|
368
|
+
prename = @str.scan(/self\./)
|
369
|
+
name = @str.scan(/[a-z_0-9A-Z.]+[?!=]?/)
|
370
|
+
unless name
|
371
|
+
name = @str.scan(/[-\[\]<>~=+|&]{1,3}/)
|
372
|
+
end
|
373
|
+
name = prename.to_s + (oname=name)
|
374
|
+
#p [prename, oname, name]
|
375
|
+
@str.skip(/\s*/)
|
376
|
+
args = scan_args().collect { |i| C_Param.new(i) }
|
377
|
+
func = @functions[name] = C_Function.new(name, args, '')
|
378
|
+
func.returntype = returntype
|
379
|
+
func.parent = @class
|
380
|
+
stack.last.functions.push(func)
|
381
|
+
puts "def "+ func.fullname
|
382
|
+
stack.push(func)
|
383
|
+
state.in_func = true
|
384
|
+
|
385
|
+
elsif state.in_func == false and @str.skip(/(string|integer|float|double|int)(?= )/x) # C String as module wrapper
|
386
|
+
type= @str[1]
|
387
|
+
@str.skip(/\s+/)
|
388
|
+
name = @str.scan(/[A-Z][a-z_0-9A-Z]*/)
|
389
|
+
@str.skip(/\s*=\s*/)
|
390
|
+
if @str.skip(/"/) #"
|
391
|
+
string = '"' + @str.scan_until(/[^\\]?"/) #"
|
392
|
+
elsif t = @str.scan(/([A-Z][a-z_0-9A-Z]*)/)
|
393
|
+
string = @str[1]
|
394
|
+
elsif type =~ /^(flo|dou|int)/ and t = @str.scan(/([0-9]+(\.[0-9]+)?(e[0-9]+)?)/)
|
395
|
+
string = @str[1]
|
396
|
+
end
|
397
|
+
klass = nil
|
398
|
+
case type
|
399
|
+
when /^str/
|
400
|
+
klass = C_String
|
401
|
+
when /^int/
|
402
|
+
klass = C_Integer
|
403
|
+
when /^(flo|dou)/
|
404
|
+
klass = C_Float
|
405
|
+
end
|
406
|
+
stack.last.classes.push(klass.new(name, string, stack.last)) if klass
|
407
|
+
|
408
|
+
elsif txt = @str.get_byte # Spare chars
|
409
|
+
if state.in_func
|
410
|
+
func.text += txt
|
411
|
+
else
|
412
|
+
puts '"' << txt << '"'
|
413
|
+
end
|
414
|
+
end
|
415
|
+
end
|
416
|
+
end
|
417
|
+
end
|
418
|
+
|
419
|
+
end # m Rubber
|