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 +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
|