ffi-swig-generator 0.2.1 → 0.3.0

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.
Files changed (89) hide show
  1. data/.hg/branch.cache +2 -0
  2. data/.hg/dirstate +0 -0
  3. data/.hg/store/00changelog.i +0 -0
  4. data/.hg/store/00manifest.i +0 -0
  5. data/.hg/store/data/.hgignore.i +0 -0
  6. data/.hg/store/data/.hgtags.i +0 -0
  7. data/.hg/store/data/_history.txt.i +0 -0
  8. data/.hg/store/data/_r_e_a_d_m_e.rdoc.i +0 -0
  9. data/.hg/store/data/_rakefile.i +0 -0
  10. data/.hg/store/data/cucumber.yml.i +0 -0
  11. data/.hg/store/data/examples/_rakefile.i +0 -0
  12. data/.hg/store/data/features/generate.feature.i +0 -0
  13. data/.hg/store/data/features/step__definitions/generate.rb.i +0 -0
  14. data/.hg/store/data/features/support/env.rb.i +0 -0
  15. data/.hg/store/data/features/support/results.rb.i +0 -0
  16. data/.hg/store/data/features/support/templates.rb.i +0 -0
  17. data/.hg/store/data/lib/ffi-swig-generator.rb.i +0 -0
  18. data/.hg/store/data/lib/generator/application.rb.i +0 -0
  19. data/.hg/store/data/lib/generator/constant.rb.i +0 -0
  20. data/.hg/store/data/lib/generator/enum.rb.i +0 -0
  21. data/.hg/store/data/lib/generator/function.rb.i +0 -0
  22. data/.hg/store/data/lib/generator/generator.rb.i +0 -0
  23. data/.hg/store/data/lib/generator/generatortask.rb.i +0 -0
  24. data/.hg/store/data/lib/generator/logger.rb.i +0 -0
  25. data/.hg/store/data/lib/generator/node.rb.i +0 -0
  26. data/.hg/store/data/lib/generator/parser.rb.i +0 -0
  27. data/.hg/store/data/lib/generator/struct.rb.i +0 -0
  28. data/.hg/store/data/lib/generator/type.rb.i +0 -0
  29. data/.hg/store/data/lib/generator/types.rb.i +0 -0
  30. data/.hg/store/data/spec/generator/constant__spec.rb.i +0 -0
  31. data/.hg/store/data/spec/generator/enum__spec.rb.i +0 -0
  32. data/.hg/store/data/spec/generator/function__spec.rb.i +0 -0
  33. data/.hg/store/data/spec/generator/generator__spec.rb.i +0 -0
  34. data/.hg/store/data/spec/generator/node__spec.rb.i +0 -0
  35. data/.hg/store/data/spec/generator/parser__spec.rb.i +0 -0
  36. data/.hg/store/data/spec/generator/struct__spec.rb.i +0 -0
  37. data/.hg/store/data/spec/generator/swig/constants.i.i +0 -0
  38. data/.hg/store/data/spec/generator/swig/functions.i.i +0 -0
  39. data/.hg/store/data/spec/generator/swig/testlib.i.i +0 -0
  40. data/.hg/store/data/spec/generator/swig/typedefs.i.i +0 -0
  41. data/.hg/store/data/spec/generator/swig/types.i.i +0 -0
  42. data/.hg/store/data/spec/generator/type__spec.rb.i +0 -0
  43. data/.hg/store/data/spec/spec__helper.rb.i +0 -0
  44. data/.hg/store/data/tasks/cucumber.rake.i +0 -0
  45. data/.hg/store/undo +0 -0
  46. data/.hg/undo.dirstate +0 -0
  47. data/.hgignore +3 -0
  48. data/.hgtags +1 -0
  49. data/History.txt +22 -2
  50. data/README.rdoc +26 -22
  51. data/Rakefile +2 -3
  52. data/cucumber.yml +1 -0
  53. data/examples/Rakefile +5 -3
  54. data/examples/generated/libc_wrap.rb +18 -0
  55. data/examples/generated/libc_wrap.xml +597 -0
  56. data/examples/generated/wiiuse_wrap.rb +322 -0
  57. data/examples/generated/wiiuse_wrap.xml +9025 -0
  58. data/features/generate.feature +45 -0
  59. data/features/step_definitions/generate.rb +32 -0
  60. data/features/support/env.rb +4 -0
  61. data/features/support/templates.rb +381 -0
  62. data/lib/ffi-swig-generator.rb +1 -1
  63. data/lib/generator/application.rb +1 -1
  64. data/lib/generator/constant.rb +24 -0
  65. data/lib/generator/enum.rb +38 -0
  66. data/lib/generator/function.rb +71 -0
  67. data/lib/generator/generatortask.rb +21 -9
  68. data/lib/generator/logger.rb +29 -0
  69. data/lib/generator/node.rb +19 -0
  70. data/lib/generator/parser.rb +168 -0
  71. data/lib/generator/struct.rb +76 -0
  72. data/lib/generator/type.rb +128 -0
  73. data/lib/generator/types.rb +36 -0
  74. data/spec/generator/constant_spec.rb +17 -0
  75. data/spec/generator/enum_spec.rb +29 -0
  76. data/spec/generator/function_spec.rb +66 -0
  77. data/spec/generator/parser_spec.rb +250 -0
  78. data/spec/generator/struct_spec.rb +77 -0
  79. data/spec/generator/swig/constants.i +5 -0
  80. data/spec/generator/swig/functions.i +8 -0
  81. data/spec/generator/swig/testlib.i +42 -0
  82. data/spec/generator/swig/typedefs.i +1 -0
  83. data/spec/generator/swig/types.i +1 -0
  84. data/spec/generator/type_spec.rb +38 -0
  85. data/spec/spec_helper.rb +6 -0
  86. data/tasks/cucumber.rake +8 -0
  87. metadata +58 -18
  88. data/lib/generator/generator.rb +0 -344
  89. data/spec/generator/generator_spec.rb +0 -248
@@ -0,0 +1,45 @@
1
+ Feature: Generate FFI glue code from SWIG interface.
2
+
3
+ In order to generate ruby-ffi glue code.
4
+ As a developer of ruby-ffi bindings.
5
+ I want the generator to automagically produce code for me.
6
+
7
+ Scenario: Generate code using default configuration
8
+ Given we are in a project directory
9
+ And the project directory is configured for the 'Scenario1'
10
+ When rake task 'ffi:generate' is invoked
11
+ Then rake task 'ffi:generate' succeeded
12
+ And the file 'generated/interface_wrap.rb' is created
13
+ And the file 'generated/interface_wrap.xml' is created
14
+ And the file 'generated/interface_wrap.rb' contains ffi glue code
15
+ And the tmp directory is removed
16
+
17
+ Scenario: Generate code using a configuration hash
18
+ Given we are in a project directory
19
+ And the project directory is configured for the 'Scenario2'
20
+ When rake task 'ffi:generate' is invoked
21
+ Then rake task 'ffi:generate' succeeded
22
+ And the file 'generated/interface_wrap.rb' is created
23
+ And the file 'generated/interface_wrap.xml' is created
24
+ And the file 'generated/interface_wrap.rb' contains ffi glue code
25
+ And the tmp directory is removed
26
+
27
+ Scenario: Generate code using a configuration block
28
+ Given we are in a project directory
29
+ And the project directory is configured for the 'Scenario3'
30
+ When rake task 'ffi:generate' is invoked
31
+ Then rake task 'ffi:generate' succeeded
32
+ And the file 'generated/interface_wrap.rb' is created
33
+ And the file 'generated/interface_wrap.xml' is created
34
+ And the file 'generated/interface_wrap.rb' contains ffi glue code
35
+ And the tmp directory is removed
36
+
37
+ Scenario: Generate code using a configuration file
38
+ Given we are in a project directory
39
+ And the project directory is configured for the 'Scenario4'
40
+ When rake task 'ffi:generate' is invoked
41
+ Then rake task 'ffi:generate' succeeded
42
+ And the file 'generated/interface_wrap.rb' is created
43
+ And the file 'generated/interface_wrap.xml' is created
44
+ And the file 'generated/interface_wrap.rb' contains ffi glue code
45
+ And the tmp directory is removed
@@ -0,0 +1,32 @@
1
+ Given /^we are in a project directory$/ do
2
+ FileUtils.mkdir_p('tmp')
3
+ Dir.chdir('tmp')
4
+ end
5
+
6
+ Given /^the project directory is configured for the '(.+)'$/ do |mod|
7
+ @scenario = eval(mod)
8
+ @scenario.generate
9
+ end
10
+
11
+ When /^rake task 'ffi:generate' is invoked$/ do
12
+ @output = `rake ffi:generate 2>&1`
13
+ @result = $?.success?
14
+ end
15
+
16
+ Then /^rake task 'ffi:generate' succeeded$/ do
17
+ @result.should be_true
18
+ end
19
+
20
+ Then /^the file '(.+)' is created/ do |fn|
21
+ File.exists?(fn).should be_true
22
+ end
23
+
24
+ Then /^the file '(.+)' contains ffi glue code$/ do |fn|
25
+ File.read(fn).should == @scenario.result_template
26
+ end
27
+
28
+ Then /^the tmp directory is removed$/ do
29
+ Dir.chdir('..')
30
+ FileUtils.rm_rf 'tmp'
31
+ File.exists?('tmp').should be_false
32
+ end
@@ -0,0 +1,4 @@
1
+ require 'rubygems'
2
+ require 'spec'
3
+
4
+ ROOT_PATH = File.expand_path(File.join(File.dirname(__FILE__), '../..'))
@@ -0,0 +1,381 @@
1
+ class Scenario1
2
+
3
+ class << self
4
+
5
+ def interface_dir
6
+ '.'
7
+ end
8
+
9
+ def create_file(fn, &blk)
10
+ File.open(fn, 'w') do |file|
11
+ yield file
12
+ end
13
+ end
14
+
15
+ def generate
16
+ FileUtils.mkdir interface_dir unless File.exists?(interface_dir)
17
+ create_file(File.join(interface_dir, 'interface.i')) { |file| file << interface_template }
18
+ create_file('Rakefile') { |file| file << rakefile_template }
19
+ end
20
+
21
+ def interface_template
22
+ <<-EOF
23
+ %module testlib
24
+
25
+ %{
26
+ module TestLib
27
+ extend FFI::Library
28
+ %}
29
+
30
+ #define CONST_1 0x10
31
+ #define CONST_2 0x20
32
+
33
+ typedef unsigned char byte;
34
+ typedef enum e_1 {
35
+ ENUM_1, ENUM_2, ENUM_3
36
+ } enum_t;
37
+
38
+ union union_t {
39
+ char c;
40
+ float f;
41
+ };
42
+
43
+ struct test_struct {
44
+ int i;
45
+ char c;
46
+ byte b;
47
+ };
48
+
49
+ struct CamelCaseStruct {
50
+ int i;
51
+ char c;
52
+ byte b;
53
+ };
54
+
55
+ typedef struct {
56
+ char c;
57
+ } test_struct_3;
58
+
59
+ typedef void (*cb)(char*, char*);
60
+ typedef void * (*cb_2)(char*, const char *);
61
+ typedef CamelCaseStruct (*cb_3)(char*, CamelCaseStruct);
62
+
63
+ struct test_struct_2 {
64
+ struct test_struct s;
65
+ CamelCaseStruct camel_case_struct;
66
+ test_struct_3 s_3;
67
+ enum_t e;
68
+ cb func;
69
+ union_t u;
70
+ cb callback;
71
+ void (*inline_callback)();
72
+ };
73
+
74
+ // struct with getter/setter method for strings and callbacks
75
+
76
+ struct _test_struct_4 {
77
+ char* string;
78
+ void (*inline_callback)();
79
+ };
80
+
81
+ struct test_struct_5 {
82
+ int i;
83
+ union {
84
+ struct {
85
+ int a;
86
+ int b;
87
+ } nested_struct_field_1;
88
+ struct {
89
+ int c;
90
+ int d;
91
+ } nested_struct_field_2;
92
+ struct {
93
+ int e;
94
+ int f;
95
+ } nested_struct_field_3;
96
+ union {
97
+ long l;
98
+ long long ll;
99
+ } union_field;
100
+ float f;
101
+ } big_union_field;
102
+ char c;
103
+ };
104
+
105
+ int get_int(struct test_struct* s);
106
+ char get_char(struct test_struct* s);
107
+ int func_with_enum(enum e_1 e);
108
+ int func_with_enum_2(enum_t e);
109
+ byte func_with_typedef();
110
+ %{
111
+ end
112
+ %}
113
+ EOF
114
+ end
115
+
116
+ def result_template
117
+ <<-EOF
118
+
119
+ module TestLib
120
+ extend FFI::Library
121
+ CONST_1 = 0x10
122
+ CONST_2 = 0x20
123
+ ENUM_1 = 0
124
+ ENUM_2 = 1
125
+ ENUM_3 = 2
126
+
127
+ class UnionT < FFI::Union
128
+ layout(
129
+ :c, :char,
130
+ :f, :float
131
+ )
132
+ end
133
+ class TestStruct < FFI::Struct
134
+ layout(
135
+ :i, :int,
136
+ :c, :char,
137
+ :b, :uchar
138
+ )
139
+ end
140
+ class CamelCaseStruct < FFI::Struct
141
+ layout(
142
+ :i, :int,
143
+ :c, :char,
144
+ :b, :uchar
145
+ )
146
+ end
147
+ class TestStruct3 < FFI::Struct
148
+ layout(
149
+ :c, :char
150
+ )
151
+ end
152
+ callback(:cb, [ :string, :string ], :void)
153
+ callback(:cb_2, [ :string, :string ], :pointer)
154
+ callback(:cb_3, [ :string, CamelCaseStruct ], CamelCaseStruct)
155
+ class TestStruct2 < FFI::Struct
156
+ layout(
157
+ :s, TestStruct,
158
+ :camel_case_struct, CamelCaseStruct,
159
+ :s_3, TestStruct3,
160
+ :e, :int,
161
+ :func, :cb,
162
+ :u, UnionT,
163
+ :callback, :cb,
164
+ :inline_callback, callback([ ], :void)
165
+ )
166
+ def func=(cb)
167
+ @func = cb
168
+ self[:func] = @func
169
+ end
170
+ def func
171
+ @func
172
+ end
173
+ def callback=(cb)
174
+ @callback = cb
175
+ self[:callback] = @callback
176
+ end
177
+ def callback
178
+ @callback
179
+ end
180
+ def inline_callback=(cb)
181
+ @inline_callback = cb
182
+ self[:inline_callback] = @inline_callback
183
+ end
184
+ def inline_callback
185
+ @inline_callback
186
+ end
187
+
188
+ end
189
+ class TestStruct4 < FFI::Struct
190
+ layout(
191
+ :string, :pointer,
192
+ :inline_callback, callback([ ], :void)
193
+ )
194
+ def string=(str)
195
+ @string = FFI::MemoryPointer.from_string(str)
196
+ self[:string] = @string
197
+ end
198
+ def string
199
+ @string.get_string(0)
200
+ end
201
+ def inline_callback=(cb)
202
+ @inline_callback = cb
203
+ self[:inline_callback] = @inline_callback
204
+ end
205
+ def inline_callback
206
+ @inline_callback
207
+ end
208
+
209
+ end
210
+ class TestStruct5BigUnionFieldNestedStructField1 < FFI::Struct
211
+ layout(
212
+ :a, :int,
213
+ :b, :int
214
+ )
215
+ end
216
+ class TestStruct5BigUnionFieldNestedStructField2 < FFI::Struct
217
+ layout(
218
+ :c, :int,
219
+ :d, :int
220
+ )
221
+ end
222
+ class TestStruct5BigUnionFieldNestedStructField3 < FFI::Struct
223
+ layout(
224
+ :e, :int,
225
+ :f, :int
226
+ )
227
+ end
228
+ class TestStruct5BigUnionFieldUnionField < FFI::Union
229
+ layout(
230
+ :l, :long,
231
+ :ll, :long_long
232
+ )
233
+ end
234
+ # FIXME: Nested structures are not correctly supported at the moment.
235
+ # Please check the order of the declarations in the structure below.
236
+ # class TestStruct5BigUnionField < FFI::Union
237
+ # layout(
238
+ # :f, :float,
239
+ # :union_field, TestStruct5BigUnionFieldUnionField,
240
+ # :nested_struct_field_3, TestStruct5BigUnionFieldNestedStructField3,
241
+ # :nested_struct_field_2, TestStruct5BigUnionFieldNestedStructField2,
242
+ # :nested_struct_field_1, TestStruct5BigUnionFieldNestedStructField1
243
+ # )
244
+ # end
245
+ # FIXME: Nested structures are not correctly supported at the moment.
246
+ # Please check the order of the declarations in the structure below.
247
+ # class TestStruct5 < FFI::Struct
248
+ # layout(
249
+ # :i, :int,
250
+ # :c, :char,
251
+ # :big_union_field, TestStruct5BigUnionField
252
+ # )
253
+ # end
254
+ attach_function :get_int, [ :pointer ], :int
255
+ attach_function :get_char, [ :pointer ], :char
256
+ attach_function :func_with_enum, [ :int ], :int
257
+ attach_function :func_with_enum_2, [ :int ], :int
258
+ attach_function :func_with_typedef, [ ], :uchar
259
+
260
+ end
261
+ EOF
262
+ end
263
+
264
+ def rakefile_template
265
+ <<-EOF
266
+ require '../lib/ffi-swig-generator'
267
+
268
+ FFI::Generator::Task.new
269
+ EOF
270
+ end
271
+
272
+ end
273
+
274
+ end
275
+
276
+ class Scenario2 < Scenario1
277
+
278
+ class << self
279
+
280
+ def interface_dir
281
+ 'interfaces'
282
+ end
283
+
284
+ def rakefile_template
285
+ <<-EOF
286
+ require 'rubygems'
287
+ require '../lib/ffi-swig-generator'
288
+
289
+ FFI::Generator::Task.new :input_fn => 'interfaces/*.i', :output_dir => 'generated/'
290
+
291
+ EOF
292
+ end
293
+
294
+ end
295
+
296
+ end
297
+
298
+ class Scenario3 < Scenario2
299
+
300
+ class << self
301
+
302
+ def rakefile_template
303
+ <<-EOF
304
+ require 'rubygems'
305
+ require '../lib/ffi-swig-generator'
306
+
307
+ FFI::Generator::Task.new do |task|
308
+ task.input_fn = 'interfaces/*.i'
309
+ task.output_dir = 'generated/'
310
+ end
311
+
312
+ EOF
313
+ end
314
+
315
+ end
316
+
317
+ end
318
+
319
+ class Scenario4 < Scenario3
320
+
321
+ class << self
322
+
323
+ def generate
324
+ super
325
+ create_file(File.join(interface_dir, 'interface.rb')) { |file| file << config_template }
326
+ end
327
+
328
+ def rakefile_template
329
+ <<-EOF
330
+ require 'rubygems'
331
+ require '../lib/ffi-swig-generator'
332
+
333
+ FFI::Generator::Task.new do |task|
334
+ task.input_fn = 'interfaces/*.i'
335
+ task.output_dir = 'generated/'
336
+ end
337
+
338
+ EOF
339
+ end
340
+
341
+ def interface_template
342
+ <<-EOF
343
+ %module my_interface
344
+
345
+ #define CONST_1 0xff1;
346
+ #define CONST_2 0Xff2;
347
+
348
+ typedef struct {
349
+ char a;
350
+ char b;
351
+ } my_struct_1;
352
+
353
+ typedef struct {
354
+ char c;
355
+ char d;
356
+ } my_struct_2;
357
+
358
+ EOF
359
+ end
360
+
361
+ def result_template
362
+ <<-EOF
363
+ CONST_1 = 0xff1
364
+ class MyStruct1 < FFI::Struct
365
+ layout(
366
+ :a, :char,
367
+ :b, :char
368
+ )
369
+ end
370
+ EOF
371
+ end
372
+
373
+ def config_template
374
+ <<-EOF
375
+ ignore 'my_struct_2', 'CONST_2'
376
+ EOF
377
+ end
378
+
379
+ end
380
+
381
+ end