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.
@@ -16,7 +16,7 @@ class FFIGen
16
16
  writer.puts "}"
17
17
  end
18
18
  writer.puts "}", ""
19
- declarations.values.compact.uniq.each do |declaration|
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 @comment
130
- # TODO constant comments
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 @comment
93
+ writer.write_description @description
159
94
  unless @fields.empty?
160
95
  writer.puts "", "= Fields:"
161
96
  @fields.each do |field|
162
- writer.puts "#{field[:symbol]} ::"
163
- writer.write_description field[:comment], false, " (#{field[:type_data][:description]}) ", " "
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[:type_data][:jna_type]} #{field[:symbol]};"
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[:java_name] }.join(', ')})"
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[:type_data][:description]}] #{parameter[:java_name]} ", " "
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 [#{return_type_data[:description]}] ", " "
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[:type_data][:jna_type]} #{parameter[:java_name]}" }.join(', ')}"
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}\")", "#{return_type_data[:jna_type]} #{java_name}(#{jna_signature});", ""
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 Constant
164
+ class Define
238
165
  def write_java(writer)
239
- writer.puts "public static int #{@name.to_java_constant} = #{@value};", ""
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
@@ -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 '#{@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.values.compact.uniq.each do |declaration|
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 @comment
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 @comment
85
+ writer.write_description @description
150
86
  unless @fields.empty?
151
87
  writer.puts "", "= Fields:"
152
88
  @fields.each do |field|
153
- writer.puts "#{field[:symbol]} ::"
154
- writer.write_description field[:comment], false, " (#{field[:type_data][:description]}) ", " "
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 << { symbol: ":dummy", type_data: { ffi_type: ":char" } } if @fields.empty?
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, return_type_declaration), index|
165
- parameter_names = function.parameters[1..-1].map { |parameter| !parameter[:name].empty? ? parameter[:name].to_ruby_downcase : "arg#{function.parameters.index(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 = return_type_declaration ? "#{return_type_declaration.ruby_name}.new " : ""
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
- "#{field[:symbol]}, #{field[:type_data][:ffi_type]}"
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[:ruby_name] }.join(', ')})"
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[:type_data][:description]}] #{parameter[:ruby_name]} ", " "
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 [#{return_type_data[:description]}] ", " "
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[:type_data][:ffi_type] }.join(', ')}], #{return_type_data[:ffi_type]}"
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 Constant
180
+
181
+ class Define
247
182
  def write_ruby(writer)
248
- writer.puts "#{@name.to_ruby_constant} = #{@value}", ""
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
- end
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