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 +5 -5
- data/lib/rbind/core/rclass.rb +4 -2
- data/lib/rbind/core/rnamespace.rb +18 -3
- data/lib/rbind/default_parser.rb +50 -1
- data/lib/rbind/generator_extern.rb +3 -1
- data/lib/rbind/generator_ruby.rb +26 -11
- data/lib/rbind/tools/hdr_parser.py +127 -50
- data/rbind.gemspec +2 -2
- metadata +3 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 8dfa66e6b61508d26cc2c07d7a903f26fc1cdafe7cf3b89e01ca3d3d2c88cbea
|
4
|
+
data.tar.gz: f4189a984e30892df84c8fc903a71379ce9e25efffa1cb10de150830c66909bd
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9d6bd892f327c156d0285268f72d08da7aff8ebf466763f5a603725b3d603e2340d76bf003ba139ffdfc21498f2c24c5a7c1003fa67f843d39a8c219da642273
|
7
|
+
data.tar.gz: 4af2d861e47900da274e9297b76c25efa0810bfebeaaf9dc016737cf7a833a648a9c42f766ebf0c8cd1acdf365dd2a34c524c77043b90cf87f5c1fa263669517
|
data/lib/rbind/core/rclass.rb
CHANGED
@@ -220,10 +220,12 @@ module Rbind
|
|
220
220
|
raise ArgumentError, "klass name is empty"
|
221
221
|
end
|
222
222
|
if parent? klass
|
223
|
-
|
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
|
-
|
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
|
-
|
141
|
-
|
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)
|
data/lib/rbind/default_parser.rb
CHANGED
@@ -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?
|
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
|
|
data/lib/rbind/generator_ruby.rb
CHANGED
@@ -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
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
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
|
-
|
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
|
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 =
|
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::
|
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*[,:]
|
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 =
|
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,
|
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, [("
|
412
|
-
("CV_EXPORTS_W", ""), ("CV_EXPORTS", ""), ("CV_CDECL", ""), ("CV_WRAP ", " "), ("CV_INLINE", "")
|
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
|
-
|
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
|
606
|
-
|
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,
|
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
|
-
|
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
|
724
|
+
if end_token == "}" and context.startswith("enum"):
|
694
725
|
decl = self.parse_enum(stmt)
|
695
|
-
|
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,
|
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
|
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:
|
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
|
-
|
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
|
-
|
858
|
+
l = ''
|
859
|
+
continue
|
806
860
|
|
807
861
|
if token == "/*":
|
808
862
|
block_head += " " + l[:pos]
|
809
|
-
|
810
|
-
if pos
|
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[
|
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
|
-
|
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
|
846
|
-
|
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,
|
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)
|
data/rbind.gemspec
CHANGED
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.
|
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:
|
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.
|
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
|