merge upstream changes
MODIFY
gen_rust.py
gen_rust.py
@@ -579,8 +579,8 @@ class FuncInfo(GeneralInfo):
self.identifier = self.fullname.replace("::", "_")
- if len(decl) > 4:
- self.comment = decl[4].encode("ascii", "ignore")
+ if len(decl) > 5:
+ self.comment = decl[5].encode("ascii", "ignore")
else:
self.comment = ""
@@ -596,7 +596,7 @@ class FuncInfo(GeneralInfo):
self.fake_attrgetter = "/ATTRGETTER" in decl[2]
self.struct_attrname = None
if self.fake_attrgetter:
- self.struct_attrname = decl[5]
+ self.struct_attrname = decl[6]
self.cname = self.cppname = self.name
@@ -832,8 +832,8 @@ class ClassInfo(GeneralInfo):
self.is_trait = self.fullname in forced_trait_classes
self.classname = self.name
self.comment = ""
- if len(decl) > 4:
- self.comment = decl[4].encode("ascii", "ignore")
+ if len(decl) > 5:
+ self.comment = decl[5].encode("ascii", "ignore")
for m in decl[2]:
if m == "/Simple" or m == "/Map" :
self.is_simple = True
@@ -896,6 +896,7 @@ class ClassInfo(GeneralInfo):
field_type,
['/ATTRGETTER'],
[],
+ None,
u'returns the {struct_field} attr of {field_type} type\n'.format(
struct_field=struct_field,
field_type=field_type,

MODIFY
hdr_parser.py
hdr_parser.py
@@ -17,21 +17,24 @@ opencv_hdr_list = [
"../../objdetect/include/opencv2/objdetect.hpp",
"../../imgcodecs/include/opencv2/imgcodecs.hpp",
"../../videoio/include/opencv2/videoio.hpp",
-"../../highgui/include/opencv2/highgui.hpp"
+"../../highgui/include/opencv2/highgui.hpp",
]
"""
-Each declaration is [funcname, return_value_type /* in C, not in Python */, <list_of_modifiers>, <list_of_arguments>],
+Each declaration is [funcname, return_value_type /* in C, not in Python */, <list_of_modifiers>, <list_of_arguments>, original_return_type, docstring],
where each element of <list_of_arguments> is 4-element list itself:
[argtype, argname, default_value /* or "" if none */, <list_of_modifiers>]
where the list of modifiers is yet another nested list of strings
(currently recognized are "/O" for output argument, "/S" for static (i.e. class) methods
and "/A value" for the plain C arrays with counters)
+original_return_type is None if the original_return_type is the same as return_value_type
"""
class CppHeaderParser(object):
- def __init__(self):
+ def __init__(self, generate_umat_decls=False):
+ self._generate_umat_decls = generate_umat_decls
+
self.BLOCK_TYPE = 0
self.BLOCK_NAME = 1
self.PROCESS_FLAG = 2
@@ -104,6 +107,14 @@ class CppHeaderParser(object):
modlist.append("/CA " + macro_arg)
arg_str = arg_str[:npos] + arg_str[npos3+1:]
+ npos = arg_str.find("const")
+ if npos >= 0:
+ modlist.append("/C")
+
+ npos = arg_str.find("&")
+ if npos >= 0:
+ modlist.append("/Ref")
+
arg_str = arg_str.strip()
word_start = 0
word_list = []
@@ -226,7 +237,7 @@ class CppHeaderParser(object):
else:
prev_val_delta = 0
prev_val = val = pv[1].strip()
- decl.append(["const " + self.get_dotted_name(pv[0].strip()), val, [], []])
+ decl.append(["const " + self.get_dotted_name(pv[0].strip()), val, [], [], None, ""])
return decl
def parse_class_decl(self, decl_str):
@@ -252,13 +263,13 @@ class CppHeaderParser(object):
l = l[:npos] + l[npos3+1:]
l = self.batch_replace(l, [("CV_EXPORTS_W", ""), ("CV_EXPORTS", ""), ("public virtual ", " "), ("public ", " "), ("::", ".")]).strip()
- ll = re.split(r'\s*[,:]?\s*', l)
+ ll = re.split(r'\s+|\s*[,:]\s*', l)
ll = [le for le in ll if le]
classname = ll[1]
bases = ll[2:]
return classname, bases, modlist
- def parse_func_decl_no_wrap(self, decl_str, static_method, comment):
+ def parse_func_decl_no_wrap(self, decl_str, static_method=False, docstring=""):
decl_str = (decl_str or "").strip()
virtual_method = False
explicit_method = False
@@ -301,7 +312,7 @@ class CppHeaderParser(object):
apos = fdecl.find("(", apos+1)
fname = "cv." + fname.replace("::", ".")
- decl = [fname, rettype, [], [], comment]
+ decl = [fname, rettype, [], [], None, docstring]
# inline constructor implementation
implmatch = re.match(r"(\(.*?\))\s*:\s*(\w+\(.*?\),?\s*)+", fdecl[apos:])
@@ -372,9 +383,11 @@ class CppHeaderParser(object):
decl[2].append("/C")
if not bool(self.block_stack[-1][self.ACTUAL_PUBLIC_SECTION]):
decl[2].append("/H")
+ if "virtual" in decl_str:
+ print(decl_str)
return decl
- def parse_func_decl(self, decl_str, comment):
+ def parse_func_decl(self, decl_str, use_umat=False, docstring=""):
"""
Parses the function or method declaration in the form:
[([CV_EXPORTS] <rettype>) | CVAPI(rettype)]
@@ -383,8 +396,9 @@ class CppHeaderParser(object):
[const] {; | <function_body>}
Returns the function declaration entry:
- [<func name>, <return value C-type>, <list of modifiers>, <list of arguments>] (see above)
+ [<func name>, <return value C-type>, <list of modifiers>, <list of arguments>, <original return type>, <docstring>] (see above)
"""
+
if self.wrap_mode:
if not (("CV_EXPORTS_AS" in decl_str) or ("CV_EXPORTS_W" in decl_str) or \
("CV_WRAP" in decl_str) or ("CV_WRAP_AS" in decl_str)):
@@ -408,11 +422,26 @@ class CppHeaderParser(object):
func_modlist.append("="+arg)
decl_str = decl_str[:npos] + decl_str[npos3+1:]
+ virtual_method = False
+ pure_virtual_method = False
+ const_method = False
+
# filter off some common prefixes, which are meaningless for Python wrappers.
# note that we do not strip "static" prefix, which does matter;
# it means class methods, not instance methods
- decl_str = self.batch_replace(decl_str, [("virtual", ""), ("static inline", ""), ("inline", ""),\
- ("CV_EXPORTS_W", ""), ("CV_EXPORTS", ""), ("CV_CDECL", ""), ("CV_WRAP ", " "), ("CV_INLINE", "")]).strip()
+ decl_str = self.batch_replace(decl_str, [("static inline", ""), ("inline", ""),\
+ ("CV_EXPORTS_W", ""), ("CV_EXPORTS", ""), ("CV_CDECL", ""), ("CV_WRAP ", " "), ("CV_INLINE", ""),
+ ("CV_DEPRECATED", ""), ("CV_DEPRECATED_EXTERNAL", "")]).strip()
+
+
+ if decl_str.strip().startswith('virtual'):
+ virtual_method = True
+
+ decl_str = decl_str.replace('virtual' , '')
+
+ end_tokens = decl_str[decl_str.rfind(')'):].split()
+ const_method = 'const' in end_tokens
+ pure_virtual_method = '=' in end_tokens and '0' in end_tokens
static_method = False
context = top[0]
@@ -447,8 +476,15 @@ class CppHeaderParser(object):
# constructor/destructor case
if bool(re.match(r'^(\w+::)*(?P<x>\w+)::~?(?P=x)$', decl_start)):
decl_start = "void " + decl_start
+
rettype, funcname, modlist, argno = self.parse_arg(decl_start, -1)
+ # determine original return type, hack for return types with underscore
+ original_type = None
+ i = decl_start.rfind(funcname)
+ if i > 0:
+ original_type = decl_start[:i].replace("&", "").replace("const", "").strip()
+
if argno >= 0:
classname = top[1]
if rettype == classname or rettype == "~" + classname:
@@ -480,7 +516,7 @@ class CppHeaderParser(object):
funcname = self.get_dotted_name(funcname)
if not self.wrap_mode:
- decl = self.parse_func_decl_no_wrap(decl_str, static_method, comment)
+ decl = self.parse_func_decl_no_wrap(decl_str, static_method, docstring)
decl[0] = funcname
return decl
@@ -535,40 +571,50 @@ class CppHeaderParser(object):
a = a[:eqpos].strip()
arg_type, arg_name, modlist, argno = self.parse_arg(a, argno)
if self.wrap_mode:
+ mat = "UMat" if use_umat else "Mat"
+
+ # TODO: Vectors should contain UMat, but this is not very easy to support and not very needed
+ vector_mat = "vector_{}".format("Mat")
+ vector_mat_template = "vector<{}>".format("Mat")
+
if arg_type == "InputArray":
- arg_type = "Mat"
+ arg_type = mat
elif arg_type == "InputOutputArray":
- arg_type = "Mat"
+ arg_type = mat
modlist.append("/IO")
elif arg_type == "OutputArray":
- arg_type = "Mat"
+ arg_type = mat
modlist.append("/O")
elif arg_type == "InputArrayOfArrays":
- arg_type = "vector_Mat"
+ arg_type = vector_mat
elif arg_type == "InputOutputArrayOfArrays":
- arg_type = "vector_Mat"
+ arg_type = vector_mat
modlist.append("/IO")
elif arg_type == "OutputArrayOfArrays":
- arg_type = "vector_Mat"
+ arg_type = vector_mat
modlist.append("/O")
- defval = self.batch_replace(defval, [("InputArrayOfArrays", "vector<Mat>"),
- ("InputOutputArrayOfArrays", "vector<Mat>"),
- ("OutputArrayOfArrays", "vector<Mat>"),
- ("InputArray", "Mat"),
- ("InputOutputArray", "Mat"),
- ("OutputArray", "Mat"),
+ defval = self.batch_replace(defval, [("InputArrayOfArrays", vector_mat_template),
+ ("InputOutputArrayOfArrays", vector_mat_template),
+ ("OutputArrayOfArrays", vector_mat_template),
+ ("InputArray", mat),
+ ("InputOutputArray", mat),
+ ("OutputArray", mat),
("noArray", arg_type)]).strip()
args.append([arg_type, arg_name, defval, modlist])
npos = arg_start-1
if static_method:
func_modlist.append("/S")
- if decl_str.endswith("const"):
+ if const_method:
func_modlist.append("/C")
+ if virtual_method:
+ func_modlist.append("/V")
+ if pure_virtual_method:
+ func_modlist.append("/PV")
func_modlist.append("/NW")
- return [funcname, rettype, func_modlist, args, comment]
+ return [funcname, rettype, func_modlist, args, original_type, docstring]
def get_dotted_name(self, name):
"""
@@ -603,7 +649,7 @@ class CppHeaderParser(object):
n = "cv.Algorithm"
return n
- def parse_stmt(self, stmt, end_token, comment):
+ def parse_stmt(self, stmt, end_token, use_umat=False, docstring=""):
"""
parses the statement (ending with ';' or '}') or a block head (ending with '{')
@@ -651,7 +697,7 @@ class CppHeaderParser(object):
exit(1)
if classname.startswith("_Ipl"):
classname = classname[1:]
- decl = [stmt_type + " " + self.get_dotted_name(classname), "", modlist, [], comment]
+ decl = [stmt_type + " " + self.get_dotted_name(classname), "", modlist, [], None, docstring]
if bases:
decl[1] = ": " + ", ".join([self.get_dotted_name(b).replace(".","::") for b in bases])
return stmt_type, classname, True, decl
@@ -666,7 +712,7 @@ class CppHeaderParser(object):
exit(1)
decl = []
if ("CV_EXPORTS_W" in stmt) or ("CV_EXPORTS_AS" in stmt) or (not self.wrap_mode):# and ("CV_EXPORTS" in stmt)):
- decl = [stmt_type + " " + self.get_dotted_name(classname), "", modlist, [], comment]
+ decl = [stmt_type + " " + self.get_dotted_name(classname), "", modlist, [], None, docstring]
if bases:
decl[1] = ": " + ", ".join([self.get_dotted_name(b).replace(".","::") for b in bases])
return stmt_type, classname, True, decl
@@ -679,7 +725,6 @@ class CppHeaderParser(object):
if len(stmt_list) < 2:
stmt_list.append("<unnamed>")
return stmt_list[0], stmt_list[1], True, None
-
if stmt.startswith("extern") and "\"C\"" in stmt:
return "namespace", "", True, None
@@ -697,7 +742,7 @@ class CppHeaderParser(object):
# since we filtered off the other places where '(' can normally occur:
# - code blocks
# - function pointer typedef's
- decl = self.parse_func_decl(stmt, comment)
+ decl = self.parse_func_decl(stmt, use_umat=use_umat, docstring=docstring)
# we return parse_flag == False to prevent the parser to look inside function/method bodies
# (except for tracking the nested blocks)
return stmt_type, "", False, decl
@@ -724,7 +769,7 @@ class CppHeaderParser(object):
def find_next_token(self, s, tlist, p=0):
"""
Finds the next token from the 'tlist' in the input 's', starting from position 'p'.
- Returns the first occured token and its position, or ("", len(s)) when no token is found
+ Returns the first occurred token and its position, or ("", len(s)) when no token is found
"""
token = ""
tpos = len(s)
@@ -751,21 +796,20 @@ class CppHeaderParser(object):
# states:
SCAN = 0 # outside of a comment or preprocessor directive
COMMENT = 1 # inside a multi-line comment
- STRUCTURED_COMMENT = 2 # inside a multi-line structured comment
- DIRECTIVE = 3 # inside a multi-line preprocessor directive
+ DIRECTIVE = 2 # inside a multi-line preprocessor directive
+ DOCSTRING = 3 # inside a multi-line docstring
state = SCAN
self.block_stack = [["file", hname, True, True, None, True]]
block_head = ""
+ docstring = ""
self.lineno = 0
self.wrap_mode = wmode
- comment = ""
-
for l0 in linelist:
self.lineno += 1
- #print self.lineno
+ #print(state, self.lineno, l0)
l = l0.strip()
@@ -778,66 +822,61 @@ class CppHeaderParser(object):
state = SCAN
define = re.match(r"#define +([A-Z_][A-Z0-9_]+) +(.+)$", l)
if define:
- decls.append(["const " + define.group(1), define.group(2), [], [], comment])
+ decls.append(["const " + define.group(1), define.group(2), [], [], docstring])
continue
- if state == STRUCTURED_COMMENT:
+ if state == COMMENT:
pos = l.find("*/")
if pos < 0:
- comment += l + "\n"
continue
- comment += l[:pos]
l = l[pos+2:]
state = SCAN
- if state == COMMENT:
+ if state == DOCSTRING:
pos = l.find("*/")
if pos < 0:
+ docstring += l + "\n"
continue
+ docstring += l[:pos] + "\n"
l = l[pos+2:]
state = SCAN
+ if l.startswith('CV__'): # just ignore this lines
+ #print('IGNORE: ' + l)
+ state = SCAN
+ continue
+
if state != SCAN:
- print("Error at %d: invlid state = %d" % (self.lineno, state))
+ print("Error at %d: invalid state = %d" % (self.lineno, state))
sys.exit(-1)
while 1:
- token, pos = self.find_next_token(l, [";", "\"", "{", "}", "//!", "//", "/*!", "/**", "/*"])
+ token, pos = self.find_next_token(l, [";", "\"", "{", "}", "//", "/*"])
if not token:
block_head += " " + l
break
- if token == "//!":
- block_head += " " + l[:pos]
- comment += l[3:].strip() + "\n"
- break
-
if token == "//":
block_head += " " + l[:pos]
break
- if token == "/*!" or token == "/**":
+ if token == "/*":
block_head += " " + l[:pos]
- pos = l.find("*/", pos+3)
- if pos < 0:
- s = l[3:].strip()
- if len(s):
- comment = s + "\n"
- else:
- comment = ""
- state = STRUCTURED_COMMENT
+ end_pos = l.find("*/", pos+2)
+ if len(l) > pos + 2 and l[pos+2] == "*":
+ # '/**', it's a docstring
+ if end_pos < 0:
+ state = DOCSTRING
+ docstring = l[pos+3:] + "\n"
break
- l = l[pos+2:]
- continue
+ else:
+ docstring = l[pos+3:end_pos]
- if token == "/*":
- block_head += " " + l[:pos]
- pos = l.find("*/", pos+2)
- if pos < 0:
+ elif end_pos < 0:
state = COMMENT
break
- l = l[pos+2:]
+ l = l[end_pos+2:]
continue
if token == "\"":
@@ -857,6 +896,7 @@ class CppHeaderParser(object):
stmt = (block_head + " " + l[:pos]).strip()
stmt = " ".join(stmt.split()) # normalize the statement
+ #print(stmt)
stack_top = self.block_stack[-1]
if stmt.startswith("@"):
@@ -867,18 +907,29 @@ class CppHeaderParser(object):
if stack_top[self.PROCESS_FLAG]:
# even if stack_top[PUBLIC_SECTION] is False, we still try to process the statement,
# since it can start with "public:"
- stmt_type, name, parse_flag, decl = self.parse_stmt(stmt, token, comment)
+ docstring = docstring.strip()
+ stmt_type, name, parse_flag, decl = self.parse_stmt(stmt, token, docstring=docstring)
if decl:
if stmt_type == "enum":
for d in decl:
decls.append(d)
else:
decls.append(decl)
+
+ if self._generate_umat_decls:
+ # If function takes as one of arguments Mat or vector<Mat> - we want to create the
+ # same declaration working with UMat (this is important for T-Api access)
+ args = decl[3]
+ has_mat = len(list(filter(lambda x: x[0] in {"Mat", "vector_Mat"}, args))) > 0
+ if has_mat:
+ _, _, _, umat_decl = self.parse_stmt(stmt, token, use_umat=True, docstring=docstring)
+ decls.append(umat_decl)
+ docstring = ""
if stmt_type == "namespace":
chunks = [block[1] for block in self.block_stack if block[0] == 'namespace'] + [name]
self.namespaces.add('.'.join(chunks))
if self.comment == None:
- self.comment = comment
+ self.comment = docstring
else:
stmt_type, name, parse_flag = "block", "", False
@@ -907,6 +958,8 @@ class CppHeaderParser(object):
"""
for d in decls:
print(d[0], d[1], ";".join(d[2]))
+ # Uncomment below line to see docstrings
+ # print('"""\n' + d[5] + '\n"""')
for a in d[3]:
print(" ", a[0], a[1], a[2], end="")
if a[3]:
@@ -915,7 +968,7 @@ class CppHeaderParser(object):
print()
if __name__ == '__main__':
- parser = CppHeaderParser()
+ parser = CppHeaderParser(generate_umat_decls=True)
decls = []
for hname in opencv_hdr_list:
decls += parser.parse(hname)

merge upstream changes