ffi_gen 1.1.0 → 1.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/README.md +39 -36
- data/lib/ffi_gen.rb +486 -214
- data/lib/ffi_gen/clang.rb +2564 -342
- data/lib/ffi_gen/java_output.rb +163 -125
- data/lib/ffi_gen/ruby_output.rb +190 -139
- metadata +17 -20
data/lib/ffi_gen/java_output.rb
CHANGED
@@ -16,7 +16,7 @@ class FFIGen
|
|
16
16
|
writer.puts "}"
|
17
17
|
end
|
18
18
|
writer.puts "}", ""
|
19
|
-
declarations.
|
19
|
+
declarations.each do |declaration|
|
20
20
|
declaration.write_java writer
|
21
21
|
end
|
22
22
|
end
|
@@ -24,83 +24,6 @@ class FFIGen
|
|
24
24
|
writer.output
|
25
25
|
end
|
26
26
|
|
27
|
-
def to_java_type(full_type, is_array = false)
|
28
|
-
canonical_type = Clang.get_canonical_type full_type
|
29
|
-
data_array = case canonical_type[:kind]
|
30
|
-
when :void then ["void", "nil"]
|
31
|
-
when :bool then ["boolean", "Boolean"]
|
32
|
-
when :u_char then ["byte", "Integer"]
|
33
|
-
when :u_short then ["short", "Integer"]
|
34
|
-
when :u_int then ["int", "Integer"]
|
35
|
-
when :u_long then ["NativeLong", "Integer"]
|
36
|
-
when :u_long_long then ["long", "Integer"]
|
37
|
-
when :char_s, :s_char then ["byte", "Integer"]
|
38
|
-
when :short then ["short", "Integer"]
|
39
|
-
when :int then ["int", "Integer"]
|
40
|
-
when :long then ["NativeLong", "Integer"]
|
41
|
-
when :long_long then ["long", "Integer"]
|
42
|
-
when :float then ["float", "Float"]
|
43
|
-
when :double then ["double", "Float"]
|
44
|
-
when :pointer
|
45
|
-
if is_array
|
46
|
-
element_type = to_java_type Clang.get_pointee_type(canonical_type)
|
47
|
-
return { jna_type: "#{element_type[:jna_type]}[]", description: "Array of #{element_type[:description]}", parameter_name: element_type[:parameter_name] }
|
48
|
-
end
|
49
|
-
|
50
|
-
pointee_type = Clang.get_pointee_type canonical_type
|
51
|
-
result = nil
|
52
|
-
case pointee_type[:kind]
|
53
|
-
when :char_s
|
54
|
-
result = ["String", "String"]
|
55
|
-
when :record
|
56
|
-
pointee_declaration = @declarations[Clang.get_cursor_type(Clang.get_type_declaration(pointee_type))]
|
57
|
-
result = [pointee_declaration.java_name, pointee_declaration.java_name] if pointee_declaration and pointee_declaration.written
|
58
|
-
when :function_proto
|
59
|
-
declaration = @declarations[full_type]
|
60
|
-
result = [":#{declaration.java_name}", "Proc(_callback_#{declaration.java_name}_)"] if declaration
|
61
|
-
end
|
62
|
-
|
63
|
-
if result.nil?
|
64
|
-
pointer_depth = 0
|
65
|
-
pointer_target_name = ""
|
66
|
-
current_type = full_type
|
67
|
-
loop do
|
68
|
-
declaration = Clang.get_type_declaration current_type
|
69
|
-
pointer_target_name = Name.new self, Clang.get_cursor_spelling(declaration).to_s_and_dispose
|
70
|
-
break if not pointer_target_name.empty?
|
71
|
-
|
72
|
-
case current_type[:kind]
|
73
|
-
when :pointer
|
74
|
-
pointer_depth += 1
|
75
|
-
current_type = Clang.get_pointee_type current_type
|
76
|
-
when :unexposed
|
77
|
-
break
|
78
|
-
else
|
79
|
-
pointer_target_name = Name.new self, Clang.get_type_kind_spelling(current_type[:kind]).to_s_and_dispose
|
80
|
-
break
|
81
|
-
end
|
82
|
-
end
|
83
|
-
result = ["Pointer", "FFI::Pointer(#{'*' * pointer_depth}#{pointer_target_name.to_java_classname})", pointer_target_name]
|
84
|
-
end
|
85
|
-
|
86
|
-
result
|
87
|
-
when :record
|
88
|
-
declaration = @declarations[canonical_type]
|
89
|
-
declaration ? ["#{declaration.java_name}.by_value", declaration.java_name] : ["byte", "unknown"] # TODO
|
90
|
-
when :enum
|
91
|
-
declaration = @declarations[canonical_type]
|
92
|
-
declaration ? [declaration.java_name, "Symbol from _enum_#{declaration.java_name}_", declaration.name] : ["byte", "unknown"] # TODO
|
93
|
-
when :constant_array
|
94
|
-
element_type_data = to_java_type Clang.get_array_element_type(canonical_type)
|
95
|
-
size = Clang.get_array_size canonical_type
|
96
|
-
["[#{element_type_data[:jna_type]}, #{size}]", "Array<#{element_type_data[:description]}>"]
|
97
|
-
else
|
98
|
-
raise NotImplementedError, "No translation for values of type #{canonical_type[:kind]}"
|
99
|
-
end
|
100
|
-
|
101
|
-
{ jna_type: data_array[0], description: data_array[1], parameter_name: (data_array[2] || Name.new(self, data_array[1])).to_java_downcase }
|
102
|
-
end
|
103
|
-
|
104
27
|
class Name
|
105
28
|
JAVA_KEYWORDS = %w{abstract assert boolean break byte case catch char class const continue default do double else enum extends final finally float for goto if implements import instanceof int interface long native new package private protected public return short static strictfp super switch synchronized this throw throws transient try void volatile while}
|
106
29
|
|
@@ -117,17 +40,26 @@ class FFIGen
|
|
117
40
|
end
|
118
41
|
end
|
119
42
|
|
43
|
+
class Type
|
44
|
+
def java_description
|
45
|
+
java_name
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
120
49
|
class Enum
|
121
50
|
def write_java(writer)
|
51
|
+
return if @name.nil?
|
122
52
|
shorten_names
|
123
53
|
|
124
|
-
@constants.each do |constant|
|
125
|
-
constant[:symbol] = ":#{constant[:name].to_ruby_downcase}"
|
126
|
-
end
|
127
|
-
|
128
54
|
writer.comment do
|
129
|
-
writer.write_description @
|
130
|
-
|
55
|
+
writer.write_description @description
|
56
|
+
writer.puts "", "<em>This entry is only for documentation and no real method. The FFI::Enum can be accessed via #enum_type(:#{java_name}).</em>"
|
57
|
+
writer.puts "", "=== Options:"
|
58
|
+
@constants.each do |constant|
|
59
|
+
writer.puts "#{constant[:name].to_java_constant} ::"
|
60
|
+
writer.write_description constant[:comment], false, " ", " "
|
61
|
+
end
|
62
|
+
writer.puts "", "@method _enum_#{java_name}_", "@return [Symbol]", "@scope class"
|
131
63
|
end
|
132
64
|
|
133
65
|
writer.puts "public enum #{java_name} implements NativeEnum {"
|
@@ -145,22 +77,25 @@ class FFIGen
|
|
145
77
|
def java_name
|
146
78
|
@java_name ||= @name.to_java_classname
|
147
79
|
end
|
80
|
+
|
81
|
+
def java_jna_type
|
82
|
+
java_name
|
83
|
+
end
|
84
|
+
|
85
|
+
def java_description
|
86
|
+
"Symbol from _enum_#{java_name}_"
|
87
|
+
end
|
148
88
|
end
|
149
89
|
|
150
90
|
class StructOrUnion
|
151
91
|
def write_java(writer)
|
152
|
-
@fields.each do |field|
|
153
|
-
field[:symbol] = field[:name].to_java_downcase
|
154
|
-
field[:type_data] = @generator.to_java_type field[:type]
|
155
|
-
end
|
156
|
-
|
157
92
|
writer.comment do
|
158
|
-
writer.write_description @
|
93
|
+
writer.write_description @description
|
159
94
|
unless @fields.empty?
|
160
95
|
writer.puts "", "= Fields:"
|
161
96
|
@fields.each do |field|
|
162
|
-
writer.puts "
|
163
|
-
writer.write_description field[:comment], false, " (#{field[:
|
97
|
+
writer.puts ":#{field[:name].to_java_downcase} ::"
|
98
|
+
writer.write_description field[:comment], false, " (#{field[:type].java_description}) ", " "
|
164
99
|
end
|
165
100
|
end
|
166
101
|
end
|
@@ -168,7 +103,7 @@ class FFIGen
|
|
168
103
|
writer.puts "public static class #{java_name} extends #{@is_union ? 'Union' : (@fields.empty? ? 'PointerType' : 'Structure')} {"
|
169
104
|
writer.indent do
|
170
105
|
@fields.each do |field|
|
171
|
-
writer.puts "public #{field[:
|
106
|
+
writer.puts "public #{field[:type].java_jna_type} #{field[:symbol]};"
|
172
107
|
end
|
173
108
|
writer.puts "// hidden structure" if @fields.empty?
|
174
109
|
end
|
@@ -180,63 +115,166 @@ class FFIGen
|
|
180
115
|
def java_name
|
181
116
|
@java_name ||= @name.to_java_classname
|
182
117
|
end
|
118
|
+
|
119
|
+
def java_jna_type
|
120
|
+
@written ? java_name : "Pointer"
|
121
|
+
end
|
122
|
+
|
123
|
+
def java_description
|
124
|
+
@written ? java_name : "FFI::Pointer(*#{java_name})"
|
125
|
+
end
|
183
126
|
end
|
184
127
|
|
185
128
|
class FunctionOrCallback
|
186
129
|
def write_java(writer)
|
187
130
|
return if @is_callback # not yet supported
|
188
131
|
|
189
|
-
@parameters.each do |parameter|
|
190
|
-
parameter[:type_data] = @generator.to_java_type parameter[:type], parameter[:is_array]
|
191
|
-
parameter[:java_name] = !parameter[:name].empty? ? parameter[:name].to_java_downcase : parameter[:type_data][:parameter_name]
|
192
|
-
parameter[:description] = []
|
193
|
-
end
|
194
|
-
return_type_data = @generator.to_java_type @return_type
|
195
|
-
|
196
|
-
function_description = []
|
197
|
-
return_value_description = []
|
198
|
-
current_description = function_description
|
199
|
-
@comment.split("\n").map do |line|
|
200
|
-
line = writer.prepare_comment_line line
|
201
|
-
if line.gsub!(/\\param (.*?) /, '')
|
202
|
-
parameter = @parameters.find { |p| p[:name].raw == $1 }
|
203
|
-
if parameter
|
204
|
-
current_description = parameter[:description]
|
205
|
-
else
|
206
|
-
current_description << "#{$1}: "
|
207
|
-
end
|
208
|
-
end
|
209
|
-
current_description = return_value_description if line.gsub! '\\returns ', ''
|
210
|
-
current_description << line
|
211
|
-
end
|
212
|
-
|
213
132
|
writer.comment do
|
214
|
-
writer.write_description function_description
|
133
|
+
writer.write_description @function_description
|
215
134
|
writer.puts "", "<em>This entry is only for documentation and no real method.</em>" if @is_callback
|
216
|
-
writer.puts "", "@method #{@is_callback ? "_callback_#{java_name}_" : java_name}(#{@parameters.map{ |parameter| parameter[:
|
135
|
+
writer.puts "", "@method #{@is_callback ? "_callback_#{java_name}_" : java_name}(#{@parameters.map{ |parameter| parameter[:name].to_java_downcase }.join(', ')})"
|
217
136
|
@parameters.each do |parameter|
|
218
|
-
writer.write_description parameter[:description], false, "@param [#{parameter[:
|
137
|
+
writer.write_description parameter[:description], false, "@param [#{parameter[:type].java_description}] #{parameter[:name].to_java_downcase} ", " "
|
219
138
|
end
|
220
|
-
writer.write_description return_value_description, false, "@return [#{
|
139
|
+
writer.write_description @return_value_description, false, "@return [#{@return_type.java_description}] ", " "
|
221
140
|
writer.puts "@scope class"
|
222
141
|
end
|
223
142
|
|
224
|
-
jna_signature = "#{@parameters.map{ |parameter| "#{parameter[:
|
143
|
+
jna_signature = "#{@parameters.map{ |parameter| "#{parameter[:type].java_jna_type} #{parameter[:name].to_java_downcase}" }.join(', ')}"
|
225
144
|
if @is_callback
|
226
145
|
writer.puts "callback :#{java_name}, #{jna_signature}", ""
|
227
146
|
else
|
228
|
-
writer.puts "@NativeName(\"#{@name.raw}\")", "#{
|
147
|
+
writer.puts "@NativeName(\"#{@name.raw}\")", "#{@return_type.java_jna_type} #{java_name}(#{jna_signature});", ""
|
229
148
|
end
|
230
149
|
end
|
231
150
|
|
232
151
|
def java_name
|
233
152
|
@java_name ||= @name.to_java_downcase
|
234
153
|
end
|
154
|
+
|
155
|
+
def java_jna_type
|
156
|
+
java_name
|
157
|
+
end
|
158
|
+
|
159
|
+
def java_description
|
160
|
+
"Proc(_callback_#{java_name}_)"
|
161
|
+
end
|
235
162
|
end
|
236
163
|
|
237
|
-
class
|
164
|
+
class Define
|
238
165
|
def write_java(writer)
|
239
|
-
|
166
|
+
parts = @value.map { |v|
|
167
|
+
if v.is_a? Array
|
168
|
+
case v[0]
|
169
|
+
when :method then v[1].to_java_downcase
|
170
|
+
when :constant then v[1].to_java_constant
|
171
|
+
else raise ArgumentError
|
172
|
+
end
|
173
|
+
else
|
174
|
+
v
|
175
|
+
end
|
176
|
+
}
|
177
|
+
if @parameters
|
178
|
+
# not implemented
|
179
|
+
else
|
180
|
+
writer.puts "public static int #{@name.to_java_constant} = #{parts.join};", ""
|
181
|
+
end
|
182
|
+
end
|
183
|
+
end
|
184
|
+
|
185
|
+
class PrimitiveType
|
186
|
+
def java_name
|
187
|
+
case @clang_type
|
188
|
+
when :void
|
189
|
+
"nil"
|
190
|
+
when :bool
|
191
|
+
"Boolean"
|
192
|
+
when :u_char, :u_short, :u_int, :u_long, :u_long_long, :char_s, :s_char, :short, :int, :long, :long_long
|
193
|
+
"Integer"
|
194
|
+
when :float, :double
|
195
|
+
"Float"
|
196
|
+
end
|
197
|
+
end
|
198
|
+
|
199
|
+
def java_jna_type
|
200
|
+
case @clang_type
|
201
|
+
when :void then "void"
|
202
|
+
when :bool then "boolean"
|
203
|
+
when :u_char then "byte"
|
204
|
+
when :u_short then "short"
|
205
|
+
when :u_int then "int"
|
206
|
+
when :u_long then "NativeLong"
|
207
|
+
when :u_long_long then "long"
|
208
|
+
when :char_s, :s_char then "byte"
|
209
|
+
when :short then "short"
|
210
|
+
when :int then "int"
|
211
|
+
when :long then "NativeLong"
|
212
|
+
when :long_long then "long"
|
213
|
+
when :float then "float"
|
214
|
+
when :double then "double"
|
215
|
+
end
|
216
|
+
end
|
217
|
+
end
|
218
|
+
|
219
|
+
class StringType
|
220
|
+
def java_name
|
221
|
+
"String"
|
222
|
+
end
|
223
|
+
|
224
|
+
def java_jna_type
|
225
|
+
"String"
|
226
|
+
end
|
227
|
+
end
|
228
|
+
|
229
|
+
class ByValueType
|
230
|
+
def java_name
|
231
|
+
@inner_type.java_name
|
232
|
+
end
|
233
|
+
|
234
|
+
def java_jna_type
|
235
|
+
@inner_type.java_jna_type
|
236
|
+
end
|
237
|
+
end
|
238
|
+
|
239
|
+
class PointerType
|
240
|
+
def java_name
|
241
|
+
@pointee_name.to_java_downcase
|
242
|
+
end
|
243
|
+
|
244
|
+
def java_jna_type
|
245
|
+
"Pointer"
|
246
|
+
end
|
247
|
+
|
248
|
+
def java_description
|
249
|
+
"FFI::Pointer(#{'*' * @depth}#{@pointee_name ? @pointee_name.to_java_classname : ''})"
|
250
|
+
end
|
251
|
+
end
|
252
|
+
|
253
|
+
class ArrayType
|
254
|
+
def java_name
|
255
|
+
"array"
|
256
|
+
end
|
257
|
+
|
258
|
+
def java_jna_type
|
259
|
+
if @constant_size
|
260
|
+
raise
|
261
|
+
else
|
262
|
+
"#{@element_type.java_jna_type}[]"
|
263
|
+
end
|
264
|
+
end
|
265
|
+
|
266
|
+
def java_description
|
267
|
+
"Array of #{@element_type.java_description}"
|
268
|
+
end
|
269
|
+
end
|
270
|
+
|
271
|
+
class UnknownType
|
272
|
+
def java_name
|
273
|
+
"unknown"
|
274
|
+
end
|
275
|
+
|
276
|
+
def java_jna_type
|
277
|
+
"byte"
|
240
278
|
end
|
241
279
|
end
|
242
280
|
end
|
data/lib/ffi_gen/ruby_output.rb
CHANGED
@@ -5,116 +5,49 @@ class FFIGen
|
|
5
5
|
writer.indent do
|
6
6
|
writer.puts "extend FFI::Library"
|
7
7
|
writer.puts "ffi_lib_flags #{@ffi_lib_flags.map(&:inspect).join(', ')}" if @ffi_lib_flags
|
8
|
-
writer.puts "ffi_lib
|
8
|
+
writer.puts "ffi_lib #{@ffi_lib.inspect}", "" if @ffi_lib
|
9
9
|
writer.puts "def self.attach_function(name, *_)", " begin; super; rescue FFI::NotFoundError => e", " (class << self; self; end).class_eval { define_method(name) { |*_| raise e } }", " end", "end", ""
|
10
|
-
declarations.
|
10
|
+
declarations.each do |declaration|
|
11
11
|
declaration.write_ruby writer
|
12
12
|
end
|
13
13
|
end
|
14
14
|
writer.puts "end"
|
15
15
|
writer.output
|
16
16
|
end
|
17
|
-
|
18
|
-
def to_ruby_type(full_type)
|
19
|
-
canonical_type = Clang.get_canonical_type full_type
|
20
|
-
data_array = case canonical_type[:kind]
|
21
|
-
when :void then [":void", "nil"]
|
22
|
-
when :bool then [":bool", "Boolean"]
|
23
|
-
when :u_char then [":uchar", "Integer"]
|
24
|
-
when :u_short then [":ushort", "Integer"]
|
25
|
-
when :u_int then [":uint", "Integer"]
|
26
|
-
when :u_long then [":ulong", "Integer"]
|
27
|
-
when :u_long_long then [":ulong_long", "Integer"]
|
28
|
-
when :char_s, :s_char then [":char", "Integer"]
|
29
|
-
when :short then [":short", "Integer"]
|
30
|
-
when :int then [":int", "Integer"]
|
31
|
-
when :long then [":long", "Integer"]
|
32
|
-
when :long_long then [":long_long", "Integer"]
|
33
|
-
when :float then [":float", "Float"]
|
34
|
-
when :double then [":double", "Float"]
|
35
|
-
when :pointer
|
36
|
-
pointee_type = Clang.get_pointee_type canonical_type
|
37
|
-
result = nil
|
38
|
-
case pointee_type[:kind]
|
39
|
-
when :char_s
|
40
|
-
result = [":string", "String"]
|
41
|
-
when :record
|
42
|
-
pointee_declaration = @declarations[Clang.get_cursor_type(Clang.get_type_declaration(pointee_type))]
|
43
|
-
result = [pointee_declaration.ruby_name, pointee_declaration.ruby_name] if pointee_declaration and pointee_declaration.written
|
44
|
-
when :function_proto
|
45
|
-
declaration = @declarations[full_type]
|
46
|
-
result = [":#{declaration.ruby_name}", "Proc(_callback_#{declaration.ruby_name}_)"] if declaration
|
47
|
-
end
|
48
|
-
|
49
|
-
if result.nil?
|
50
|
-
pointer_depth = 0
|
51
|
-
pointer_target_name = ""
|
52
|
-
current_type = full_type
|
53
|
-
loop do
|
54
|
-
declaration = Clang.get_type_declaration current_type
|
55
|
-
pointer_target_name = Name.new self, Clang.get_cursor_spelling(declaration).to_s_and_dispose
|
56
|
-
break if not pointer_target_name.empty?
|
57
|
-
|
58
|
-
case current_type[:kind]
|
59
|
-
when :pointer
|
60
|
-
pointer_depth += 1
|
61
|
-
current_type = Clang.get_pointee_type current_type
|
62
|
-
when :unexposed
|
63
|
-
break
|
64
|
-
else
|
65
|
-
pointer_target_name = Name.new self, Clang.get_type_kind_spelling(current_type[:kind]).to_s_and_dispose
|
66
|
-
break
|
67
|
-
end
|
68
|
-
end
|
69
|
-
result = [":pointer", "FFI::Pointer(#{'*' * pointer_depth}#{pointer_target_name.to_ruby_classname})", pointer_target_name]
|
70
|
-
end
|
71
|
-
|
72
|
-
result
|
73
|
-
when :record
|
74
|
-
declaration = @declarations[canonical_type]
|
75
|
-
declaration ? ["#{declaration.ruby_name}.by_value", declaration.ruby_name] : [":char", "unknown"] # TODO
|
76
|
-
when :enum
|
77
|
-
declaration = @declarations[canonical_type]
|
78
|
-
declaration ? [":#{declaration.ruby_name}", "Symbol from _enum_#{declaration.ruby_name}_", declaration.name] : [":char", "unknown"] # TODO
|
79
|
-
when :constant_array
|
80
|
-
element_type_data = to_ruby_type Clang.get_array_element_type(canonical_type)
|
81
|
-
size = Clang.get_array_size canonical_type
|
82
|
-
["[#{element_type_data[:ffi_type]}, #{size}]", "Array<#{element_type_data[:description]}>"]
|
83
|
-
when :unexposed
|
84
|
-
[":char", "unexposed"]
|
85
|
-
else
|
86
|
-
raise NotImplementedError, "No translation for values of type #{canonical_type[:kind]}"
|
87
|
-
end
|
88
|
-
|
89
|
-
{ ffi_type: data_array[0], description: data_array[1], parameter_name: (data_array[2] || Name.new(self, data_array[1])).to_ruby_downcase }
|
90
|
-
end
|
91
|
-
|
17
|
+
|
92
18
|
class Name
|
93
19
|
RUBY_KEYWORDS = %w{alias and begin break case class def defined do else elsif end ensure false for if in module next nil not or redo rescue retry return self super then true undef unless until when while yield BEGIN END}
|
94
20
|
|
95
21
|
def to_ruby_downcase
|
96
22
|
format :downcase, :underscores, RUBY_KEYWORDS
|
97
23
|
end
|
98
|
-
|
24
|
+
|
99
25
|
def to_ruby_classname
|
100
26
|
format :camelcase, RUBY_KEYWORDS
|
101
27
|
end
|
102
|
-
|
28
|
+
|
103
29
|
def to_ruby_constant
|
104
30
|
format :upcase, :underscores, RUBY_KEYWORDS
|
105
31
|
end
|
106
32
|
end
|
107
|
-
|
33
|
+
|
34
|
+
class Type
|
35
|
+
def ruby_description
|
36
|
+
ruby_name
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
108
40
|
class Enum
|
109
41
|
def write_ruby(writer)
|
42
|
+
return if @name.nil?
|
110
43
|
shorten_names
|
111
|
-
|
44
|
+
|
112
45
|
@constants.each do |constant|
|
113
46
|
constant[:symbol] = ":#{constant[:name].to_ruby_downcase}"
|
114
47
|
end
|
115
|
-
|
48
|
+
|
116
49
|
writer.comment do
|
117
|
-
writer.write_description @
|
50
|
+
writer.write_description @description
|
118
51
|
writer.puts "", "<em>This entry is only for documentation and no real method. The FFI::Enum can be accessed via #enum_type(:#{ruby_name}).</em>"
|
119
52
|
writer.puts "", "=== Options:"
|
120
53
|
@constants.each do |constant|
|
@@ -123,7 +56,7 @@ class FFIGen
|
|
123
56
|
end
|
124
57
|
writer.puts "", "@method _enum_#{ruby_name}_", "@return [Symbol]", "@scope class"
|
125
58
|
end
|
126
|
-
|
59
|
+
|
127
60
|
writer.puts "enum :#{ruby_name}, ["
|
128
61
|
writer.indent do
|
129
62
|
writer.write_array @constants, "," do |constant|
|
@@ -132,41 +65,51 @@ class FFIGen
|
|
132
65
|
end
|
133
66
|
writer.puts "]", ""
|
134
67
|
end
|
135
|
-
|
68
|
+
|
136
69
|
def ruby_name
|
137
70
|
@ruby_name ||= @name.to_ruby_downcase
|
138
71
|
end
|
72
|
+
|
73
|
+
def ruby_ffi_type
|
74
|
+
":#{ruby_name}"
|
75
|
+
end
|
76
|
+
|
77
|
+
def ruby_description
|
78
|
+
"Symbol from _enum_#{ruby_name}_"
|
79
|
+
end
|
139
80
|
end
|
140
|
-
|
81
|
+
|
141
82
|
class StructOrUnion
|
142
83
|
def write_ruby(writer)
|
143
|
-
@fields.each do |field|
|
144
|
-
field[:symbol] = ":#{field[:name].to_ruby_downcase}"
|
145
|
-
field[:type_data] = @generator.to_ruby_type field[:type]
|
146
|
-
end
|
147
|
-
|
148
84
|
writer.comment do
|
149
|
-
writer.write_description @
|
85
|
+
writer.write_description @description
|
150
86
|
unless @fields.empty?
|
151
87
|
writer.puts "", "= Fields:"
|
152
88
|
@fields.each do |field|
|
153
|
-
writer.puts "
|
154
|
-
writer.write_description field[:comment], false, " (#{field[:
|
89
|
+
writer.puts ":#{field[:name].to_ruby_downcase} ::"
|
90
|
+
writer.write_description field[:comment], false, " (#{field[:type].ruby_description}) ", " "
|
155
91
|
end
|
156
92
|
end
|
157
93
|
end
|
158
|
-
|
159
|
-
@fields << {
|
94
|
+
|
95
|
+
@fields << { name: Name.new(["dummy"]), type: PrimitiveType.new(:char_s) } if @fields.empty?
|
160
96
|
|
161
97
|
unless @oo_functions.empty?
|
162
98
|
writer.puts "module #{ruby_name}Wrappers"
|
163
99
|
writer.indent do
|
164
|
-
@oo_functions.each_with_index do |(name, function
|
165
|
-
parameter_names = function.parameters[1..-1].map { |parameter|
|
100
|
+
@oo_functions.each_with_index do |(name, function), index|
|
101
|
+
parameter_names = function.parameters[1..-1].map { |parameter| parameter[:name].to_ruby_downcase }
|
166
102
|
writer.puts "" unless index == 0
|
103
|
+
writer.comment do
|
104
|
+
function.parameters[1..-1].each do |parameter|
|
105
|
+
writer.write_description parameter[:description], false, "@param [#{parameter[:type].ruby_description}] #{parameter[:name].to_ruby_downcase} ", " "
|
106
|
+
end
|
107
|
+
return_type = function.return_type.is_a?(StructOrUnion) ? function.return_type.ruby_name : function.return_type.ruby_description
|
108
|
+
writer.write_description function.return_value_description, false, "@return [#{return_type}] ", " "
|
109
|
+
end
|
167
110
|
writer.puts "def #{name.to_ruby_downcase}(#{parameter_names.join(', ')})"
|
168
111
|
writer.indent do
|
169
|
-
cast =
|
112
|
+
cast = function.return_type.is_a?(StructOrUnion) ? "#{function.return_type.ruby_name}.new " : ""
|
170
113
|
writer.puts "#{cast}#{@generator.module_name}.#{function.ruby_name}(#{(["self"] + parameter_names).join(', ')})"
|
171
114
|
end
|
172
115
|
writer.puts "end"
|
@@ -174,78 +117,186 @@ class FFIGen
|
|
174
117
|
end
|
175
118
|
writer.puts "end", ""
|
176
119
|
end
|
177
|
-
|
120
|
+
|
178
121
|
writer.puts "class #{ruby_name} < #{@is_union ? 'FFI::Union' : 'FFI::Struct'}"
|
179
122
|
writer.indent do
|
180
123
|
writer.puts "include #{ruby_name}Wrappers" unless @oo_functions.empty?
|
181
124
|
writer.write_array @fields, ",", "layout ", " " do |field|
|
182
|
-
"
|
125
|
+
":#{field[:name].to_ruby_downcase}, #{field[:type].ruby_ffi_type}"
|
183
126
|
end
|
184
127
|
end
|
185
128
|
writer.puts "end", ""
|
186
|
-
|
129
|
+
|
187
130
|
@written = true
|
188
131
|
end
|
189
|
-
|
132
|
+
|
190
133
|
def ruby_name
|
191
134
|
@ruby_name ||= @name.to_ruby_classname
|
192
135
|
end
|
136
|
+
|
137
|
+
def ruby_ffi_type
|
138
|
+
@written ? ruby_name : ":pointer"
|
139
|
+
end
|
140
|
+
|
141
|
+
def ruby_description
|
142
|
+
@written ? ruby_name : "FFI::Pointer(*#{ruby_name})"
|
143
|
+
end
|
193
144
|
end
|
194
|
-
|
145
|
+
|
195
146
|
class FunctionOrCallback
|
196
147
|
def write_ruby(writer)
|
197
|
-
@parameters.each do |parameter|
|
198
|
-
parameter[:type_data] = @generator.to_ruby_type parameter[:type]
|
199
|
-
parameter[:ruby_name] = !parameter[:name].empty? ? parameter[:name].to_ruby_downcase : parameter[:type_data][:parameter_name]
|
200
|
-
parameter[:description] = []
|
201
|
-
end
|
202
|
-
return_type_data = @generator.to_ruby_type @return_type
|
203
|
-
|
204
|
-
function_description = []
|
205
|
-
return_value_description = []
|
206
|
-
current_description = function_description
|
207
|
-
@comment.split("\n").map do |line|
|
208
|
-
line = writer.prepare_comment_line line
|
209
|
-
if line.gsub!(/\\param (.*?) /, '')
|
210
|
-
parameter = @parameters.find { |p| p[:name].raw == $1 }
|
211
|
-
if parameter
|
212
|
-
current_description = parameter[:description]
|
213
|
-
else
|
214
|
-
current_description << "#{$1}: "
|
215
|
-
end
|
216
|
-
end
|
217
|
-
current_description = return_value_description if line.gsub! '\\returns ', ''
|
218
|
-
current_description << line
|
219
|
-
end
|
220
|
-
|
221
148
|
writer.puts "@blocking = true" if @blocking
|
222
149
|
writer.comment do
|
223
|
-
writer.write_description function_description
|
150
|
+
writer.write_description @function_description
|
224
151
|
writer.puts "", "<em>This entry is only for documentation and no real method.</em>" if @is_callback
|
225
|
-
writer.puts "", "@method #{@is_callback ? "_callback_#{ruby_name}_" : ruby_name}(#{@parameters.map{ |parameter| parameter[:
|
152
|
+
writer.puts "", "@method #{@is_callback ? "_callback_#{ruby_name}_" : ruby_name}(#{@parameters.map{ |parameter| parameter[:name].to_ruby_downcase }.join(', ')})"
|
226
153
|
@parameters.each do |parameter|
|
227
|
-
writer.write_description parameter[:description], false, "@param [#{parameter[:
|
154
|
+
writer.write_description parameter[:description], false, "@param [#{parameter[:type].ruby_description}] #{parameter[:name].to_ruby_downcase} ", " "
|
228
155
|
end
|
229
|
-
writer.write_description return_value_description, false, "@return [#{
|
156
|
+
writer.write_description @return_value_description, false, "@return [#{@return_type.ruby_description}] ", " "
|
230
157
|
writer.puts "@scope class"
|
231
158
|
end
|
232
|
-
|
233
|
-
ffi_signature = "[#{@parameters.map{ |parameter| parameter[:
|
159
|
+
|
160
|
+
ffi_signature = "[#{@parameters.map{ |parameter| parameter[:type].ruby_ffi_type }.join(', ')}], #{@return_type.ruby_ffi_type}"
|
234
161
|
if @is_callback
|
235
162
|
writer.puts "callback :#{ruby_name}, #{ffi_signature}", ""
|
236
163
|
else
|
237
164
|
writer.puts "attach_function :#{ruby_name}, :#{@name.raw}, #{ffi_signature}", ""
|
238
165
|
end
|
239
166
|
end
|
240
|
-
|
167
|
+
|
241
168
|
def ruby_name
|
242
169
|
@ruby_name ||= @name.to_ruby_downcase
|
243
170
|
end
|
171
|
+
|
172
|
+
def ruby_ffi_type
|
173
|
+
":#{ruby_name}"
|
174
|
+
end
|
175
|
+
|
176
|
+
def ruby_description
|
177
|
+
"Proc(_callback_#{ruby_name}_)"
|
178
|
+
end
|
244
179
|
end
|
245
|
-
|
246
|
-
class
|
180
|
+
|
181
|
+
class Define
|
247
182
|
def write_ruby(writer)
|
248
|
-
|
183
|
+
parts = @value.map { |v|
|
184
|
+
if v.is_a? Array
|
185
|
+
case v[0]
|
186
|
+
when :method then v[1].to_ruby_downcase
|
187
|
+
when :constant then v[1].to_ruby_constant
|
188
|
+
else raise ArgumentError
|
189
|
+
end
|
190
|
+
else
|
191
|
+
v
|
192
|
+
end
|
193
|
+
}
|
194
|
+
if @parameters
|
195
|
+
writer.puts "def #{@name.to_ruby_downcase}(#{@parameters.join(", ")})"
|
196
|
+
writer.indent do
|
197
|
+
writer.puts parts.join
|
198
|
+
end
|
199
|
+
writer.puts "end", ""
|
200
|
+
else
|
201
|
+
writer.puts "#{@name.to_ruby_constant} = #{parts.join}", ""
|
202
|
+
end
|
203
|
+
end
|
204
|
+
end
|
205
|
+
|
206
|
+
class PrimitiveType
|
207
|
+
def ruby_name
|
208
|
+
case @clang_type
|
209
|
+
when :void
|
210
|
+
"nil"
|
211
|
+
when :bool
|
212
|
+
"Boolean"
|
213
|
+
when :u_char, :u_short, :u_int, :u_long, :u_long_long, :char_s, :s_char, :short, :int, :long, :long_long
|
214
|
+
"Integer"
|
215
|
+
when :float, :double
|
216
|
+
"Float"
|
217
|
+
end
|
218
|
+
end
|
219
|
+
|
220
|
+
def ruby_ffi_type
|
221
|
+
case @clang_type
|
222
|
+
when :void then ":void"
|
223
|
+
when :bool then ":bool"
|
224
|
+
when :u_char then ":uchar"
|
225
|
+
when :u_short then ":ushort"
|
226
|
+
when :u_int then ":uint"
|
227
|
+
when :u_long then ":ulong"
|
228
|
+
when :u_long_long then ":ulong_long"
|
229
|
+
when :char_s, :s_char then ":char"
|
230
|
+
when :short then ":short"
|
231
|
+
when :int then ":int"
|
232
|
+
when :long then ":long"
|
233
|
+
when :long_long then ":long_long"
|
234
|
+
when :float then ":float"
|
235
|
+
when :double then ":double"
|
236
|
+
end
|
237
|
+
end
|
238
|
+
end
|
239
|
+
|
240
|
+
class StringType
|
241
|
+
def ruby_name
|
242
|
+
"String"
|
243
|
+
end
|
244
|
+
|
245
|
+
def ruby_ffi_type
|
246
|
+
":string"
|
247
|
+
end
|
248
|
+
end
|
249
|
+
|
250
|
+
class ByValueType
|
251
|
+
def ruby_name
|
252
|
+
@inner_type.ruby_name
|
253
|
+
end
|
254
|
+
|
255
|
+
def ruby_ffi_type
|
256
|
+
"#{@inner_type.ruby_ffi_type}.by_value"
|
249
257
|
end
|
250
258
|
end
|
251
|
-
|
259
|
+
|
260
|
+
class PointerType
|
261
|
+
def ruby_name
|
262
|
+
@pointee_name.to_ruby_downcase
|
263
|
+
end
|
264
|
+
|
265
|
+
def ruby_ffi_type
|
266
|
+
":pointer"
|
267
|
+
end
|
268
|
+
|
269
|
+
def ruby_description
|
270
|
+
"FFI::Pointer(#{'*' * @depth}#{@pointee_name ? @pointee_name.to_ruby_classname : ''})"
|
271
|
+
end
|
272
|
+
end
|
273
|
+
|
274
|
+
class ArrayType
|
275
|
+
def ruby_name
|
276
|
+
"array"
|
277
|
+
end
|
278
|
+
|
279
|
+
def ruby_ffi_type
|
280
|
+
if @constant_size
|
281
|
+
"[#{@element_type.ruby_ffi_type}, #{@constant_size}]"
|
282
|
+
else
|
283
|
+
":pointer"
|
284
|
+
end
|
285
|
+
end
|
286
|
+
|
287
|
+
def ruby_description
|
288
|
+
"Array<#{@element_type.ruby_description}>"
|
289
|
+
end
|
290
|
+
end
|
291
|
+
|
292
|
+
class UnknownType
|
293
|
+
def ruby_name
|
294
|
+
"unknown"
|
295
|
+
end
|
296
|
+
|
297
|
+
def ruby_ffi_type
|
298
|
+
":char"
|
299
|
+
end
|
300
|
+
end
|
301
|
+
|
302
|
+
end
|