rbind 0.0.16 → 0.0.17

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 (54) hide show
  1. data/lib/rbind.rb +1 -0
  2. data/lib/rbind/clang/clang.rb +3699 -0
  3. data/lib/rbind/clang/clang_types.rb +327 -0
  4. data/lib/rbind/clang_parser.rb +451 -0
  5. data/lib/rbind/core.rb +7 -4
  6. data/lib/rbind/core/rattribute.rb +17 -21
  7. data/lib/rbind/core/rbase.rb +98 -64
  8. data/lib/rbind/core/rcallback.rb +15 -0
  9. data/lib/rbind/core/rclass.rb +79 -16
  10. data/lib/rbind/core/rdata_type.rb +40 -39
  11. data/lib/rbind/core/renum.rb +18 -0
  12. data/lib/rbind/core/rnamespace.rb +189 -52
  13. data/lib/rbind/core/roperation.rb +52 -20
  14. data/lib/rbind/core/rparameter.rb +43 -8
  15. data/lib/rbind/core/rpointer.rb +70 -0
  16. data/lib/rbind/core/rreference.rb +54 -0
  17. data/lib/rbind/core/rtemplate_class.rb +49 -0
  18. data/lib/rbind/core/rtype_qualifier.rb +60 -0
  19. data/lib/rbind/default_parser.rb +48 -36
  20. data/lib/rbind/generator_c.rb +2 -2
  21. data/lib/rbind/generator_extern.rb +1 -3
  22. data/lib/rbind/generator_ruby.rb +201 -47
  23. data/lib/rbind/logger.rb +3 -0
  24. data/lib/rbind/rbind.rb +25 -9
  25. data/lib/rbind/templates/c/CMakeLists.txt +6 -6
  26. data/lib/rbind/templates/ruby/rbind.rb +1 -1
  27. data/lib/rbind/templates/ruby/rmethod.rb +4 -1
  28. data/lib/rbind/templates/ruby/rnamespace.rb +2 -1
  29. data/lib/rbind/templates/ruby/roverloaded_method.rb +3 -1
  30. data/lib/rbind/templates/ruby/roverloaded_method_call.rb +1 -0
  31. data/lib/rbind/templates/ruby/roverloaded_static_method.rb +3 -2
  32. data/lib/rbind/templates/ruby/rstatic_method.rb +4 -1
  33. data/lib/rbind/templates/ruby/rtype.rb +19 -16
  34. data/lib/rbind/templates/ruby/rtype_template.rb +7 -0
  35. data/lib/rbind/{core/rstring.rb → types/std_string.rb} +8 -8
  36. data/lib/rbind/types/std_vector.rb +100 -0
  37. data/rbind.gemspec +2 -2
  38. data/test/headers/cfunctions.h +7 -0
  39. data/test/headers/classes.hpp +29 -0
  40. data/test/headers/constants.hpp +14 -0
  41. data/test/headers/enums.hpp +22 -0
  42. data/test/headers/std_string.hpp +26 -0
  43. data/test/headers/std_vector.hpp +31 -0
  44. data/test/headers/structs.hpp +34 -0
  45. data/test/headers/templates.hpp +20 -0
  46. data/test/test_clang_parser.rb +146 -0
  47. data/test/test_generator_ruby.rb +0 -5
  48. data/test/test_roperation.rb +144 -0
  49. data/test/test_rparameter.rb +88 -0
  50. metadata +24 -7
  51. data/lib/rbind/core/.roperation.rb.swp +0 -0
  52. data/lib/rbind/core/rconst.rb +0 -35
  53. data/lib/rbind/core/rstruct.rb +0 -87
  54. data/lib/rbind/core/rvector.rb +0 -27
@@ -85,7 +85,7 @@ module Rbind
85
85
  @root.each_container do |type|
86
86
  str2 = ""
87
87
  type.each_const(false) do |c|
88
- str2 += "#{c.csignature};\n"
88
+ str2 += "#{c.signature};\n"
89
89
  end
90
90
  if !str2.empty?
91
91
  str += "\n\n//constants for #{type.full_name}\n"
@@ -169,7 +169,7 @@ module Rbind
169
169
  def wrap_parameters
170
170
  cparameters.map do |arg|
171
171
  next if arg.type.basic_type?
172
- "#{"const " if arg.read_only?}#{arg.type.full_name} *#{arg.name}_ = fromC(#{arg.name});\n\t"
172
+ "#{arg.type.to_single_ptr.signature} #{arg.name}_ = fromC(#{arg.name});\n\t"
173
173
  end.compact.join("")
174
174
  end
175
175
 
@@ -8,7 +8,7 @@ module Rbind
8
8
  attr_accessor :ruby_module_name
9
9
  attr_accessor :file_prefix
10
10
  def self.normalize_type_name(name)
11
- name.gsub('::','.')
11
+ name.gsub('::','.').gsub(" ","")
12
12
  end
13
13
 
14
14
  def initialize(root)
@@ -26,8 +26,6 @@ module Rbind
26
26
  @root.each_type do |t|
27
27
  if t.is_a? RClass
28
28
  file_extern.write "class #{GeneratorExtern.normalize_type_name(t.full_name)} /Extern\n"
29
- elsif t.is_a? RStruct
30
- file_extern.write "struct #{GeneratorExtern.normalize_type_name(t.full_name)} /Extern\n"
31
29
  end
32
30
  end
33
31
 
@@ -1,6 +1,7 @@
1
1
  require 'fileutils'
2
2
  require 'delegate'
3
3
  require 'erb'
4
+ require 'open-uri'
4
5
 
5
6
  module Rbind
6
7
  class GeneratorRuby
@@ -10,13 +11,23 @@ module Rbind
10
11
  attr_accessor :ffi_type_map
11
12
  end
12
13
  self.ruby_default_value_map ||= {"true" => "true","TRUE" => "true", "false" => "false","FALSE" => "false"}
13
- self.ffi_type_map ||= {"char *" => "string","unsigned char" => "uchar" ,"const char *" => "string" }
14
+ self.ffi_type_map ||= {"char *" => "string","unsigned char" => "uchar" ,"const char *" => "string","uint8_t" => "uint8" }
14
15
 
15
16
 
16
17
  def self.keyword?(name)
17
18
  %w{__FILE__ __LINE__ alias and begin BEGIN break case class def defined? do else elsif end 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}.include? name
18
19
  end
19
20
 
21
+ def self.normalize_doc(str)
22
+ return nil if !str || str.empty?
23
+ s = str
24
+ str = str.gsub(/\$\$(.*)\$\$/m) do
25
+ "![equation](http://latex.codecogs.com/gif.latex?#{URI::encode($1.to_s)})"
26
+ end
27
+ str = str.gsub(/^ *#?/,"# ")
28
+ "#{str.chomp}\n"
29
+ end
30
+
20
31
  def self.on_normalize_type_name(&block)
21
32
  self.on_normalize_type_name = block
22
33
  end
@@ -49,7 +60,8 @@ module Rbind
49
60
  normalize_type_name(parameter.default_value)
50
61
  end
51
62
  else
52
- if(parameter.default_value =~ /([\w:]*) *\((.*)\)/)
63
+ if(parameter.default_value =~ /([\w:<>]*) *\((.*)\)/)
64
+ value = $2
53
65
  t = parameter.owner.owner.type($1,false)
54
66
  ops = Array(parameter.owner.owner.operation($1,false)) if !t
55
67
  t,ops = if t || !ops.empty?
@@ -65,14 +77,14 @@ module Rbind
65
77
  [nil,nil]
66
78
  end
67
79
  end
68
- if ops && !ops.empty?
80
+ s = if ops && !ops.empty?
69
81
  if t
70
- "#{normalize_type_name(t.full_name)}::#{normalize_method_name(ops.first.name)}(#{($2)})"
82
+ "#{normalize_type_name(t.full_name)}::#{normalize_method_name(ops.first.name)}(#{(value)})"
71
83
  else
72
- "#{normalize_method_name(ops.first.name)}(#{($2)})"
84
+ "#{normalize_method_name(ops.first.name)}(#{(value)})"
73
85
  end
74
86
  elsif t
75
- "#{normalize_type_name(t.full_name)}.new(#{($2)})"
87
+ "#{normalize_type_name(t.full_name)}.new(#{(value)})"
76
88
  end
77
89
  else
78
90
  parameter.default_value
@@ -87,15 +99,27 @@ module Rbind
87
99
 
88
100
 
89
101
  def self.normalize_type_name(name)
102
+ name = name.gsub(" ","")
103
+
104
+ # map template classes
105
+ # std::vector<std::string> -> Std::Vector::Std_String
106
+ if name =~ /([\w:]*)<(.*)>$/
107
+ return "#{normalize_type_name($1)}::#{normalize_type_name($2).gsub("::","_")}"
108
+ else
109
+ name
110
+ end
111
+
90
112
  # custom normalization
91
113
  if @on_normalize_type_name
92
114
  n = @on_normalize_type_name.call(name)
93
115
  return n if n
94
116
  end
95
117
 
118
+ # map all uint ... to Fixnum
96
119
  if name =~ /^u?int\d*$/ || name =~ /^u?int\d+_t$/
97
120
  return "Fixnum"
98
121
  end
122
+
99
123
  name = name.gsub(/^_/,"")
100
124
  names = name.split("::").map do |n|
101
125
  n.gsub(/^(\w)(.*)/) do
@@ -106,7 +130,8 @@ module Rbind
106
130
  if n == n.upcase
107
131
  return names.join("::")
108
132
  end
109
- names.join("::").split("_").map do |n|
133
+
134
+ name = names.join("::").split("_").map do |n|
110
135
  n.gsub(/^(\w)(.*)/) do
111
136
  $1.upcase+$2
112
137
  end
@@ -123,24 +148,10 @@ module Rbind
123
148
  end
124
149
  end
125
150
 
126
- # normalize c method to meet ruby conventions
127
- # see unit tests
128
- def self.normalize_method_name(orig_name)
129
- #remove cprefix and replaced _X with #X
130
- name = orig_name.to_s.gsub(/\A#{RBase.cprefix}/, "") .gsub(/_((?<!\A)\p{Lu})/u, '#\1')
131
- #replaced X with _x
132
- name = name.gsub(/(?<!\A)[\p{Lu}\d]/u, '_\0').downcase
133
- #replaced _x_ with #x#
134
- name = name.to_s.gsub(/[_#]([a-zA-Z\d])[_#]/u, '#\1#')
135
- #replaced _x$ with #x
136
- name = name.to_s.gsub(/[_#]([a-zA-Z\d])$/u, '#\1')
137
- #replaced ## with _
138
- name = name.gsub(/##/, '_')
139
- #replace #xx with _xx
140
- name = name.gsub(/#([a-zA-Z\d]{2})/, '_\1')
141
- #remove all remaining #
142
- name = name.gsub(/#/, '')
143
- #replace operatorX with the correct ruby operator
151
+ def self.normalize_alias_method_name(orig_name)
152
+ name = orig_name
153
+ #replace operatorX with the correct ruby operator when
154
+ #there are overloaded operators
144
155
  name = if name =~/^operator(.*)/
145
156
  n = $1
146
157
  if n =~ /\(\)/
@@ -165,6 +176,26 @@ module Rbind
165
176
  else
166
177
  name
167
178
  end
179
+ end
180
+
181
+ # normalize c method to meet ruby conventions
182
+ # see unit tests
183
+ def self.normalize_method_name(orig_name)
184
+ #remove cprefix and replaced _X with #X
185
+ name = orig_name.to_s.gsub(/\A#{RBase.cprefix}/, "") .gsub(/_((?<!\A)\p{Lu})/u, '#\1')
186
+ #replaced X with _x
187
+ name = name.gsub(/(?<!\A)[\p{Lu}\d]/u, '_\0').downcase
188
+ #replaced _x_ with #x#
189
+ name = name.to_s.gsub(/[_#]([a-zA-Z\d])[_#]/u, '#\1#')
190
+ #replaced _x$ with #x
191
+ name = name.to_s.gsub(/[_#]([a-zA-Z\d])$/u, '#\1')
192
+ #replaced ## with _
193
+ name = name.gsub(/##/, '_')
194
+ #replace #xx with _xx
195
+ name = name.gsub(/#([a-zA-Z\d]{2})/, '_\1')
196
+ #remove all remaining #
197
+ name = name.gsub(/#/, '')
198
+ name = normalize_alias_method_name(name)
168
199
  raise "generated empty name for #{orig_name}" if name.empty?
169
200
  name
170
201
  end
@@ -231,37 +262,46 @@ module Rbind
231
262
  str += "\n#methods for #{t.full_name}\n"
232
263
  if t.cdelete_method
233
264
  str += "attach_function :#{normalize_m t.cdelete_method},"\
234
- ":#{t.cdelete_method},[#{normalize_t t.full_name}],:void\n"
265
+ ":#{t.cdelete_method},[#{normalize_t(t.full_name)}],:void\n"
235
266
  str += "attach_function :#{normalize_m t.cdelete_method}_struct,"\
236
- ":#{t.cdelete_method},[#{normalize_t t.full_name}Struct],:void\n"
267
+ ":#{t.cdelete_method},[#{normalize_t(t.full_name)}Struct],:void\n"
237
268
  end
238
269
  t.each_operation do |op|
239
270
  return_type = if op.constructor?
240
271
  "#{normalize_t op.owner.full_name}"
241
272
  else
242
273
  if op.return_type.basic_type?
243
- ":#{normalize_bt op.return_type.csignature}"
274
+ if op.return_type.ptr?
275
+ ":pointer"
276
+ else
277
+ ":#{normalize_bt op.return_type.to_raw.csignature}"
278
+ end
244
279
  else
245
280
  if op.return_type.extern_package_name
246
- normalize_t("::#{op.return_type.extern_package_name}::#{op.return_type.full_name}")
281
+ normalize_t("::#{op.return_type.extern_package_name}::#{op.return_type.to_raw.full_name}")
247
282
  else
248
- normalize_t op.return_type.full_name
283
+ normalize_t op.return_type.to_raw.full_name
249
284
  end
250
285
  end
251
286
  end
252
287
  args = op.cparameters.map do |p|
253
288
  if p.type.basic_type?
254
- ":#{normalize_bt p.type.csignature}"
289
+ if p.type.ptr?
290
+ ":pointer"
291
+ else
292
+ ":#{normalize_bt p.type.to_raw.csignature}"
293
+ end
255
294
  else
256
295
  if p.type.extern_package_name
257
- normalize_t("::#{p.type.extern_package_name}::#{p.type.full_name}")
296
+ normalize_t("::#{p.type.extern_package_name}::#{p.type.to_raw.full_name}")
258
297
  else
259
- normalize_t p.type.full_name
298
+ normalize_t p.type.to_raw.full_name
260
299
  end
261
300
  end
262
301
  end
263
302
  fct_name = normalize_m op.cname
264
303
  str += "attach_function :#{fct_name},:#{op.cname},[#{args.join(",")}],#{return_type}\n"
304
+ str
265
305
  end
266
306
  str+"\n"
267
307
  end
@@ -270,6 +310,37 @@ module Rbind
270
310
  end
271
311
  end
272
312
 
313
+ class RTypeTemplateHelper < HelperBase
314
+ def initialize(name, root,compact_namespace = false)
315
+ @type_template_wrapper = ERB.new(File.open(File.join(File.dirname(__FILE__),"templates","ruby","rtype_template.rb")).read,nil,"-")
316
+ super(name,root)
317
+ end
318
+
319
+ def name
320
+ GeneratorRuby.normalize_type_name(@name)
321
+ end
322
+
323
+ def cname
324
+ GeneratorRuby.normalize_type_name(@root.cname)
325
+ end
326
+
327
+ def add_doc
328
+ str = GeneratorRuby::normalize_doc(@root.doc)
329
+ end
330
+
331
+ def add_specializing(root = @root)
332
+ root.specialize_ruby
333
+ end
334
+
335
+ def result
336
+ return "" if @root.extern?
337
+ str = @type_template_wrapper.result(self.binding)
338
+ str.gsub!("\n","\n ").gsub!(" \n","\n")
339
+ " "+str[0,str.size-4]
340
+ end
341
+ end
342
+
343
+
273
344
  class RTypeHelper < HelperBase
274
345
  class OperationHelper < SimpleDelegator
275
346
  def min_number_of_parameters
@@ -283,7 +354,7 @@ module Rbind
283
354
 
284
355
  def signature_default_values
285
356
  str = parameters.map do |p|
286
- if p.default_value
357
+ if p.default_value
287
358
  GeneratorRuby.normalize_default_value p
288
359
  else
289
360
  "nil"
@@ -334,6 +405,49 @@ module Rbind
334
405
  GeneratorRuby.normalize_method_name(__getobj__.cname)
335
406
  end
336
407
 
408
+ def add_alias
409
+ name = if auto_alias
410
+ __getobj__.name
411
+ else
412
+ __getobj__.alias || __getobj__.name
413
+ end
414
+ name = GeneratorRuby::normalize_alias_method_name(name)
415
+ if name == self.name || !cplusplus_alias?
416
+ nil
417
+ elsif static?
418
+ " class << self; alias :#{name} :#{self.name}; end\n"
419
+ else
420
+ " alias :#{name} :#{self.name}\n"
421
+ end
422
+ end
423
+
424
+ def add_specialize_ruby
425
+ str = specialize_ruby
426
+ " #{str}\n" if str
427
+ end
428
+
429
+ def generate_param_doc
430
+ paras = parameters.map do |p|
431
+ n = GeneratorRuby.normalize_arg_name p.name
432
+ t = GeneratorRuby.normalize_type_name(p.type.full_name)
433
+ "# @param [#{t}] #{n} #{p.doc}"
434
+ end
435
+ if return_type
436
+ t = GeneratorRuby.normalize_type_name(return_type.full_name)
437
+ paras << "# @return [#{t}]"
438
+ end
439
+ paras.join("\n")+"\n"
440
+ end
441
+
442
+ def add_doc
443
+ str = GeneratorRuby::normalize_doc(doc)
444
+ str = if !parameters.empty? || return_type
445
+ str += "#\n" if str
446
+ "#{str}#{generate_param_doc}"
447
+ end
448
+ str.gsub(/^/," ") if str
449
+ end
450
+
337
451
  def binding
338
452
  Kernel.binding
339
453
  end
@@ -359,6 +473,28 @@ module Rbind
359
473
  end.join("\n")
360
474
  end
361
475
 
476
+ def add_alias
477
+ name = GeneratorRuby::normalize_alias_method_name(@root.first.alias || @root.first.name)
478
+ if name == self.name || !@root.first.cplusplus_alias?
479
+ nil
480
+ elsif static?
481
+ " class << self; alias :#{name} :#{self.name}; end\n"
482
+ else
483
+ " alias #{name} #{self.name}\n"
484
+ end
485
+ end
486
+
487
+ def add_doc
488
+ str = @root.map do |op|
489
+ s = op.add_doc
490
+ s ||= ""
491
+ s = s.gsub(/( *#)/) do
492
+ "#{$1} "
493
+ end
494
+ " # @overload #{op.name}(#{op.wrap_parameters_signature})\n#{s}"
495
+ end.join(" #\n")
496
+ end
497
+
362
498
  def binding
363
499
  Kernel.binding
364
500
  end
@@ -367,7 +503,7 @@ module Rbind
367
503
  def initialize(name, root,compact_namespace = false)
368
504
  @type_wrapper = ERB.new(File.open(File.join(File.dirname(__FILE__),"templates","ruby","rtype.rb")).read,nil,"-")
369
505
  @namespace_wrapper = ERB.new(File.open(File.join(File.dirname(__FILE__),"templates","ruby","rnamespace.rb")).read,nil,"-")
370
- @static_method_wrapper = ERB.new(File.open(File.join(File.dirname(__FILE__),"templates","ruby","rstatic_method.rb")).read)
506
+ @static_method_wrapper = ERB.new(File.open(File.join(File.dirname(__FILE__),"templates","ruby","rstatic_method.rb")).read,nil,"-")
371
507
  @method_wrapper = ERB.new(File.open(File.join(File.dirname(__FILE__),"templates","ruby","rmethod.rb")).read,nil,'-')
372
508
  @overloaded_method_wrapper = ERB.new(File.open(File.join(File.dirname(__FILE__),"templates","ruby","roverloaded_method.rb")).read,nil,"-")
373
509
  @overloaded_static_method_wrapper = ERB.new(File.open(File.join(File.dirname(__FILE__),"templates","ruby","roverloaded_static_method.rb")).read,nil,"-")
@@ -389,11 +525,7 @@ module Rbind
389
525
  end
390
526
 
391
527
  def add_specializing(root = @root)
392
- str = if @root.respond_to?(:specialize_ruby)
393
- root.specialize_ruby
394
- else
395
- ""
396
- end
528
+ str = root.specialize_ruby.to_s
397
529
  root.each_type(false) do |t|
398
530
  next if t.basic_type? && !t.is_a?(RNamespace)
399
531
  str += add_specialize(t) if name == GeneratorRuby.normalize_type_name(t.full_name)
@@ -411,10 +543,25 @@ module Rbind
411
543
  end.join("\n")
412
544
  end
413
545
 
546
+ def add_constructor_doc
547
+ ops = Array(@root.operation(@root.name,false))
548
+ ops = ops.map do |c|
549
+ next if c.ignore?
550
+ OperationHelper.new(c)
551
+ end.compact
552
+ if ops.empty?
553
+ nil
554
+ elsif ops.size == 1
555
+ ops.first.add_doc
556
+ else
557
+ OverloadedOperationHelper.new(ops).add_doc
558
+ end
559
+ end
560
+
414
561
  def add_consts(root=@root)
415
562
  str = @root.consts.map do |c|
416
563
  next if c.extern? || c.ignore?
417
- " #{c.name} = #{GeneratorRuby::normalize_type_name(c.value)}\n"
564
+ " #{c.name} = #{GeneratorRuby::normalize_type_name(c.default_value)}\n"
418
565
  end.join
419
566
  return str unless @compact_namespace
420
567
 
@@ -478,13 +625,16 @@ module Rbind
478
625
 
479
626
  def add_types(root = @root)
480
627
  str = ""
481
- root.each_type(false) do |t|
628
+ root.each_type(false,true) do |t|
629
+ next if t.ignore? || t.extern?
482
630
  next if t.basic_type? && !t.is_a?(RNamespace)
483
631
  str += if @compact_namespace && name == GeneratorRuby.normalize_type_name(t.full_name)
484
- add_types(t)
485
- else
486
- RTypeHelper.new(t.name,t).result
487
- end
632
+ add_types(t)
633
+ elsif t.template?
634
+ RTypeTemplateHelper.new(t.name,t).result
635
+ else
636
+ RTypeHelper.new(t.name,t).result
637
+ end
488
638
  end
489
639
  str
490
640
  end
@@ -493,9 +643,13 @@ module Rbind
493
643
  @root.full_name
494
644
  end
495
645
 
646
+ def add_doc
647
+ GeneratorRuby::normalize_doc(@root.doc)
648
+ end
649
+
496
650
  def result
497
651
  return "" if @root.extern?
498
- str = if @root.is_a? RStruct
652
+ str = if @root.is_a? RClass
499
653
  @type_wrapper.result(self.binding)
500
654
  else
501
655
  @namespace_wrapper.result(self.binding)
@@ -8,6 +8,9 @@ module Rbind
8
8
  o.log = ::Logger.new(STDOUT)
9
9
  o.log.level = ::Logger::INFO
10
10
  o.log.progname = o.name
11
+ o.log.formatter = proc do |severity, datetime, progname, msg|
12
+ "#{progname}: #{msg}\n"
13
+ end
11
14
  end
12
15
  end
13
16
  extend ::Rbind::Logger