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
@@ -6,36 +6,19 @@ module Rbind
6
6
  attr_accessor :invalid_value
7
7
  attr_accessor :cdelete_method
8
8
  attr_accessor :check_type
9
- attr_accessor :extern_package_name
10
9
 
11
- def initialize(name,*flags)
10
+ def initialize(name)
12
11
  super
13
12
  @invalid_value = 0
14
13
  @check_type = true
15
14
  end
16
15
 
17
- def extern?
18
- @flags.include? :Extern
19
- end
20
-
21
- def valid_flags
22
- super << :Extern
23
- end
24
-
25
16
  def ==(other)
26
- other.name == name && other.ptr == ptr
27
- end
28
-
29
- def generate_signatures
30
- if ref?
31
- ["#{full_name} &","#{cname} &"]
32
- elsif ptr?
33
- ["#{full_name} *","#{cname} *"]
34
- else
35
- super
36
- end
17
+ other.generate_signatures[0] == generate_signatures[0]
37
18
  end
38
19
 
20
+ # indicates of the type shall be checked before
21
+ # casting
39
22
  def check_type?
40
23
  @check_type
41
24
  end
@@ -63,42 +46,60 @@ module Rbind
63
46
  !!@typedef
64
47
  end
65
48
 
49
+ def template?
50
+ false
51
+ end
52
+
66
53
  # elementar type of c
67
54
  def basic_type?
68
55
  true
69
56
  end
70
57
 
71
- # holds ofther operations, types or consts
58
+ # holds other operations, types or consts
72
59
  def container?
73
60
  false
74
61
  end
75
62
 
76
- def to_value
77
- owner.type(name)
63
+ def to_raw
64
+ self
65
+ end
66
+
67
+ def to_single_ptr
68
+ t = to_raw
69
+ t = t.to_const if const?
70
+ t.to_ptr
78
71
  end
79
72
 
80
73
  def to_ptr
81
- return self if ptr? && !ref?
82
- t = self.dup
83
- t.ref = false
84
- t.ptr = true
85
- t
86
- end
87
-
88
- def delete!
89
- if @owner
90
- @owner.delete_type self.name
91
- else
92
- raise "#{self} has no owner."
93
- end
74
+ RPointer.new(self)
75
+ end
76
+
77
+ def to_ref
78
+ RReference.new(self)
79
+ end
80
+
81
+ def to_const
82
+ RTypeQualifier.new(self,:const => true)
83
+ end
84
+
85
+ def remove_const
86
+ self
87
+ end
88
+
89
+ def raw?
90
+ true
91
+ end
92
+
93
+ def const?
94
+ false
94
95
  end
95
96
 
96
97
  def ptr?
97
- !!ptr
98
+ false
98
99
  end
99
100
 
100
101
  def ref?
101
- !!ref
102
+ false
102
103
  end
103
104
  end
104
105
  end
@@ -1,5 +1,23 @@
1
1
 
2
2
  module Rbind
3
3
  class REnum < RDataType
4
+ attr_accessor :values
5
+
6
+ def initialize(name)
7
+ super(name)
8
+ @values = Hash.new
9
+ end
10
+
11
+ def generate_signatures
12
+ ["#{full_name} = #{values}","const #{cname} = #{values}"]
13
+ end
14
+
15
+ def basic_type?
16
+ true
17
+ end
18
+
19
+ def add_value(name,val)
20
+ @values[name] = val
21
+ end
4
22
  end
5
23
  end
@@ -1,26 +1,58 @@
1
+ require 'hooks'
1
2
 
2
3
  module Rbind
3
4
  class RNamespace< RDataType
5
+ include Hooks
6
+ define_hook :on_type_not_found
7
+ define_hook :on_type_look_up
8
+ define_hook :on_add_type
9
+ define_hook :on_add_operation
10
+ define_hook :on_add_const
11
+
4
12
  class << self
5
13
  attr_accessor :default_type_names
14
+ attr_accessor :default_type_alias
6
15
  end
7
- self.default_type_names = [:int,:int8,:int32,:int64,:uint,:uint8,:uint32,:uint64,:int8_t,:int32_t,:int64_t,:uint8_t,:uint32_t,:uint64_t,:bool,:double,:float,:void,:char,:size_t]
16
+ # TODO move somewhere else
17
+ self.default_type_names = [:int,:int8,:int32,:int64,:uint,:uint8,:uint32,:uint64,
18
+ :int8_t,:int32_t,:int64_t,:uint8_t,:uint32_t,:uint64_t,
19
+ :bool,:double,:float,:void,:char,:size_t,:long,
20
+ :uchar, :char16, :char32, :ushort, :ulong, :ulong_long,
21
+ :uint128, :short, :long_long, :int128, :long_double,
22
+ :c_string,:constant_array]
23
+ self.default_type_alias= { :u_char => :uchar, :u_short => :ushort, :u_long => :ulong,
24
+ :u_long_long => :ulong_long,:u_int => :uint, :uint128 => :uint128,
25
+ :char_s => :char}
8
26
 
9
27
  attr_reader :operations
10
28
  attr_reader :operation_alias
11
29
  attr_reader :consts
12
30
  attr_reader :used_namespaces
13
- attr_accessor :root
14
- attr_accessor :types_alias
31
+ attr_reader :type_alias
32
+ attr_reader :root
15
33
 
16
- def initialize(name,*flags)
34
+ def initialize(name=nil,root = nil)
17
35
  @consts = Hash.new
18
36
  @types = Hash.new
19
- @types_alias = Hash.new
37
+ @type_alias = Hash.new
20
38
  @operations = Hash.new{|hash,key| hash[key] = Array.new}
21
39
  @operation_alias = Hash.new{|hash,key| hash[key] = Array.new}
22
- @used_namespaces = Hash.new
23
- super(name,*flags)
40
+ @used_namespaces = Array.new
41
+ name ||= begin
42
+ @root = true
43
+ "root"
44
+ end
45
+ if root
46
+ #share varaibales accross root namesapces
47
+ raise "#{root} is not a root namespace" unless root.root?
48
+ @consts = root.instance_variable_get(:@consts)
49
+ @types = root.instance_variable_get(:@types)
50
+ @type_alias = root.instance_variable_get(:@type_alias)
51
+ @operations = root.instance_variable_get(:@operations)
52
+ @operation_alias =root.instance_variable_get(:@operation_alias)
53
+ @used_namespaces = root.instance_variable_get(:@used_namespaces)
54
+ end
55
+ super(name)
24
56
  end
25
57
 
26
58
  def root?
@@ -45,13 +77,23 @@ module Rbind
45
77
  end
46
78
 
47
79
  def use_namespace(namespace)
48
- @used_namespaces[namespace.name] = namespace
80
+ # Check if there is another root embedded
81
+ # and add the corresponding namespace.
82
+ # This is needed to support multiple roots providing
83
+ # types to the same namespace
84
+ @used_namespaces.each do |ns|
85
+ next unless ns.root?
86
+ if (ns2 = ns.type(namespace.full_name,false))
87
+ @used_namespaces << ns2 if ns.object_id != namespace.object_id
88
+ end
89
+ end
90
+ @used_namespaces << namespace
49
91
  end
50
92
 
51
93
  def each_type(childs=true,all=false,&block)
52
94
  if block_given?
53
95
  types.each do |t|
54
- next if !all && (t.ignore? || t.extern?)
96
+ next if !all && (t.ignore? || t.extern? || t.template?)
55
97
  yield t
56
98
  t.each_type(childs,all,&block) if childs && t.respond_to?(:each_type)
57
99
  end
@@ -60,8 +102,8 @@ module Rbind
60
102
  end
61
103
  end
62
104
 
63
- def each_container(all=false,&block)
64
- each_type(true,all) do |t|
105
+ def each_container(childs=true,all=false,&block)
106
+ each_type(childs,all) do |t|
65
107
  next unless t.container?
66
108
  yield t
67
109
  end
@@ -81,7 +123,7 @@ module Rbind
81
123
  end
82
124
  end
83
125
  c ||= begin
84
- used_namespaces.values.each do |ns|
126
+ used_namespaces.each do |ns|
85
127
  c = ns.const(name,false,false)
86
128
  break if c
87
129
  end
@@ -91,6 +133,7 @@ module Rbind
91
133
  owner.const(name,false)
92
134
  end
93
135
  raise RuntimeError,"#{full_name} has no const called #{name}" if raise_ && !c
136
+ c
94
137
  end
95
138
 
96
139
  def each_const(childs=true,all=false,&block)
@@ -100,7 +143,7 @@ module Rbind
100
143
  yield c
101
144
  end
102
145
  return unless childs
103
- each_container(all) do |t|
146
+ each_container(false,all) do |t|
104
147
  t.each_const(childs,all,&block)
105
148
  end
106
149
  else
@@ -109,7 +152,7 @@ module Rbind
109
152
  end
110
153
 
111
154
  def extern?
112
- return super() if self.is_a?(RStruct)
155
+ return super if self.is_a? RClass
113
156
 
114
157
  # check if self is container holding only
115
158
  # extern objects
@@ -122,7 +165,6 @@ module Rbind
122
165
  each_operation do |t|
123
166
  return false
124
167
  end
125
- true
126
168
  end
127
169
 
128
170
  def each_operation(all=false,&block)
@@ -162,9 +204,15 @@ module Rbind
162
204
  !!operation(name,false)
163
205
  end
164
206
 
165
- def add_operation(op)
166
- op.owner = self
207
+ def add_operation(op,&block)
208
+ if op.is_a? String
209
+ op = ROperation.new(op,void)
210
+ op.owner = self
211
+ instance_exec(op,&block) if block
212
+ return add_operation(op)
213
+ end
167
214
 
215
+ op.owner = self
168
216
  # make sure there is no name clash
169
217
  other = @operations[op.name].find do |o|
170
218
  o.cname == op.cname
@@ -190,8 +238,9 @@ module Rbind
190
238
  op
191
239
  end
192
240
 
193
- def add_namespace(namespace)
194
- names = namespace.split("::")
241
+ # TODO rename to add_namespace_name
242
+ def add_namespace(namespace_name)
243
+ names = namespace_name.split("::")
195
244
  current_type = self
196
245
  while !names.empty?
197
246
  name = names.shift
@@ -207,8 +256,14 @@ module Rbind
207
256
  end
208
257
 
209
258
  def add_const(const)
210
- if const(const.full_name,false,false)
211
- raise ArgumentError,"#A const with the name #{const.full_name} already exists"
259
+ const.const!
260
+ if(c = const(const.full_name,false,false))
261
+ if c.type.full_name == const.type.full_name && c.default_value == const.default_value
262
+ ::Rbind.log.warn "A const with the name #{const.full_name} already exists"
263
+ return c
264
+ else
265
+ raise ArgumentError,"#A different const with the name #{const.full_name} already exists: #{const} != #{c}"
266
+ end
212
267
  end
213
268
  if const.namespace? && self.full_name != const.namespace
214
269
  t=type(const.namespace,false)
@@ -223,9 +278,13 @@ module Rbind
223
278
 
224
279
  def add_default_types
225
280
  add_simple_types RNamespace.default_type_names
226
- add_type ::Rbind::RDataType.new("uchar").cname("unsigned char")
227
- add_type ::Rbind::RDataType.new("c_string").cname("char *")
228
- add_type ::Rbind::RDataType.new("const_c_string").cname("const char *")
281
+ type("uchar").cname("unsigned char")
282
+ type("c_string").cname("char *")
283
+ RNamespace.default_type_alias.each_pair do |key,val|
284
+ next if @type_alias.has_key?(key)
285
+ @type_alias[key.to_s] = type(val)
286
+ end
287
+ self
229
288
  end
230
289
 
231
290
  def add_simple_type(name)
@@ -239,9 +298,8 @@ module Rbind
239
298
  end
240
299
  end
241
300
 
242
- def add_type(type)
243
- raise ArgumentError, "wrong parmeter type #{type}" unless type.is_a? RDataType
244
- if type(type.full_name,false,false)
301
+ def add_type(type,check_exist = true)
302
+ if check_exist && type(type.full_name,false,false)
245
303
  raise ArgumentError,"A type with the name #{type.full_name} already exists"
246
304
  end
247
305
  # if self is not the right namespace
@@ -252,28 +310,31 @@ module Rbind
252
310
  else
253
311
  type.owner = self
254
312
  if type.alias
255
- if type(type.alias,false,false)
313
+ if check_exist && type(type.alias,false,false)
256
314
  raise ArgumentError,"A type with the name alias #{type.alias} already exists"
257
315
  end
258
- @types_alias[type.alias] = type
316
+ raise ArgumentError,"A type alias with the name #{t.alias} already exists" if(t = @type_alias[type.alias])
317
+ @type_alias[type.alias] = type.to_raw
259
318
  end
260
- @types[type.name] = type
319
+ raise ArgumentError,"A type with the name #{t.full_name} already exists" if(t = @types[type.name])
320
+ @types[type.name] = type.to_raw
261
321
  end
262
322
  type
263
323
  end
264
324
 
265
325
  def type(name,raise_ = true,search_owner = true)
266
- ptr = name.include?("*")
267
- ref = name.include?("&")
268
- if(ptr && ref)
269
- raise ArgumentError,"given type is a reference and pointer at the same time: #{name}"
270
- end
271
- name = name.gsub("*","").gsub("&","")
272
- name = name.chomp(" ")
326
+ name = name.to_s
327
+ constant = if name =~ /const /
328
+ true
329
+ else
330
+ false
331
+ end
332
+ name = name.gsub("unsigned ","u").gsub("const ","").gsub(" ","").gsub(">>","> >")
333
+
273
334
  t = if @types.has_key?(name)
274
335
  @types[name]
275
- elsif @types_alias.has_key?(name)
276
- @types_alias[name]
336
+ elsif @type_alias.has_key?(name)
337
+ @type_alias[name]
277
338
  else
278
339
  if !!(ns = RBase.namespace(name))
279
340
  ns = ns.split("::")
@@ -283,7 +344,7 @@ module Rbind
283
344
  end
284
345
  end
285
346
  t ||= begin
286
- used_namespaces.values.each do |ns|
347
+ used_namespaces.each do |ns|
287
348
  t = ns.type(name,false,false)
288
349
  break if t
289
350
  end
@@ -292,25 +353,84 @@ module Rbind
292
353
  t ||= if search_owner && owner
293
354
  owner.type(name,false)
294
355
  end
295
- raise RuntimeError,"#{full_name} has no type called #{name}" if raise_ && !t
296
- if t && (ptr || ref)
297
- t = t.clone
298
- t.ref = ref
299
- t.ptr = ptr
356
+ # check if type is a pointer and pointee is registered
357
+ t ||= begin
358
+ ptr_level = $1.to_s.size if name =~ /(\**)$/
359
+ name2 = name.gsub("*","")
360
+ ref_level = $1.to_s.size if name2 =~ /(&*)$/
361
+ name2 = name2.gsub("&","")
362
+ if ptr_level > 0 || ref_level > 0
363
+ t = type(name2,raise_,search_owner)
364
+ if t
365
+ 1.upto(ptr_level) do
366
+ t = t.to_ptr
367
+ end
368
+ 1.upto(ref_level) do
369
+ t = t.to_ref
370
+ end
371
+ # t.owner.add_type(t,false)
372
+ t
373
+ end
374
+ end
375
+ end
376
+
377
+ # check if type is a template and a template is registered
378
+ # under the given name
379
+ t ||= if search_owner && name =~ /([:\w]*)<(.*)>$/
380
+ t = type($1,false) if $1 && !$1.empty?
381
+ t2 = type($2,false) if $2 && !$2.empty?
382
+ if t && t2
383
+ name = "#{t.name}<#{t2.full_name}>"
384
+ t3 ||= t.owner.type(name,false,false)
385
+ t3 ||= begin
386
+ if !t.template?
387
+ ::Rbind.log.error "try to spezialize a class #{t.full_name} --> #{name}"
388
+ nil
389
+ else
390
+ t3 = t.do_specialize(name,t2)
391
+ if !t3
392
+ ::Rbind.log.error "Failed to specialize template #{t.full_name} --> #{name}"
393
+ nil
394
+ else
395
+ t.owner.add_type(t3,false)
396
+ ::Rbind.log.info "spezialize template #{t.full_name} --> #{t3.full_name}"
397
+ t3
398
+ end
399
+ end
400
+ end
401
+ end
402
+ end
403
+
404
+ if !t && raise_
405
+ if self.class.callbacks_for_hook(:on_type_not_found)
406
+ results = self.run_hook(:on_type_not_found,self,name)
407
+ t = results.find do |t|
408
+ t.respond_to?(:type)
409
+ end
410
+ end
411
+ raise RuntimeError,"#{full_name} has no type called #{name}" if !t
412
+ end
413
+ if constant
414
+ t.to_const
415
+ else
416
+ t
300
417
  end
301
- t
302
418
  end
303
419
 
304
420
  def pretty_print_name
305
- "namespace #{full_name}#{" Flags: #{flags.join(", ")}" unless flags.empty?}"
421
+ "namespace #{full_name}"
306
422
  end
307
423
 
308
424
  def root?
309
425
  !!root
310
426
  end
311
427
 
428
+ def empty?
429
+ consts.empty? && types.empty? && operations.empty?
430
+ end
431
+
312
432
  def pretty_print(pp)
313
- pp.text pretty_print_name
433
+ pp.text pretty_print_name unless root?
314
434
 
315
435
  unless consts.empty?
316
436
  pp.nest(2) do
@@ -329,7 +449,20 @@ module Rbind
329
449
  pp.breakable
330
450
  pp.text "Types:"
331
451
  pp.nest(2) do
452
+ simple = []
453
+ other = []
332
454
  types.each do |t|
455
+ if t.basic_type? && !t.container?
456
+ simple << t.name
457
+ else
458
+ other << t
459
+ end
460
+ end
461
+ if !simple.empty?
462
+ pp.breakable
463
+ pp.text(simple.join(", "))
464
+ end
465
+ other.each do |t|
333
466
  pp.breakable
334
467
  pp.pp(t)
335
468
  end
@@ -354,12 +487,16 @@ module Rbind
354
487
  end
355
488
 
356
489
  def method_missing(m,*args)
357
- t = type(m.to_s,false,false)
358
- return t if t
490
+ if m != :to_ary && args.empty?
491
+ t = type(m.to_s,false,false)
492
+ return t if t
359
493
 
360
- op = operation(m.to_s,false)
361
- return op if op
494
+ op = operation(m.to_s,false)
495
+ return op if op
362
496
 
497
+ c = const(m.to_s,false)
498
+ return c if c
499
+ end
363
500
  super
364
501
  end
365
502
  end