mirror of
https://github.com/opencv/opencv.git
synced 2026-07-29 07:13:02 +04:00
bindings: backport generator from OpenCV 4.x
- better handling of enum arguments - less merge conflicts
This commit is contained in:
committed by
Alexander Alekhin
parent
d034ef6f27
commit
f5b58e5fc9
@@ -6,6 +6,7 @@ import os, sys, re, string, io
|
||||
# the list only for debugging. The real list, used in the real OpenCV build, is specified in CMakeLists.txt
|
||||
opencv_hdr_list = [
|
||||
"../../core/include/opencv2/core.hpp",
|
||||
"../../core/include/opencv2/core/mat.hpp",
|
||||
"../../core/include/opencv2/core/ocl.hpp",
|
||||
"../../flann/include/opencv2/flann/miniflann.hpp",
|
||||
"../../ml/include/opencv2/ml.hpp",
|
||||
@@ -32,8 +33,9 @@ original_return_type is None if the original_return_type is the same as return_v
|
||||
|
||||
class CppHeaderParser(object):
|
||||
|
||||
def __init__(self, generate_umat_decls=False):
|
||||
def __init__(self, generate_umat_decls=False, generate_gpumat_decls=False):
|
||||
self._generate_umat_decls = generate_umat_decls
|
||||
self._generate_gpumat_decls = generate_gpumat_decls
|
||||
|
||||
self.BLOCK_TYPE = 0
|
||||
self.BLOCK_NAME = 1
|
||||
@@ -375,11 +377,9 @@ class CppHeaderParser(object):
|
||||
decl[2].append("/A")
|
||||
if bool(re.match(r".*\)\s*const(\s*=\s*0)?", decl_str)):
|
||||
decl[2].append("/C")
|
||||
if "virtual" in decl_str:
|
||||
print(decl_str)
|
||||
return decl
|
||||
|
||||
def parse_func_decl(self, decl_str, use_umat=False, docstring=""):
|
||||
def parse_func_decl(self, decl_str, mat="Mat", docstring=""):
|
||||
"""
|
||||
Parses the function or method declaration in the form:
|
||||
[([CV_EXPORTS] <rettype>) | CVAPI(rettype)]
|
||||
@@ -392,8 +392,7 @@ class CppHeaderParser(object):
|
||||
"""
|
||||
|
||||
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)):
|
||||
if not (("CV_EXPORTS_AS" in decl_str) or ("CV_EXPORTS_W" in decl_str) or ("CV_WRAP" in decl_str)):
|
||||
return []
|
||||
|
||||
# ignore old API in the documentation check (for now)
|
||||
@@ -413,6 +412,16 @@ class CppHeaderParser(object):
|
||||
arg, npos3 = self.get_macro_arg(decl_str, npos)
|
||||
func_modlist.append("="+arg)
|
||||
decl_str = decl_str[:npos] + decl_str[npos3+1:]
|
||||
npos = decl_str.find("CV_WRAP_PHANTOM")
|
||||
if npos >= 0:
|
||||
decl_str, _ = self.get_macro_arg(decl_str, npos)
|
||||
func_modlist.append("/phantom")
|
||||
npos = decl_str.find("CV_WRAP_MAPPABLE")
|
||||
if npos >= 0:
|
||||
mappable, npos3 = self.get_macro_arg(decl_str, npos)
|
||||
func_modlist.append("/mappable="+mappable)
|
||||
classname = top[1]
|
||||
return ['.'.join([classname, classname]), None, func_modlist, [], None, None]
|
||||
|
||||
virtual_method = False
|
||||
pure_virtual_method = False
|
||||
@@ -526,8 +535,6 @@ class CppHeaderParser(object):
|
||||
t, npos = self.find_next_token(decl_str, ["(", ")", ",", "<", ">"], npos)
|
||||
if not t:
|
||||
print("Error: no closing ')' at %d" % (self.lineno,))
|
||||
print(decl_str)
|
||||
print(decl_str[arg_start:])
|
||||
sys.exit(-1)
|
||||
if t == "<":
|
||||
angle_balance += 1
|
||||
@@ -563,8 +570,6 @@ 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")
|
||||
@@ -629,8 +634,10 @@ class CppHeaderParser(object):
|
||||
block_type, block_name = b[self.BLOCK_TYPE], b[self.BLOCK_NAME]
|
||||
if block_type in ["file", "enum"]:
|
||||
continue
|
||||
if block_type not in ["struct", "class", "namespace"]:
|
||||
print("Error at %d: there are non-valid entries in the current block stack " % (self.lineno, self.block_stack))
|
||||
if block_type in ["enum struct", "enum class"] and block_name == name:
|
||||
continue
|
||||
if block_type not in ["struct", "class", "namespace", "enum struct", "enum class"]:
|
||||
print("Error at %d: there are non-valid entries in the current block stack %s" % (self.lineno, self.block_stack))
|
||||
sys.exit(-1)
|
||||
if block_name and (block_type == "namespace" or not qualified_name):
|
||||
n += block_name + "."
|
||||
@@ -639,7 +646,7 @@ class CppHeaderParser(object):
|
||||
n = "cv.Algorithm"
|
||||
return n
|
||||
|
||||
def parse_stmt(self, stmt, end_token, use_umat=False, docstring=""):
|
||||
def parse_stmt(self, stmt, end_token, mat="Mat", docstring=""):
|
||||
"""
|
||||
parses the statement (ending with ';' or '}') or a block head (ending with '{')
|
||||
|
||||
@@ -706,20 +713,19 @@ class CppHeaderParser(object):
|
||||
decl[1] = ": " + ", ".join([self.get_dotted_name(b).replace(".","::") for b in bases])
|
||||
return stmt_type, classname, True, decl
|
||||
|
||||
if stmt.startswith("enum"):
|
||||
return "enum", "", True, None
|
||||
|
||||
if stmt.startswith("namespace"):
|
||||
stmt_list = stmt.split()
|
||||
if stmt.startswith("enum") or stmt.startswith("namespace"):
|
||||
stmt_list = stmt.rsplit(" ", 1)
|
||||
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
|
||||
|
||||
if end_token == "}" and context == "enum":
|
||||
if end_token == "}" and context.startswith("enum"):
|
||||
decl = self.parse_enum(stmt)
|
||||
return "enum", "", False, decl
|
||||
name = stack_top[self.BLOCK_NAME]
|
||||
return context, name, False, decl
|
||||
|
||||
if end_token == ";" and stmt.startswith("typedef"):
|
||||
# TODO: handle typedef's more intelligently
|
||||
@@ -731,7 +737,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, use_umat=use_umat, docstring=docstring)
|
||||
decl = self.parse_func_decl(stmt, mat=mat, 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
|
||||
@@ -827,7 +833,7 @@ class CppHeaderParser(object):
|
||||
l = l[pos+2:]
|
||||
state = SCAN
|
||||
|
||||
if l.startswith('CV__'): # just ignore this lines
|
||||
if l.startswith('CV__') or l.startswith('__CV_'): # just ignore these lines
|
||||
#print('IGNORE: ' + l)
|
||||
state = SCAN
|
||||
continue
|
||||
@@ -841,11 +847,17 @@ class CppHeaderParser(object):
|
||||
|
||||
if not token:
|
||||
block_head += " " + l
|
||||
break
|
||||
block_head = block_head.strip()
|
||||
if len(block_head) > 0 and block_head[-1] == ')' and block_head.startswith('CV_ENUM_FLAGS('):
|
||||
l = ''
|
||||
token = ';'
|
||||
else:
|
||||
break
|
||||
|
||||
if token == "//":
|
||||
block_head += " " + l[:pos]
|
||||
break
|
||||
l = ''
|
||||
continue
|
||||
|
||||
if token == "/*":
|
||||
block_head += " " + l[:pos]
|
||||
@@ -896,20 +908,29 @@ class CppHeaderParser(object):
|
||||
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)
|
||||
if stmt_type.startswith("enum"):
|
||||
decls.append([stmt_type + " " + self.get_dotted_name(name), "", [], decl, None, ""])
|
||||
else:
|
||||
decls.append(decl)
|
||||
|
||||
if self._generate_gpumat_decls and "cv.cuda." in decl[0]:
|
||||
# If function takes as one of arguments Mat or vector<Mat> - we want to create the
|
||||
# same declaration working with GpuMat (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:
|
||||
_, _, _, gpumat_decl = self.parse_stmt(stmt, token, mat="cuda::GpuMat", docstring=docstring)
|
||||
decls.append(gpumat_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)
|
||||
_, _, _, umat_decl = self.parse_stmt(stmt, token, mat="UMat", 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]
|
||||
@@ -952,7 +973,7 @@ class CppHeaderParser(object):
|
||||
print()
|
||||
|
||||
if __name__ == '__main__':
|
||||
parser = CppHeaderParser(generate_umat_decls=True)
|
||||
parser = CppHeaderParser(generate_umat_decls=True, generate_gpumat_decls=False)
|
||||
decls = []
|
||||
for hname in opencv_hdr_list:
|
||||
decls += parser.parse(hname)
|
||||
|
||||
Reference in New Issue
Block a user