rbind 0.0.28 → 0.0.30

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: e930dbda0aa8e1f1acf8758c78fad9324c0019bd
4
- data.tar.gz: 62cf7fb25736383555dad7621b1df2fa0ddb5542
2
+ SHA256:
3
+ metadata.gz: 8dfa66e6b61508d26cc2c07d7a903f26fc1cdafe7cf3b89e01ca3d3d2c88cbea
4
+ data.tar.gz: f4189a984e30892df84c8fc903a71379ce9e25efffa1cb10de150830c66909bd
5
5
  SHA512:
6
- metadata.gz: 7b75baa4b7012be3076556b6980addc786630124005f2ff72e258cca0f0aa1e6a04e5623214c2723e159bbef661a0cced3f6b1b7778b0afd98d2794c996c24cc
7
- data.tar.gz: 10d0e92af7049191962ea3c3197ffb08eec3f1eb09f88febe61993e78cf054da5f45d4e206071303878f6287b6542b6a62411f1e4fdd3b9f65e547a8c58cb9e8
6
+ metadata.gz: 9d6bd892f327c156d0285268f72d08da7aff8ebf466763f5a603725b3d603e2340d76bf003ba139ffdfc21498f2c24c5a7c1003fa67f843d39a8c219da642273
7
+ data.tar.gz: 4af2d861e47900da274e9297b76c25efa0810bfebeaaf9dc016737cf7a833a648a9c42f766ebf0c8cd1acdf365dd2a34c524c77043b90cf87f5c1fa263669517
@@ -220,10 +220,12 @@ module Rbind
220
220
  raise ArgumentError, "klass name is empty"
221
221
  end
222
222
  if parent? klass
223
- raise ArgumentError,"#A parent class with the name #{klass.name} already exists"
223
+ puts "ignore: parent class #{klass.name} was added multiple time to class #{name}"
224
+ return self
224
225
  end
225
226
  if klass.full_name == full_name || klass == self
226
- raise ArgumentError,"class #{klass.full_name} cannot be parent of its self"
227
+ puts "ignore: class #{klass.name} cannot be parent class of itself"
228
+ return self
227
229
  end
228
230
  @parent_classes[klass.name] = ParentClass.new(klass,accessor)
229
231
  raise "Cannot use namespace #{klass.full_name} as parent class for #{self.full_name}" unless(klass.respond_to?(:child?))
@@ -132,13 +132,28 @@ module Rbind
132
132
  end
133
133
  end
134
134
 
135
+ def enum_hash
136
+ @enum_hash ||= Hash.new # cache values so that they can be modified
137
+ @types.each_value do |t|
138
+ next unless t.is_a? REnum
139
+ t.values.each do |key,value|
140
+ next if @enum_hash.has_key?(key)
141
+ p = RParameter.new(key,type("const int"),value)
142
+ p.owner = self
143
+ @enum_hash[key] = p
144
+ end
145
+ end
146
+ @enum_hash
147
+ end
148
+
135
149
  def consts
136
- @consts.values
150
+ @consts.values+enum_hash.values
137
151
  end
138
152
 
139
153
  def const(name,raise_ = true,search_owner = true)
140
- c = if @consts.has_key?(name)
141
- @consts[name]
154
+ hash = @consts.merge(enum_hash)
155
+ c = if hash.has_key?(name)
156
+ hash[name]
142
157
  else
143
158
  if !!(ns = RBase.namespace(name))
144
159
  t = type(ns,false)
@@ -50,6 +50,7 @@ module Rbind
50
50
  return type_name
51
51
  end
52
52
 
53
+ type_name = type_name.gsub("cv::vector","vector") # fix namespace
53
54
  if(type_name =~/^vector/ || type_name =~/^Ptr/)
54
55
  if(type_name =~ /^([a-zA-Z\d]*)_([_a-zA-Z\d]*) ?(\(?.*)\)? */)
55
56
  "#{$1}<#{unmask_template($2)}>#{$3}"
@@ -89,7 +90,7 @@ module Rbind
89
90
  array = flags.shift.split(" ")
90
91
  type_name = array.shift
91
92
  para_name = array.shift
92
- default = unmask_template(array.join(" "))
93
+ default = unmask_template(array.join(" ").gsub("/C",""))
93
94
  type = find_type(owner,type_name)
94
95
  flags = normalize_flags(line_number,flags,:IO,:O)
95
96
  type = if flags.include?(:O) || flags.include?(:IO)
@@ -153,6 +154,9 @@ module Rbind
153
154
  end
154
155
  end
155
156
  classes[i] = val.join(",")
157
+ elsif val =="cv::class" # bug in parser
158
+ puts "ignore: parent class #{val} which is invalid for #{$1}"
159
+ classes[i] = nil
156
160
  end
157
161
  end
158
162
  classes.compact!
@@ -257,7 +261,50 @@ module Rbind
257
261
  [c,1]
258
262
  end
259
263
 
264
+ def parse_enum(line_number,string)
265
+ lines = string.split("\n")
266
+ a = lines.shift.rstrip.gsub("enum struct ","enum ")
267
+ a = a.gsub("enum class ","enum ")
268
+ unless a =~ /enum ([<>a-zA-Z\.\d_:]*)/
269
+ raise "cannot parse enum#{a}"
270
+ end
271
+ name = $1.gsub("<unnamed>","Unknown")
272
+ renum = REnum.new(name)
273
+ renum = begin
274
+ add_type(renum)
275
+ rescue => e
276
+ t = type(name)
277
+ if !t.is_a? REnum || (renum.name != "Unknown" && !renum.values.empty?)
278
+ raise "cannot overwrite #{t.class}: #{t} with #{renum.class}: #{renum}. Use forward declaration?"
279
+ end
280
+ t
281
+ end
282
+
283
+ line_counter = 1
284
+ lines.each do |line|
285
+ line_counter += 1
286
+ line =~ /const ([<>a-zA-Z\.\d_:]*) (.*) \[\]/
287
+ val = $2.strip
288
+ name = $1.strip
289
+ name = name.gsub("#{renum.full_name.gsub("::",".")}.","") # bug in hdl_parser giving full name for some of the types
290
+ name = name.gsub("#{renum.namespace.gsub("::",".")}.","")
291
+ Set.new(val.split(/[ ><\+\-\*\/\&\|\)\(\~]/)).each do |v|
292
+ c = const(v,false)
293
+ if c
294
+ val.gsub!(v,c.full_name)
295
+ elsif renum.values.include? v
296
+ val.gsub!(v,renum.values[v])
297
+ end
298
+ end
299
+ renum.add_value(name,val)
300
+ end
301
+ [renum,line_counter]
302
+ rescue RuntimeError => e
303
+ raise "input line #{line_number}: #{e}"
304
+ end
305
+
260
306
  def parse_operation(line_number,string)
307
+ string = string.gsub(";"," ") # strip wrong characters from the parser
261
308
  a = string.split("\n")
262
309
  line = a.shift
263
310
  flags = line.split(" /")
@@ -332,6 +379,8 @@ module Rbind
332
379
  parse_class(line_number,block)
333
380
  elsif first == "struct"
334
381
  parse_struct(line_number,block)
382
+ elsif first == "enum"
383
+ parse_enum(line_number,block)
335
384
  else
336
385
  parse_operation(line_number,block)
337
386
  end
@@ -32,8 +32,10 @@ module Rbind
32
32
 
33
33
  #write all types so they get parsed first
34
34
  @root.each_type do |t|
35
- if t.is_a? RClass
35
+ if t.is_a?(RClass)
36
36
  file_extern.write "class #{GeneratorExtern.normalize_type_name(t.full_name)}\n"
37
+ elsif t.is_a?(REnum)
38
+ file_extern.write "enum #{GeneratorExtern.normalize_type_name(t.full_name)}\n"
37
39
  end
38
40
  end
39
41
 
@@ -133,12 +133,12 @@ module Rbind
133
133
  # map template classes
134
134
  # std::vector<std::string> -> Std::Vector::Std_String
135
135
  if name =~ /([\w:]*)<(.*)>$/
136
- name = $1
137
- names = $2.split(",")
138
- names.map! do |val|
139
- normalize_type_name(val,true).gsub("::","_")
140
- end
141
- return "#{normalize_type_name(name,true)}::#{names.join("_")}"
136
+ name = $1
137
+ names = $2.split(",")
138
+ names.map! do |val|
139
+ normalize_type_name(val,true).gsub("::","_")
140
+ end
141
+ return "#{normalize_type_name(name,true)}::#{names.join("_")}"
142
142
  else
143
143
  name
144
144
  end
@@ -253,6 +253,21 @@ module Rbind
253
253
  name
254
254
  end
255
255
 
256
+ def self.normalize_const_value(name)
257
+ name = name.to_s.gsub(" ","")
258
+ # Parse constant declaration with suffix like 1000000LL
259
+ if name =~ /^([0-9]+)[uUlL]{0,2}/
260
+ name = $1
261
+ return name
262
+ end
263
+ # upcase first letter
264
+ name = name.gsub(/\w*/) do |n|
265
+ next unless n.size > 0
266
+ n[0].upcase+n[1,n.size-1]
267
+ end
268
+ name
269
+ end
270
+
256
271
  class HelperBase
257
272
  extend ::Rbind::Logger
258
273
 
@@ -406,12 +421,13 @@ module Rbind
406
421
  str += "\tenum :#{GeneratorRuby::normalize_enum_name(t.to_raw.csignature)}, ["
407
422
  t.values.each do |name,value|
408
423
  if value
409
- str += ":#{name},#{value}, "
424
+ value = GeneratorRuby.normalize_const_value(value)
425
+ str += ":#{name},#{GeneratorRuby.normalize_type_name(value)}, "
410
426
  else
411
427
  str += ":#{name}, "
412
428
  end
413
429
  end
414
- str += "]\n\n"
430
+ str += "]\n"
415
431
  end
416
432
  end
417
433
  str
@@ -676,7 +692,7 @@ module Rbind
676
692
  end
677
693
 
678
694
  def add_consts(root=@root)
679
- str = @root.consts.map do |c|
695
+ str = root.consts.map do |c|
680
696
  next if c.extern? || c.ignore?
681
697
  if not c.default_value
682
698
  HelperBase.log.warn "#{c.name}: no default value"
@@ -685,13 +701,12 @@ module Rbind
685
701
  val = begin
686
702
  eval(c.default_value)
687
703
  rescue
688
- GeneratorRuby::normalize_type_name(c.default_value)
704
+ GeneratorRuby::normalize_const_value(c.default_value)
689
705
  end
690
706
  " #{c.name} = #{val}\n"
691
707
  end
692
708
  end.join
693
709
  return str unless @compact_namespace
694
-
695
710
  root.each_type(false) do |t|
696
711
  next if t.basic_type? && !t.is_a?(RNamespace)
697
712
  str += add_consts(t) if name == GeneratorRuby.normalize_type_name(t.full_name)
@@ -21,18 +21,20 @@ opencv_hdr_list = [
21
21
  ]
22
22
 
23
23
  """
24
- Each declaration is [funcname, return_value_type /* in C, not in Python */, <list_of_modifiers>, <list_of_arguments>],
24
+ Each declaration is [funcname, return_value_type /* in C, not in Python */, <list_of_modifiers>, <list_of_arguments>, original_return_type, docstring],
25
25
  where each element of <list_of_arguments> is 4-element list itself:
26
26
  [argtype, argname, default_value /* or "" if none */, <list_of_modifiers>]
27
27
  where the list of modifiers is yet another nested list of strings
28
28
  (currently recognized are "/O" for output argument, "/S" for static (i.e. class) methods
29
29
  and "/A value" for the plain C arrays with counters)
30
+ original_return_type is None if the original_return_type is the same as return_value_type
30
31
  """
31
32
 
32
33
  class CppHeaderParser(object):
33
34
 
34
- def __init__(self, generate_umat_decls=False):
35
+ def __init__(self, generate_umat_decls=False, generate_gpumat_decls=False):
35
36
  self._generate_umat_decls = generate_umat_decls
37
+ self._generate_gpumat_decls = generate_gpumat_decls
36
38
 
37
39
  self.BLOCK_TYPE = 0
38
40
  self.BLOCK_NAME = 1
@@ -104,6 +106,14 @@ class CppHeaderParser(object):
104
106
  modlist.append("/CA " + macro_arg)
105
107
  arg_str = arg_str[:npos] + arg_str[npos3+1:]
106
108
 
109
+ npos = arg_str.find("const")
110
+ if npos >= 0:
111
+ modlist.append("/C")
112
+
113
+ npos = arg_str.find("&")
114
+ if npos >= 0:
115
+ modlist.append("/Ref")
116
+
107
117
  arg_str = arg_str.strip()
108
118
  word_start = 0
109
119
  word_list = []
@@ -226,7 +236,7 @@ class CppHeaderParser(object):
226
236
  else:
227
237
  prev_val_delta = 0
228
238
  prev_val = val = pv[1].strip()
229
- decl.append(["const " + self.get_dotted_name(pv[0].strip()), val, [], []])
239
+ decl.append(["const " + self.get_dotted_name(pv[0].strip()), val, [], [], None, ""])
230
240
  return decl
231
241
 
232
242
  def parse_class_decl(self, decl_str):
@@ -250,13 +260,13 @@ class CppHeaderParser(object):
250
260
  l = l[:npos] + l[npos3+1:]
251
261
 
252
262
  l = self.batch_replace(l, [("CV_EXPORTS_W", ""), ("CV_EXPORTS", ""), ("public virtual ", " "), ("public ", " "), ("::", ".")]).strip()
253
- ll = re.split(r'\s*[,:]?\s*', l)
263
+ ll = re.split(r'\s+|\s*[,:]\s*', l)
254
264
  ll = [le for le in ll if le]
255
265
  classname = ll[1]
256
266
  bases = ll[2:]
257
267
  return classname, bases, modlist
258
268
 
259
- def parse_func_decl_no_wrap(self, decl_str, static_method = False):
269
+ def parse_func_decl_no_wrap(self, decl_str, static_method=False, docstring=""):
260
270
  decl_str = (decl_str or "").strip()
261
271
  virtual_method = False
262
272
  explicit_method = False
@@ -299,7 +309,7 @@ class CppHeaderParser(object):
299
309
  apos = fdecl.find("(", apos+1)
300
310
 
301
311
  fname = "cv." + fname.replace("::", ".")
302
- decl = [fname, rettype, [], []]
312
+ decl = [fname, rettype, [], [], None, docstring]
303
313
 
304
314
  # inline constructor implementation
305
315
  implmatch = re.match(r"(\(.*?\))\s*:\s*(\w+\(.*?\),?\s*)+", fdecl[apos:])
@@ -366,11 +376,9 @@ class CppHeaderParser(object):
366
376
  decl[2].append("/A")
367
377
  if bool(re.match(r".*\)\s*const(\s*=\s*0)?", decl_str)):
368
378
  decl[2].append("/C")
369
- if "virtual" in decl_str:
370
- print(decl_str)
371
379
  return decl
372
380
 
373
- def parse_func_decl(self, decl_str, use_umat=False):
381
+ def parse_func_decl(self, decl_str, mat="Mat", docstring=""):
374
382
  """
375
383
  Parses the function or method declaration in the form:
376
384
  [([CV_EXPORTS] <rettype>) | CVAPI(rettype)]
@@ -379,12 +387,11 @@ class CppHeaderParser(object):
379
387
  [const] {; | <function_body>}
380
388
 
381
389
  Returns the function declaration entry:
382
- [<func name>, <return value C-type>, <list of modifiers>, <list of arguments>] (see above)
390
+ [<func name>, <return value C-type>, <list of modifiers>, <list of arguments>, <original return type>, <docstring>] (see above)
383
391
  """
384
392
 
385
393
  if self.wrap_mode:
386
- if not (("CV_EXPORTS_AS" in decl_str) or ("CV_EXPORTS_W" in decl_str) or \
387
- ("CV_WRAP" in decl_str) or ("CV_WRAP_AS" in decl_str)):
394
+ if not (("CV_EXPORTS_AS" in decl_str) or ("CV_EXPORTS_W" in decl_str) or ("CV_WRAP" in decl_str)):
388
395
  return []
389
396
 
390
397
  # ignore old API in the documentation check (for now)
@@ -404,12 +411,37 @@ class CppHeaderParser(object):
404
411
  arg, npos3 = self.get_macro_arg(decl_str, npos)
405
412
  func_modlist.append("="+arg)
406
413
  decl_str = decl_str[:npos] + decl_str[npos3+1:]
414
+ npos = decl_str.find("CV_WRAP_PHANTOM")
415
+ if npos >= 0:
416
+ decl_str, _ = self.get_macro_arg(decl_str, npos)
417
+ func_modlist.append("/phantom")
418
+ npos = decl_str.find("CV_WRAP_MAPPABLE")
419
+ if npos >= 0:
420
+ mappable, npos3 = self.get_macro_arg(decl_str, npos)
421
+ func_modlist.append("/mappable="+mappable)
422
+ classname = top[1]
423
+ return ['.'.join([classname, classname]), None, func_modlist, [], None, None]
424
+
425
+ virtual_method = False
426
+ pure_virtual_method = False
427
+ const_method = False
407
428
 
408
429
  # filter off some common prefixes, which are meaningless for Python wrappers.
409
430
  # note that we do not strip "static" prefix, which does matter;
410
431
  # it means class methods, not instance methods
411
- decl_str = self.batch_replace(decl_str, [("virtual", ""), ("static inline", ""), ("inline", ""),\
412
- ("CV_EXPORTS_W", ""), ("CV_EXPORTS", ""), ("CV_CDECL", ""), ("CV_WRAP ", " "), ("CV_INLINE", "")]).strip()
432
+ decl_str = self.batch_replace(decl_str, [("static inline", ""), ("inline", ""),\
433
+ ("CV_EXPORTS_W", ""), ("CV_EXPORTS", ""), ("CV_CDECL", ""), ("CV_WRAP ", " "), ("CV_INLINE", ""),
434
+ ("CV_DEPRECATED", ""), ("CV_DEPRECATED_EXTERNAL", "")]).strip()
435
+
436
+
437
+ if decl_str.strip().startswith('virtual'):
438
+ virtual_method = True
439
+
440
+ decl_str = decl_str.replace('virtual' , '')
441
+
442
+ end_tokens = decl_str[decl_str.rfind(')'):].split()
443
+ const_method = 'const' in end_tokens
444
+ pure_virtual_method = '=' in end_tokens and '0' in end_tokens
413
445
 
414
446
  static_method = False
415
447
  context = top[0]
@@ -484,7 +516,7 @@ class CppHeaderParser(object):
484
516
  funcname = self.get_dotted_name(funcname)
485
517
 
486
518
  if not self.wrap_mode:
487
- decl = self.parse_func_decl_no_wrap(decl_str, static_method)
519
+ decl = self.parse_func_decl_no_wrap(decl_str, static_method, docstring)
488
520
  decl[0] = funcname
489
521
  return decl
490
522
 
@@ -502,8 +534,6 @@ class CppHeaderParser(object):
502
534
  t, npos = self.find_next_token(decl_str, ["(", ")", ",", "<", ">"], npos)
503
535
  if not t:
504
536
  print("Error: no closing ')' at %d" % (self.lineno,))
505
- print(decl_str)
506
- print(decl_str[arg_start:])
507
537
  sys.exit(-1)
508
538
  if t == "<":
509
539
  angle_balance += 1
@@ -539,8 +569,6 @@ class CppHeaderParser(object):
539
569
  a = a[:eqpos].strip()
540
570
  arg_type, arg_name, modlist, argno = self.parse_arg(a, argno)
541
571
  if self.wrap_mode:
542
- mat = "UMat" if use_umat else "Mat"
543
-
544
572
  # TODO: Vectors should contain UMat, but this is not very easy to support and not very needed
545
573
  vector_mat = "vector_{}".format("Mat")
546
574
  vector_mat_template = "vector<{}>".format("Mat")
@@ -573,11 +601,14 @@ class CppHeaderParser(object):
573
601
 
574
602
  if static_method:
575
603
  func_modlist.append("/S")
604
+ if const_method:
605
+ func_modlist.append("/C")
606
+ if virtual_method:
607
+ func_modlist.append("/V")
608
+ if pure_virtual_method:
609
+ func_modlist.append("/PV")
576
610
 
577
- if original_type is None:
578
- return [funcname, rettype, func_modlist, args]
579
- else:
580
- return [funcname, rettype, func_modlist, args, original_type]
611
+ return [funcname, rettype, func_modlist, args, original_type, docstring]
581
612
 
582
613
  def get_dotted_name(self, name):
583
614
  """
@@ -602,8 +633,10 @@ class CppHeaderParser(object):
602
633
  block_type, block_name = b[self.BLOCK_TYPE], b[self.BLOCK_NAME]
603
634
  if block_type in ["file", "enum"]:
604
635
  continue
605
- if block_type not in ["struct", "class", "namespace"]:
606
- print("Error at %d: there are non-valid entries in the current block stack " % (self.lineno, self.block_stack))
636
+ if block_type in ["enum struct", "enum class"] and block_name == name:
637
+ continue
638
+ if block_type not in ["struct", "class", "namespace", "enum struct", "enum class"]:
639
+ print("Error at %d: there are non-valid entries in the current block stack %s" % (self.lineno, self.block_stack))
607
640
  sys.exit(-1)
608
641
  if block_name and (block_type == "namespace" or not qualified_name):
609
642
  n += block_name + "."
@@ -612,7 +645,7 @@ class CppHeaderParser(object):
612
645
  n = "cv.Algorithm"
613
646
  return n
614
647
 
615
- def parse_stmt(self, stmt, end_token, use_umat=False):
648
+ def parse_stmt(self, stmt, end_token, mat="Mat", docstring=""):
616
649
  """
617
650
  parses the statement (ending with ';' or '}') or a block head (ending with '{')
618
651
 
@@ -659,7 +692,7 @@ class CppHeaderParser(object):
659
692
  exit(1)
660
693
  if classname.startswith("_Ipl"):
661
694
  classname = classname[1:]
662
- decl = [stmt_type + " " + self.get_dotted_name(classname), "", modlist, []]
695
+ decl = [stmt_type + " " + self.get_dotted_name(classname), "", modlist, [], None, docstring]
663
696
  if bases:
664
697
  decl[1] = ": " + ", ".join([self.get_dotted_name(b).replace(".","::") for b in bases])
665
698
  return stmt_type, classname, True, decl
@@ -674,25 +707,24 @@ class CppHeaderParser(object):
674
707
  exit(1)
675
708
  decl = []
676
709
  if ("CV_EXPORTS_W" in stmt) or ("CV_EXPORTS_AS" in stmt) or (not self.wrap_mode):# and ("CV_EXPORTS" in stmt)):
677
- decl = [stmt_type + " " + self.get_dotted_name(classname), "", modlist, []]
710
+ decl = [stmt_type + " " + self.get_dotted_name(classname), "", modlist, [], None, docstring]
678
711
  if bases:
679
712
  decl[1] = ": " + ", ".join([self.get_dotted_name(b).replace(".","::") for b in bases])
680
713
  return stmt_type, classname, True, decl
681
714
 
682
- if stmt.startswith("enum"):
683
- return "enum", "", True, None
684
-
685
- if stmt.startswith("namespace"):
686
- stmt_list = stmt.split()
715
+ if stmt.startswith("enum") or stmt.startswith("namespace"):
716
+ stmt_list = stmt.rsplit(" ", 1)
687
717
  if len(stmt_list) < 2:
688
718
  stmt_list.append("<unnamed>")
689
719
  return stmt_list[0], stmt_list[1], True, None
720
+
690
721
  if stmt.startswith("extern") and "\"C\"" in stmt:
691
722
  return "namespace", "", True, None
692
723
 
693
- if end_token == "}" and context == "enum":
724
+ if end_token == "}" and context.startswith("enum"):
694
725
  decl = self.parse_enum(stmt)
695
- return "enum", "", False, decl
726
+ name = stack_top[self.BLOCK_NAME]
727
+ return context, name, False, decl
696
728
 
697
729
  if end_token == ";" and stmt.startswith("typedef"):
698
730
  # TODO: handle typedef's more intelligently
@@ -704,7 +736,7 @@ class CppHeaderParser(object):
704
736
  # since we filtered off the other places where '(' can normally occur:
705
737
  # - code blocks
706
738
  # - function pointer typedef's
707
- decl = self.parse_func_decl(stmt, use_umat=use_umat)
739
+ decl = self.parse_func_decl(stmt, mat=mat, docstring=docstring)
708
740
  # we return parse_flag == False to prevent the parser to look inside function/method bodies
709
741
  # (except for tracking the nested blocks)
710
742
  return stmt_type, "", False, decl
@@ -731,7 +763,7 @@ class CppHeaderParser(object):
731
763
  def find_next_token(self, s, tlist, p=0):
732
764
  """
733
765
  Finds the next token from the 'tlist' in the input 's', starting from position 'p'.
734
- Returns the first occured token and its position, or ("", len(s)) when no token is found
766
+ Returns the first occurred token and its position, or ("", len(s)) when no token is found
735
767
  """
736
768
  token = ""
737
769
  tpos = len(s)
@@ -759,17 +791,19 @@ class CppHeaderParser(object):
759
791
  SCAN = 0 # outside of a comment or preprocessor directive
760
792
  COMMENT = 1 # inside a multi-line comment
761
793
  DIRECTIVE = 2 # inside a multi-line preprocessor directive
794
+ DOCSTRING = 3 # inside a multi-line docstring
762
795
 
763
796
  state = SCAN
764
797
 
765
798
  self.block_stack = [["file", hname, True, True, None]]
766
799
  block_head = ""
800
+ docstring = ""
767
801
  self.lineno = 0
768
802
  self.wrap_mode = wmode
769
803
 
770
804
  for l0 in linelist:
771
805
  self.lineno += 1
772
- #print self.lineno
806
+ #print(state, self.lineno, l0)
773
807
 
774
808
  l = l0.strip()
775
809
 
@@ -789,8 +823,22 @@ class CppHeaderParser(object):
789
823
  l = l[pos+2:]
790
824
  state = SCAN
791
825
 
826
+ if state == DOCSTRING:
827
+ pos = l.find("*/")
828
+ if pos < 0:
829
+ docstring += l + "\n"
830
+ continue
831
+ docstring += l[:pos] + "\n"
832
+ l = l[pos+2:]
833
+ state = SCAN
834
+
835
+ if l.startswith('CV__') or l.startswith('__CV_'): # just ignore these lines
836
+ #print('IGNORE: ' + l)
837
+ state = SCAN
838
+ continue
839
+
792
840
  if state != SCAN:
793
- print("Error at %d: invlid state = %d" % (self.lineno, state))
841
+ print("Error at %d: invalid state = %d" % (self.lineno, state))
794
842
  sys.exit(-1)
795
843
 
796
844
  while 1:
@@ -798,19 +846,34 @@ class CppHeaderParser(object):
798
846
 
799
847
  if not token:
800
848
  block_head += " " + l
801
- break
849
+ block_head = block_head.strip()
850
+ if len(block_head) > 0 and block_head[-1] == ')' and block_head.startswith('CV_ENUM_FLAGS('):
851
+ l = ''
852
+ token = ';'
853
+ else:
854
+ break
802
855
 
803
856
  if token == "//":
804
857
  block_head += " " + l[:pos]
805
- break
858
+ l = ''
859
+ continue
806
860
 
807
861
  if token == "/*":
808
862
  block_head += " " + l[:pos]
809
- pos = l.find("*/", pos+2)
810
- if pos < 0:
863
+ end_pos = l.find("*/", pos+2)
864
+ if len(l) > pos + 2 and l[pos+2] == "*":
865
+ # '/**', it's a docstring
866
+ if end_pos < 0:
867
+ state = DOCSTRING
868
+ docstring = l[pos+3:] + "\n"
869
+ break
870
+ else:
871
+ docstring = l[pos+3:end_pos]
872
+
873
+ elif end_pos < 0:
811
874
  state = COMMENT
812
875
  break
813
- l = l[pos+2:]
876
+ l = l[end_pos+2:]
814
877
  continue
815
878
 
816
879
  if token == "\"":
@@ -830,6 +893,7 @@ class CppHeaderParser(object):
830
893
 
831
894
  stmt = (block_head + " " + l[:pos]).strip()
832
895
  stmt = " ".join(stmt.split()) # normalize the statement
896
+ #print(stmt)
833
897
  stack_top = self.block_stack[-1]
834
898
 
835
899
  if stmt.startswith("@"):
@@ -840,22 +904,33 @@ class CppHeaderParser(object):
840
904
  if stack_top[self.PROCESS_FLAG]:
841
905
  # even if stack_top[PUBLIC_SECTION] is False, we still try to process the statement,
842
906
  # since it can start with "public:"
843
- stmt_type, name, parse_flag, decl = self.parse_stmt(stmt, token)
907
+ docstring = docstring.strip()
908
+ stmt_type, name, parse_flag, decl = self.parse_stmt(stmt, token, docstring=docstring)
844
909
  if decl:
845
- if stmt_type == "enum":
846
- for d in decl:
847
- decls.append(d)
910
+ if stmt_type.startswith("enum"):
911
+ decls.append([stmt_type + " " + self.get_dotted_name(name), "", [], decl, None, ""])
848
912
  else:
849
913
  decls.append(decl)
850
914
 
915
+ if self._generate_gpumat_decls and "cv.cuda." in decl[0]:
916
+ # If function takes as one of arguments Mat or vector<Mat> - we want to create the
917
+ # same declaration working with GpuMat (this is important for T-Api access)
918
+ args = decl[3]
919
+ has_mat = len(list(filter(lambda x: x[0] in {"Mat", "vector_Mat"}, args))) > 0
920
+ if has_mat:
921
+ _, _, _, gpumat_decl = self.parse_stmt(stmt, token, mat="cuda::GpuMat", docstring=docstring)
922
+ decls.append(gpumat_decl)
923
+
851
924
  if self._generate_umat_decls:
852
925
  # If function takes as one of arguments Mat or vector<Mat> - we want to create the
853
926
  # same declaration working with UMat (this is important for T-Api access)
854
927
  args = decl[3]
855
928
  has_mat = len(list(filter(lambda x: x[0] in {"Mat", "vector_Mat"}, args))) > 0
856
929
  if has_mat:
857
- _, _, _, umat_decl = self.parse_stmt(stmt, token, use_umat=True)
930
+ _, _, _, umat_decl = self.parse_stmt(stmt, token, mat="UMat", docstring=docstring)
858
931
  decls.append(umat_decl)
932
+
933
+ docstring = ""
859
934
  if stmt_type == "namespace":
860
935
  chunks = [block[1] for block in self.block_stack if block[0] == 'namespace'] + [name]
861
936
  self.namespaces.add('.'.join(chunks))
@@ -887,6 +962,8 @@ class CppHeaderParser(object):
887
962
  """
888
963
  for d in decls:
889
964
  print(d[0], d[1], ";".join(d[2]))
965
+ # Uncomment below line to see docstrings
966
+ # print('"""\n' + d[5] + '\n"""')
890
967
  for a in d[3]:
891
968
  print(" ", a[0], a[1], a[2], end="")
892
969
  if a[3]:
@@ -895,7 +972,7 @@ class CppHeaderParser(object):
895
972
  print()
896
973
 
897
974
  if __name__ == '__main__':
898
- parser = CppHeaderParser(generate_umat_decls=False)
975
+ parser = CppHeaderParser(generate_umat_decls=True, generate_gpumat_decls=False)
899
976
  decls = []
900
977
  # for hname in opencv_hdr_list:
901
978
  # decls += parser.parse(hname)
@@ -1,7 +1,7 @@
1
1
  Gem::Specification.new do |s|
2
2
  s.name = 'rbind'
3
- s.version = '0.0.28'
4
- s.date = '2018-07-10'
3
+ s.version = '0.0.30'
4
+ s.date = '2019-06-06'
5
5
  s.platform = Gem::Platform::RUBY
6
6
  s.authors = ['Alexander Duda']
7
7
  s.email = ['Alexander.Duda@me.com']
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rbind
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.28
4
+ version: 0.0.30
5
5
  platform: ruby
6
6
  authors:
7
7
  - Alexander Duda
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2018-07-10 00:00:00.000000000 Z
11
+ date: 2019-06-06 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: ffi
@@ -123,7 +123,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
123
123
  version: 1.3.6
124
124
  requirements: []
125
125
  rubyforge_project:
126
- rubygems_version: 2.5.2.3
126
+ rubygems_version: 2.7.3
127
127
  signing_key:
128
128
  specification_version: 4
129
129
  summary: Library for genereating automated ffi-bindings for c/c++ libraries