ffi-swig-generator 0.2.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.hg/00changelog.i +0 -0
- data/.hg/branch +1 -0
- data/.hg/dirstate +0 -0
- data/.hg/hgrc +2 -0
- data/.hg/requires +2 -0
- data/.hg/store/00changelog.i +0 -0
- data/.hg/store/00manifest.i +0 -0
- data/.hg/store/data/_history.txt.i +0 -0
- data/.hg/store/data/_r_e_a_d_m_e.rdoc.i +0 -0
- data/.hg/store/data/_rakefile.i +0 -0
- data/.hg/store/data/bin/ffi-gen.i +0 -0
- data/.hg/store/data/examples/_rakefile.i +0 -0
- data/.hg/store/data/examples/interfaces/libc.i.i +0 -0
- data/.hg/store/data/examples/interfaces/wiiuse.i.i +0 -0
- data/.hg/store/data/lib/ffi-swig-generator.rb.i +0 -0
- data/.hg/store/data/lib/generator/application.rb.i +0 -0
- data/.hg/store/data/lib/generator/generator.rb.i +0 -0
- data/.hg/store/data/lib/generator/generatortask.rb.i +0 -0
- data/.hg/store/data/pkg/ffi-swig-generator-0.2.1.gem.i +0 -0
- data/.hg/store/data/pkg/ffi-swig-generator-0.2.1.tgz.i +0 -0
- data/.hg/store/data/pkg/ffi-swig-generator-0.2.1/.gitignore.i +0 -0
- data/.hg/store/data/pkg/ffi-swig-generator-0.2.1/_history.txt.i +0 -0
- data/.hg/store/data/pkg/ffi-swig-generator-0.2.1/_r_e_a_d_m_e.rdoc.i +0 -0
- data/.hg/store/data/pkg/ffi-swig-generator-0.2.1/_rakefile.i +0 -0
- data/.hg/store/data/pkg/ffi-swig-generator-0.2.1/bin/ffi-gen.i +0 -0
- data/.hg/store/data/pkg/ffi-swig-generator-0.2.1/examples/_rakefile.i +0 -0
- data/.hg/store/data/pkg/ffi-swig-generator-0.2.1/examples/interfaces/libc.i.i +0 -0
- data/.hg/store/data/pkg/ffi-swig-generator-0.2.1/examples/interfaces/wiiuse.i.i +0 -0
- data/.hg/store/data/pkg/ffi-swig-generator-0.2.1/ffi-swig-generator.gemspec.i +0 -0
- data/.hg/store/data/pkg/ffi-swig-generator-0.2.1/lib/ffi-swig-generator.rb.i +0 -0
- data/.hg/store/data/pkg/ffi-swig-generator-0.2.1/lib/generator/application.rb.i +0 -0
- data/.hg/store/data/pkg/ffi-swig-generator-0.2.1/lib/generator/generator.rb.i +0 -0
- data/.hg/store/data/pkg/ffi-swig-generator-0.2.1/lib/generator/generatortask.rb.i +0 -0
- data/.hg/store/data/pkg/ffi-swig-generator-0.2.1/spec/ffi-swig-generator__spec.rb.i +0 -0
- data/.hg/store/data/pkg/ffi-swig-generator-0.2.1/spec/generator/generator__spec.rb.i +0 -0
- data/.hg/store/data/pkg/ffi-swig-generator-0.2.1/spec/generator/swig/constants.i.i +0 -0
- data/.hg/store/data/pkg/ffi-swig-generator-0.2.1/spec/generator/swig/enums.i.i +0 -0
- data/.hg/store/data/pkg/ffi-swig-generator-0.2.1/spec/generator/swig/functions.i.i +0 -0
- data/.hg/store/data/pkg/ffi-swig-generator-0.2.1/spec/generator/swig/structs.i.i +0 -0
- data/.hg/store/data/pkg/ffi-swig-generator-0.2.1/spec/generator/swig/testlib.i.i +0 -0
- data/.hg/store/data/pkg/ffi-swig-generator-0.2.1/spec/generator/swig/typedefs.i.i +0 -0
- data/.hg/store/data/pkg/ffi-swig-generator-0.2.1/spec/generator/swig/types.i.i +0 -0
- data/.hg/store/data/pkg/ffi-swig-generator-0.2.1/spec/generator/swig/unions.i.i +0 -0
- data/.hg/store/data/pkg/ffi-swig-generator-0.2.1/spec/spec.opts.i +0 -0
- data/.hg/store/data/pkg/ffi-swig-generator-0.2.1/spec/spec__helper.rb.i +0 -0
- data/.hg/store/data/pkg/ffi-swig-generator-0.2.1/tasks/ann.rake.i +0 -0
- data/.hg/store/data/pkg/ffi-swig-generator-0.2.1/tasks/bones.rake.i +0 -0
- data/.hg/store/data/pkg/ffi-swig-generator-0.2.1/tasks/gem.rake.i +0 -0
- data/.hg/store/data/pkg/ffi-swig-generator-0.2.1/tasks/git.rake.i +0 -0
- data/.hg/store/data/pkg/ffi-swig-generator-0.2.1/tasks/notes.rake.i +0 -0
- data/.hg/store/data/pkg/ffi-swig-generator-0.2.1/tasks/post__load.rake.i +0 -0
- data/.hg/store/data/pkg/ffi-swig-generator-0.2.1/tasks/rdoc.rake.i +0 -0
- data/.hg/store/data/pkg/ffi-swig-generator-0.2.1/tasks/rubyforge.rake.i +0 -0
- data/.hg/store/data/pkg/ffi-swig-generator-0.2.1/tasks/setup.rb.i +0 -0
- data/.hg/store/data/pkg/ffi-swig-generator-0.2.1/tasks/spec.rake.i +0 -0
- data/.hg/store/data/pkg/ffi-swig-generator-0.2.1/tasks/svn.rake.i +0 -0
- data/.hg/store/data/pkg/ffi-swig-generator-0.2.1/tasks/test.rake.i +0 -0
- data/.hg/store/data/spec/ffi-swig-generator__spec.rb.i +0 -0
- data/.hg/store/data/spec/generator/generator__spec.rb.i +0 -0
- data/.hg/store/data/spec/generator/swig/constants.i.i +0 -0
- data/.hg/store/data/spec/generator/swig/enums.i.i +0 -0
- data/.hg/store/data/spec/generator/swig/functions.i.i +0 -0
- data/.hg/store/data/spec/generator/swig/structs.i.i +0 -0
- data/.hg/store/data/spec/generator/swig/testlib.i.i +0 -0
- data/.hg/store/data/spec/generator/swig/typedefs.i.i +0 -0
- data/.hg/store/data/spec/generator/swig/types.i.i +0 -0
- data/.hg/store/data/spec/generator/swig/unions.i.i +0 -0
- data/.hg/store/data/spec/spec.opts.i +0 -0
- data/.hg/store/data/spec/spec__helper.rb.i +0 -0
- data/.hg/store/data/tasks/ann.rake.i +0 -0
- data/.hg/store/data/tasks/bones.rake.i +0 -0
- data/.hg/store/data/tasks/gem.rake.i +0 -0
- data/.hg/store/data/tasks/git.rake.i +0 -0
- data/.hg/store/data/tasks/notes.rake.i +0 -0
- data/.hg/store/data/tasks/post__load.rake.i +0 -0
- data/.hg/store/data/tasks/rdoc.rake.i +0 -0
- data/.hg/store/data/tasks/rubyforge.rake.i +0 -0
- data/.hg/store/data/tasks/setup.rb.i +0 -0
- data/.hg/store/data/tasks/spec.rake.i +0 -0
- data/.hg/store/data/tasks/svn.rake.i +0 -0
- data/.hg/store/data/tasks/test.rake.i +0 -0
- data/.hg/store/undo +0 -0
- data/.hg/undo.branch +1 -0
- data/.hg/undo.dirstate +0 -0
- data/.hgignore +2 -0
- data/History.txt +25 -0
- data/README.rdoc +99 -0
- data/Rakefile +42 -0
- data/bin/ffi-gen +7 -0
- data/examples/Rakefile +4 -0
- data/examples/interfaces/libc.i +26 -0
- data/examples/interfaces/wiiuse.i +672 -0
- data/lib/ffi-swig-generator.rb +48 -0
- data/lib/generator/application.rb +69 -0
- data/lib/generator/generator.rb +344 -0
- data/lib/generator/generatortask.rb +45 -0
- data/spec/ffi-swig-generator_spec.rb +7 -0
- data/spec/generator/generator_spec.rb +248 -0
- data/spec/generator/swig/constants.i +3 -0
- data/spec/generator/swig/enums.i +5 -0
- data/spec/generator/swig/functions.i +24 -0
- data/spec/generator/swig/structs.i +25 -0
- data/spec/generator/swig/testlib.i +48 -0
- data/spec/generator/swig/typedefs.i +5 -0
- data/spec/generator/swig/types.i +52 -0
- data/spec/generator/swig/unions.i +6 -0
- data/spec/spec.opts +4 -0
- data/spec/spec_helper.rb +27 -0
- data/tasks/ann.rake +80 -0
- data/tasks/bones.rake +20 -0
- data/tasks/gem.rake +201 -0
- data/tasks/git.rake +40 -0
- data/tasks/notes.rake +27 -0
- data/tasks/post_load.rake +34 -0
- data/tasks/rdoc.rake +50 -0
- data/tasks/rubyforge.rake +55 -0
- data/tasks/setup.rb +300 -0
- data/tasks/spec.rake +54 -0
- data/tasks/svn.rake +47 -0
- data/tasks/test.rake +40 -0
- metadata +204 -0
@@ -0,0 +1,48 @@
|
|
1
|
+
module FFI
|
2
|
+
module Generator
|
3
|
+
# :stopdoc:
|
4
|
+
VERSION = '0.2.1'
|
5
|
+
LIBPATH = ::File.expand_path(::File.dirname(__FILE__)) + ::File::SEPARATOR
|
6
|
+
PATH = ::File.dirname(LIBPATH) + ::File::SEPARATOR
|
7
|
+
# :startdoc:
|
8
|
+
|
9
|
+
# Returns the version string for the library.
|
10
|
+
#
|
11
|
+
def self.version
|
12
|
+
VERSION
|
13
|
+
end
|
14
|
+
|
15
|
+
# Returns the library path for the module. If any arguments are given,
|
16
|
+
# they will be joined to the end of the libray path using
|
17
|
+
# <tt>File.join</tt>.
|
18
|
+
#
|
19
|
+
def self.libpath( *args )
|
20
|
+
args.empty? ? LIBPATH : ::File.join(LIBPATH, args.flatten)
|
21
|
+
end
|
22
|
+
|
23
|
+
# Returns the lpath for the module. If any arguments are given,
|
24
|
+
# they will be joined to the end of the path using
|
25
|
+
# <tt>File.join</tt>.
|
26
|
+
#
|
27
|
+
def self.path( *args )
|
28
|
+
args.empty? ? PATH : ::File.join(PATH, args.flatten)
|
29
|
+
end
|
30
|
+
|
31
|
+
# Utility method used to require all files ending in .rb that lie in the
|
32
|
+
# directory below this file that has the same name as the filename passed
|
33
|
+
# in. Optionally, a specific _directory_ name can be passed in such that
|
34
|
+
# the _filename_ does not have to be equivalent to the directory.
|
35
|
+
#
|
36
|
+
def self.require_all_libs_relative_to( fname, dir = nil )
|
37
|
+
dir ||= ::File.basename(fname, '.*')
|
38
|
+
search_me = ::File.expand_path(
|
39
|
+
::File.join(::File.dirname(fname), dir, '**', '*.rb'))
|
40
|
+
|
41
|
+
Dir.glob(search_me).sort.each {|rb| require rb}
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
FFI::Generator.require_all_libs_relative_to(__FILE__, 'generator')
|
47
|
+
|
48
|
+
# EOF
|
@@ -0,0 +1,69 @@
|
|
1
|
+
require 'getoptlong'
|
2
|
+
|
3
|
+
module FFI
|
4
|
+
module Generator
|
5
|
+
class Application
|
6
|
+
OPTIONS = [
|
7
|
+
[ "--help", "-u", GetoptLong::NO_ARGUMENT,
|
8
|
+
"Display help information." ],
|
9
|
+
[ "--version", "-v", GetoptLong::NO_ARGUMENT,
|
10
|
+
"Display the version number and quit." ],
|
11
|
+
]
|
12
|
+
|
13
|
+
USAGE_PREAMBLE = <<-EOU
|
14
|
+
Usage: ffi-gen [options] <input_file> <output_file>
|
15
|
+
|
16
|
+
<input_file> is the xml parse tree generated by swig -xml command.
|
17
|
+
<output_file> is the ruby-ffi wrapper file.
|
18
|
+
|
19
|
+
EOU
|
20
|
+
class << self
|
21
|
+
def run
|
22
|
+
process_args
|
23
|
+
if ARGV.size == 2
|
24
|
+
File.open(ARGV[1], 'w') do |file|
|
25
|
+
file << FFI::Generator::Parser.generate(Nokogiri::XML(File.open(ARGV[0])))
|
26
|
+
end
|
27
|
+
else
|
28
|
+
help
|
29
|
+
raise "Invalid number of arguments!"
|
30
|
+
end
|
31
|
+
end
|
32
|
+
private
|
33
|
+
def do_option(option, value = nil)
|
34
|
+
case option
|
35
|
+
when '--help'
|
36
|
+
help
|
37
|
+
exit
|
38
|
+
when '--version'
|
39
|
+
puts "ffi-swig-generator, version #{Generator::VERSION}\n"
|
40
|
+
exit
|
41
|
+
end
|
42
|
+
end
|
43
|
+
def command_line_options
|
44
|
+
OPTIONS.collect { |lst| lst[0..-2] }
|
45
|
+
end
|
46
|
+
def process_args
|
47
|
+
opts = GetoptLong.new(*command_line_options)
|
48
|
+
opts.each { |opt, value| do_option(opt, value) }
|
49
|
+
end
|
50
|
+
def help
|
51
|
+
puts
|
52
|
+
puts USAGE_PREAMBLE
|
53
|
+
puts "Recognized options are:"
|
54
|
+
puts
|
55
|
+
OPTIONS.sort.each do |long, short, mode, desc|
|
56
|
+
if mode == GetoptLong::REQUIRED_ARGUMENT
|
57
|
+
if desc =~ /\b([A-Z]{2,})\b/
|
58
|
+
long = long + "=#{$1}"
|
59
|
+
end
|
60
|
+
end
|
61
|
+
printf " %-20s (%s)\n", long, short
|
62
|
+
printf " %s\n", desc
|
63
|
+
puts
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
@@ -0,0 +1,344 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'nokogiri'
|
3
|
+
|
4
|
+
module FFI
|
5
|
+
module Generator
|
6
|
+
@typedefs = {}
|
7
|
+
TYPES = {
|
8
|
+
'char' => ':char',
|
9
|
+
'double' => ':double',
|
10
|
+
'float' => ':float',
|
11
|
+
'unsigned long' => ':ulong',
|
12
|
+
'unsigned char' => ':uchar',
|
13
|
+
'signed char' => ':char',
|
14
|
+
'unsigned char' => ':uchar',
|
15
|
+
'short' => ':short',
|
16
|
+
'signed short' => ':short',
|
17
|
+
'signed short int' => ':short',
|
18
|
+
'unsigned short' => ':ushort',
|
19
|
+
'unsigned short int' => ':ushort',
|
20
|
+
'int' => ':int',
|
21
|
+
'signed int' => ':int',
|
22
|
+
'unsigned int' => ':uint',
|
23
|
+
'long' => ':long',
|
24
|
+
'long int' => ':long',
|
25
|
+
'signed long' => ':long',
|
26
|
+
'signed long int' => ':long',
|
27
|
+
'unsigned long' => ':ulong',
|
28
|
+
'unsigned long int' => ':ulong',
|
29
|
+
'long unsigned int' => ':ulong',
|
30
|
+
'long long' => ':long_long',
|
31
|
+
'long long int' => ':long_long',
|
32
|
+
'signed long long' => ':long_long',
|
33
|
+
'signed long long int' => ':long_long',
|
34
|
+
'unsigned long long' => ':ulong_long',
|
35
|
+
'unsigned long long int' => ':ulong_long',
|
36
|
+
'void' => ':void'
|
37
|
+
}
|
38
|
+
class << self
|
39
|
+
attr_reader :typedefs
|
40
|
+
def add_type(ctype, rtype)
|
41
|
+
@typedefs[ctype] = rtype
|
42
|
+
end
|
43
|
+
end
|
44
|
+
class Node
|
45
|
+
attr_reader :symname
|
46
|
+
def initialize(params = { })
|
47
|
+
params = { :indent => 0 }.merge(params)
|
48
|
+
@node, @indent = params[:node], params[:indent]
|
49
|
+
@indent_str = ' ' * @indent
|
50
|
+
@symname = get_attr('name')
|
51
|
+
end
|
52
|
+
def get_attr(name)
|
53
|
+
if @node
|
54
|
+
attr = (@node / "./attributelist/attribute[@name='#{name}']").first
|
55
|
+
attr['value'] if attr
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
class Type < Node
|
60
|
+
def initialize(params = { })
|
61
|
+
super
|
62
|
+
@statement = params[:statement] || get_statement
|
63
|
+
end
|
64
|
+
def to_s
|
65
|
+
get_type
|
66
|
+
end
|
67
|
+
private
|
68
|
+
def get_statement
|
69
|
+
get_attr('decl').to_s + get_attr('type').to_s if @node
|
70
|
+
end
|
71
|
+
def is_native?
|
72
|
+
Generator::TYPES.has_key?(@statement)
|
73
|
+
end
|
74
|
+
def is_pointer?
|
75
|
+
@statement[/^p\./] and not is_callback?
|
76
|
+
end
|
77
|
+
def is_enum?
|
78
|
+
@statement[/^enum/]
|
79
|
+
end
|
80
|
+
def is_array?
|
81
|
+
@statement and @statement[/\w+\(\d+\)/]
|
82
|
+
end
|
83
|
+
def is_struct?
|
84
|
+
@statement[/^struct/]
|
85
|
+
end
|
86
|
+
def is_union?
|
87
|
+
@statement[/^union/]
|
88
|
+
end
|
89
|
+
def is_constant?
|
90
|
+
@statement[/^q\(const\)/]
|
91
|
+
end
|
92
|
+
def is_callback?
|
93
|
+
@statement[/^p.f\(/]
|
94
|
+
end
|
95
|
+
def native
|
96
|
+
if is_native?
|
97
|
+
@statement = Generator::TYPES[@statement]
|
98
|
+
get_type
|
99
|
+
end
|
100
|
+
end
|
101
|
+
def constant
|
102
|
+
if is_constant?
|
103
|
+
@statement = @statement.scan(/^q\(const\)\.(.+)/).flatten[0]
|
104
|
+
get_type
|
105
|
+
end
|
106
|
+
end
|
107
|
+
def pointer
|
108
|
+
if is_pointer?
|
109
|
+
if @statement[/char/] and @statement.scan(/p\./).size == 1
|
110
|
+
@statement = ':string'
|
111
|
+
# @decl.gsub!(/p\./, '')
|
112
|
+
get_type
|
113
|
+
else
|
114
|
+
return ':pointer'
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|
118
|
+
def array
|
119
|
+
if is_array?
|
120
|
+
num = @statement.scan(/\w+\((\d+)\)/).flatten[0]
|
121
|
+
@statement.gsub!(/\w+\(\d+\)\./, '')
|
122
|
+
"[#{get_type}, #{num}]"
|
123
|
+
end
|
124
|
+
end
|
125
|
+
def struct
|
126
|
+
if is_struct?
|
127
|
+
@statement = Structure.camelcase(@statement.scan(/^struct\s(\w+)/).flatten[0])
|
128
|
+
get_type
|
129
|
+
end
|
130
|
+
end
|
131
|
+
def union
|
132
|
+
if is_union?
|
133
|
+
@statement = Union.camelcase(@statement.scan(/^union\s(\w+)/).flatten[0])
|
134
|
+
get_type
|
135
|
+
end
|
136
|
+
end
|
137
|
+
def enum
|
138
|
+
if is_enum?
|
139
|
+
@statement = Generator::TYPES['int']
|
140
|
+
get_type
|
141
|
+
end
|
142
|
+
end
|
143
|
+
def callback
|
144
|
+
Callback.new(:node => @node).to_s if is_callback?
|
145
|
+
end
|
146
|
+
def typedef
|
147
|
+
if Generator.typedefs.has_key?(@statement)
|
148
|
+
@statement = Generator.typedefs[@statement]
|
149
|
+
get_type
|
150
|
+
end
|
151
|
+
end
|
152
|
+
def get_type
|
153
|
+
constant || pointer || enum || typedef || native || struct || union || array || callback || "#{@statement}"
|
154
|
+
end
|
155
|
+
end
|
156
|
+
class Typedef < Type
|
157
|
+
attr_reader :symname, :statement
|
158
|
+
def initialize(params = { })
|
159
|
+
super
|
160
|
+
@symname = get_attr('name')
|
161
|
+
# @type = is_pointer? ? ':pointer' : get_attr('type')
|
162
|
+
# p @statement
|
163
|
+
end
|
164
|
+
end
|
165
|
+
class Constant < Node
|
166
|
+
def initialize(params = { })
|
167
|
+
super
|
168
|
+
@name, @value = get_attr('sym_name'), get_attr('value')
|
169
|
+
end
|
170
|
+
def to_s
|
171
|
+
@indent_str + "#{@name} = #{@value}"
|
172
|
+
end
|
173
|
+
end
|
174
|
+
class Enum < Node
|
175
|
+
def initialize(params = { })
|
176
|
+
super
|
177
|
+
eval_items
|
178
|
+
end
|
179
|
+
def to_s
|
180
|
+
@items.sort { |i1, i2| i1[1] <=> i2[1] }.inject("") do |result, item|
|
181
|
+
result << assignment_str(item[0], item[1]) << "\n"
|
182
|
+
end
|
183
|
+
end
|
184
|
+
private
|
185
|
+
def assignment_str(name, value)
|
186
|
+
@indent_str + "#{name} = #{value}"
|
187
|
+
end
|
188
|
+
def eval_expr(expr)
|
189
|
+
if expr.include?('+')
|
190
|
+
(@items[expr[/\w+/]].to_i + 1).to_s
|
191
|
+
else
|
192
|
+
0.to_s
|
193
|
+
end
|
194
|
+
end
|
195
|
+
def eval_items
|
196
|
+
@items = {}
|
197
|
+
get_items.each do |i|
|
198
|
+
node = Node.new(:node => i)
|
199
|
+
@items[node.get_attr('name')] = node.get_attr('enumvalueex') ? eval_expr(node.get_attr('enumvalueex')) : node.get_attr('enumvalue')
|
200
|
+
end
|
201
|
+
@items
|
202
|
+
end
|
203
|
+
def get_items
|
204
|
+
@node / './enumitem'
|
205
|
+
end
|
206
|
+
end
|
207
|
+
class Structure < Node
|
208
|
+
def self.camelcase(name)
|
209
|
+
name.gsub(/^\w|\_\w/).each {|c| c.upcase }.delete('_')
|
210
|
+
end
|
211
|
+
def initialize(params = { })
|
212
|
+
super
|
213
|
+
@name = self.class.camelcase(@symname)
|
214
|
+
end
|
215
|
+
def to_s
|
216
|
+
fields_str = fields.inject("") do |str, f|
|
217
|
+
str << @indent_str + ' ' * 9 << f.join(', ') << ",\n"
|
218
|
+
end
|
219
|
+
code = klass_string + @indent_str + " layout(\n" + fields_str.chomp.chomp(',') + "\n" + @indent_str + " )\n" + @indent_str + "end\n"
|
220
|
+
end
|
221
|
+
private
|
222
|
+
def klass_string
|
223
|
+
@indent_str + "class #{@name} < FFI::Struct\n"
|
224
|
+
end
|
225
|
+
def fields
|
226
|
+
(@node / 'cdecl').inject([]) do |array, field|
|
227
|
+
array << [":#{Node.new(:node => field).symname}", "#{Type.new(:node => field)}"]
|
228
|
+
end
|
229
|
+
end
|
230
|
+
end
|
231
|
+
class Union < Structure
|
232
|
+
private
|
233
|
+
def klass_string
|
234
|
+
@indent_str + "class #{@name} < FFI::Union\n"
|
235
|
+
end
|
236
|
+
end
|
237
|
+
class Function < Type
|
238
|
+
class Argument < Type
|
239
|
+
def to_s
|
240
|
+
get_attr('type') == 'void' ? nil : super
|
241
|
+
end
|
242
|
+
end
|
243
|
+
def initialize(params = { })
|
244
|
+
super
|
245
|
+
@type = get_attr('type')
|
246
|
+
end
|
247
|
+
def to_s
|
248
|
+
params = get_params(@node).inject([]) do |array, node|
|
249
|
+
array << Argument.new(:node => node).to_s
|
250
|
+
end.collect { |p| "#{p}" }
|
251
|
+
@indent_str + "attach_function :#{@symname}, [ #{params.join(', ')} ], #{get_rvalue}"
|
252
|
+
end
|
253
|
+
private
|
254
|
+
def get_params(node)
|
255
|
+
parmlist = node / './attributelist/parmlist/parm'
|
256
|
+
end
|
257
|
+
def get_rvalue
|
258
|
+
Type.new(:node => @node, :statement => @statement.scan(/^f\(.*\)\.(.+)/).flatten[0]).to_s
|
259
|
+
end
|
260
|
+
end
|
261
|
+
class Callback < Type
|
262
|
+
def to_s
|
263
|
+
params = get_params.inject([]) do |array, type|
|
264
|
+
array << (type == 'void' ? '' : Type.new(:statement => type).to_s)
|
265
|
+
end
|
266
|
+
@indent_str + "callback(:#{@symname}, [ #{params.join(', ')} ], #{get_rtype})"
|
267
|
+
end
|
268
|
+
private
|
269
|
+
def get_params
|
270
|
+
@statement.scan(/p.f\((.*)\)/).flatten[0].split(',')
|
271
|
+
end
|
272
|
+
def get_rtype
|
273
|
+
Type.new(:statement => @statement.scan(/\)\.(\w+)/).flatten[0]).to_s
|
274
|
+
end
|
275
|
+
end
|
276
|
+
class Parser
|
277
|
+
@indent = 2
|
278
|
+
class << self
|
279
|
+
def get_verbatim(node)
|
280
|
+
node.xpath("./attributelist/attribute[@name='code']").first['value']
|
281
|
+
end
|
282
|
+
def is_insert_runtime?(node)
|
283
|
+
section = node.xpath("./attributelist/attribute[@name='section']")
|
284
|
+
section.first['value'] == 'runtime' if section.first
|
285
|
+
end
|
286
|
+
def is_constant?(node)
|
287
|
+
node.name == 'constant'
|
288
|
+
end
|
289
|
+
def is_enum?(node)
|
290
|
+
node.name == 'enum'
|
291
|
+
end
|
292
|
+
def is_function_decl?(node)
|
293
|
+
node.name == 'cdecl' and (node / "./attributelist/attribute[@name='kind']").first['value'] == 'function'
|
294
|
+
end
|
295
|
+
def is_struct?(node)
|
296
|
+
node.name == 'class' and (node / "./attributelist/attribute[@name='kind']").first['value'] == 'struct'
|
297
|
+
end
|
298
|
+
def is_union?(node)
|
299
|
+
node.name == 'class' and (node / "./attributelist/attribute[@name='kind']").first['value'] == 'union'
|
300
|
+
end
|
301
|
+
def is_typedef?(node)
|
302
|
+
node.name == 'cdecl' and (node / "./attributelist/attribute[@name='kind']").first['value'] == 'typedef'
|
303
|
+
end
|
304
|
+
def is_callback?(node)
|
305
|
+
(node / "./attributelist/attribute[@name='decl']").first['value'] =~ /^p\.f\(/
|
306
|
+
end
|
307
|
+
def generate(node)
|
308
|
+
result = ""
|
309
|
+
node.traverse do |node|
|
310
|
+
if is_constant?(node)
|
311
|
+
result << Constant.new(:node => node, :indent => @indent).to_s << "\n"
|
312
|
+
elsif is_typedef?(node)
|
313
|
+
typedef = Typedef.new(:node => node)
|
314
|
+
Generator.add_type(typedef.symname, typedef.statement)
|
315
|
+
if is_callback?(node)
|
316
|
+
cb = Callback.new(:node => node, :indent => @indent).to_s << "\n"
|
317
|
+
Generator.add_type(typedef.symname, ":#{typedef.symname}")
|
318
|
+
result << cb.to_s
|
319
|
+
end
|
320
|
+
elsif is_enum?(node)
|
321
|
+
e = Enum.new(:node => node, :indent => @indent)
|
322
|
+
Generator.add_type(e.symname, Generator::TYPES['int'])
|
323
|
+
result << e.to_s << "\n"
|
324
|
+
elsif is_struct?(node)
|
325
|
+
s = Structure.new(:node => node, :indent => @indent)
|
326
|
+
Generator.add_type(s.symname, "struct #{s.symname}")
|
327
|
+
result << s.to_s
|
328
|
+
elsif is_union?(node)
|
329
|
+
s = Union.new(:node => node, :indent => @indent)
|
330
|
+
Generator.add_type(s.symname, "union #{s.symname}")
|
331
|
+
result << s.to_s
|
332
|
+
elsif is_function_decl?(node)
|
333
|
+
result << Function.new(:node => node, :indent => @indent).to_s << "\n"
|
334
|
+
elsif node.name == 'insert' and not is_insert_runtime?(node)
|
335
|
+
result << get_verbatim(node)
|
336
|
+
end
|
337
|
+
end
|
338
|
+
result
|
339
|
+
end
|
340
|
+
end
|
341
|
+
end
|
342
|
+
end
|
343
|
+
end
|
344
|
+
|