3 from __future__ import print_function
4 import os, sys, re, string, io
6 # the list only for debugging. The real list, used in the real OpenCV build, is specified in CMakeLists.txt
8 "../../core/include/opencv2/core.hpp",
9 "../../core/include/opencv2/core/mat.hpp",
10 "../../core/include/opencv2/core/ocl.hpp",
11 "../../flann/include/opencv2/flann/miniflann.hpp",
12 "../../ml/include/opencv2/ml.hpp",
13 "../../imgproc/include/opencv2/imgproc.hpp",
14 "../../calib3d/include/opencv2/calib3d.hpp",
15 "../../features2d/include/opencv2/features2d.hpp",
16 "../../video/include/opencv2/video/tracking.hpp",
17 "../../video/include/opencv2/video/background_segm.hpp",
18 "../../objdetect/include/opencv2/objdetect.hpp",
19 "../../imgcodecs/include/opencv2/imgcodecs.hpp",
20 "../../videoio/include/opencv2/videoio.hpp",
21 "../../highgui/include/opencv2/highgui.hpp",
25 Each declaration is [funcname, return_value_type /* in C, not in Python */, <list_of_modifiers>, <list_of_arguments>, original_return_type, docstring],
26 where each element of <list_of_arguments> is 4-element list itself:
27 [argtype, argname, default_value /* or "" if none */, <list_of_modifiers>]
28 where the list of modifiers is yet another nested list of strings
29 (currently recognized are "/O" for output argument, "/S" for static (i.e. class) methods
30 and "/A value" for the plain C arrays with counters)
31 original_return_type is None if the original_return_type is the same as return_value_type
34 class CppHeaderParser(object):
36 def __init__(self, generate_umat_decls=False, generate_gpumat_decls=False):
37 self._generate_umat_decls = generate_umat_decls
38 self._generate_gpumat_decls = generate_gpumat_decls
43 self.PUBLIC_SECTION = 3
46 self.namespaces = set()
48 def batch_replace(self, s, pairs):
49 for before, after in pairs:
50 s = s.replace(before, after)
53 def get_macro_arg(self, arg_str, npos):
54 npos2 = npos3 = arg_str.find("(", npos)
56 print("Error: no arguments for the macro at %d" % (self.lineno,))
60 t, npos3 = self.find_next_token(arg_str, ['(', ')'], npos3+1)
62 print("Error: no matching ')' in the macro call at %d" % (self.lineno,))
71 return arg_str[npos2+1:npos3].strip(), npos3
73 def parse_arg(self, arg_str, argno):
75 Parses <arg_type> [arg_name]
76 Returns arg_type, arg_name, modlist, argno, where
77 modlist is the list of wrapper-related modifiers (such as "output argument", "has counter", ...)
78 and argno is the new index of an anonymous argument.
79 That is, if no arg_str is just an argument type without argument name, the argument name is set to
80 "arg" + str(argno), and then argno is incremented.
84 # pass 0: extracts the modifiers
85 if "CV_OUT" in arg_str:
87 arg_str = arg_str.replace("CV_OUT", "")
89 if "CV_IN_OUT" in arg_str:
91 arg_str = arg_str.replace("CV_IN_OUT", "")
94 npos = arg_str.find("CV_CARRAY")
97 macro_arg, npos3 = self.get_macro_arg(arg_str, npos)
99 modlist.append("/A " + macro_arg)
100 arg_str = arg_str[:npos] + arg_str[npos3+1:]
102 npos = arg_str.find("CV_CUSTOM_CARRAY")
105 macro_arg, npos3 = self.get_macro_arg(arg_str, npos)
107 modlist.append("/CA " + macro_arg)
108 arg_str = arg_str[:npos] + arg_str[npos3+1:]
110 npos = arg_str.find("const")
114 npos = arg_str.find("&&")
116 arg_str = arg_str.replace("&&", '')
117 modlist.append("/RRef")
119 npos = arg_str.find("&")
121 modlist.append("/Ref")
123 arg_str = arg_str.strip()
128 #print self.lineno, ":\t", arg_str
130 # pass 1: split argument type into tokens
133 t, npos = self.find_next_token(arg_str, [" ", "&", "*", "<", ">", ","], npos)
134 w = arg_str[word_start:npos].strip()
136 word_list.append("operator " + arg_str[npos:].strip())
138 if w not in ["", "const"]:
140 if t not in ["", " ", "&"]:
145 npos = word_start - 1
151 #print self.lineno, ":\t", word_list
153 # pass 2: decrypt the list
159 if prev_w == "char" and not isarray:
160 arg_type = arg_type[:-len("char")] + "c_string"
166 angle_stack.append(0)
167 elif w == "," or w == '>':
169 print("Error at %d: argument contains ',' or '>' not within template arguments" % (self.lineno,))
174 if angle_stack[0] == 0:
175 print("Error at %s:%d: template has no arguments" % (self.hname, self.lineno))
177 if angle_stack[0] > 1:
179 angle_stack[-1:] = []
183 elif arg_type == "struct":
185 elif arg_type and arg_type != "~":
186 arg_name = " ".join(word_list[wi:])
194 if ("[" in arg_name) and not ("operator" in arg_str):
196 p1 = arg_name.find("[")
197 p2 = arg_name.find("]",p1+1)
199 print("Error at %d: no closing ]" % (self.lineno,))
201 counter_str = arg_name[p1+1:p2].strip()
202 if counter_str == "":
205 modlist.append("/A " + counter_str.strip())
206 arg_name = arg_name[:p1]
210 if arg_type.startswith("operator"):
211 arg_type, arg_name = "", arg_type
213 arg_name = "arg" + str(argno)
216 while arg_type.endswith("_end_"):
217 arg_type = arg_type[:-len("_end_")]
222 arg_type = self.batch_replace(arg_type, [("std::", ""), ("cv::", ""), ("::", "_")])
224 return arg_type, arg_name, modlist, argno
226 def parse_enum(self, decl_str):
229 if ll[-1].strip() == "":
241 val += str(prev_val_delta)
244 prev_val = val = pv[1].strip()
245 decl.append(["const " + self.get_dotted_name(pv[0].strip()), val, [], [], None, ""])
248 def parse_class_decl(self, decl_str):
250 Parses class/struct declaration start in the form:
251 {class|struct} [CV_EXPORTS] <class_name> [: public <base_class1> [, ...]]
252 Returns class_name1, <list of base_classes>
256 if "CV_EXPORTS_W_MAP" in l:
257 l = l.replace("CV_EXPORTS_W_MAP", "")
258 modlist.append("/Map")
259 if "CV_EXPORTS_W_SIMPLE" in l:
260 l = l.replace("CV_EXPORTS_W_SIMPLE", "")
261 modlist.append("/Simple")
262 npos = l.find("CV_EXPORTS_AS")
264 npos = l.find('CV_WRAP_AS')
266 macro_arg, npos3 = self.get_macro_arg(l, npos)
267 modlist.append("=" + macro_arg)
268 l = l[:npos] + l[npos3+1:]
270 l = self.batch_replace(l, [("CV_EXPORTS_W", ""), ("CV_EXPORTS", ""), ("public virtual ", " "), ("public ", " "), ("::", ".")]).strip()
271 ll = re.split(r'\s+|\s*[,:]\s*', l)
272 ll = [le for le in ll if le]
275 return classname, bases, modlist
277 def parse_func_decl_no_wrap(self, decl_str, static_method=False, docstring=""):
278 decl_str = (decl_str or "").strip()
279 virtual_method = False
280 explicit_method = False
281 if decl_str.startswith("explicit"):
282 decl_str = decl_str[len("explicit"):].lstrip()
283 explicit_method = True
284 if decl_str.startswith("virtual"):
285 decl_str = decl_str[len("virtual"):].lstrip()
286 virtual_method = True
287 if decl_str.startswith("static"):
288 decl_str = decl_str[len("static"):].lstrip()
291 fdecl = decl_str.replace("CV_OUT", "").replace("CV_IN_OUT", "")
292 fdecl = fdecl.strip().replace("\t", " ")
294 fdecl = fdecl.replace(" ", " ")
295 fname = fdecl[:fdecl.find("(")].strip()
296 fnpos = fname.rfind(" ")
299 fname = fname[fnpos:].strip()
300 rettype = fdecl[:fnpos].strip()
302 if rettype.endswith("operator"):
303 fname = ("operator " + fname).strip()
304 rettype = rettype[:rettype.rfind("operator")].strip()
305 if rettype.endswith("::"):
306 rpos = rettype.rfind(" ")
308 fname = rettype[rpos+1:].strip() + fname
309 rettype = rettype[:rpos].strip()
311 fname = rettype + fname
314 apos = fdecl.find("(")
315 if fname.endswith("operator"):
317 apos = fdecl.find("(", apos+1)
319 fname = "cv." + fname.replace("::", ".")
320 decl = [fname, rettype, [], [], None, docstring]
322 # inline constructor implementation
323 implmatch = re.match(r"(\(.*?\))\s*:\s*(\w+\(.*?\),?\s*)+", fdecl[apos:])
325 fdecl = fdecl[:apos] + implmatch.group(1)
327 args0str = fdecl[apos+1:fdecl.rfind(")")].strip()
329 if args0str != "" and args0str != "void":
330 args0str = re.sub(r"\([^)]*\)", lambda m: m.group(0).replace(',', "@comma@"), args0str)
331 args0 = args0str.split(",")
337 balance_paren = narg.count("(") - narg.count(")")
338 balance_angle = narg.count("<") - narg.count(">")
339 if balance_paren == 0 and balance_angle == 0:
340 args.append(narg.strip())
344 dfpos = arg.find("=")
347 defval = arg[dfpos+1:].strip()
349 dfpos = arg.find("CV_DEFAULT")
351 defval, pos3 = self.get_macro_arg(arg, dfpos)
353 dfpos = arg.find("CV_WRAP_DEFAULT")
355 defval, pos3 = self.get_macro_arg(arg, dfpos)
357 defval = defval.replace("@comma@", ",")
358 arg = arg[:dfpos].strip()
360 while pos >= 0 and (arg[pos] in "_[]" or arg[pos].isalpha() or arg[pos].isdigit()):
363 aname = arg[pos+1:].strip()
364 atype = arg[:pos+1].strip()
365 if aname.endswith("&") or aname.endswith("*") or (aname in ["int", "String", "Mat"]):
366 atype = (atype + " " + aname).strip()
371 if aname.endswith("]"):
372 bidx = aname.find('[')
373 atype += aname[bidx:]
375 decl[3].append([atype, aname, defval, []])
383 if bool(re.match(r".*\)\s*(const)?\s*=\s*0", decl_str)):
385 if bool(re.match(r".*\)\s*const(\s*=\s*0)?", decl_str)):
389 def parse_func_decl(self, decl_str, mat="Mat", docstring=""):
391 Parses the function or method declaration in the form:
392 [([CV_EXPORTS] <rettype>) | CVAPI(rettype)]
394 (<arg_type1> <arg_name1>[=<default_value1>] [, <arg_type2> <arg_name2>[=<default_value2>] ...])
395 [const] {; | <function_body>}
397 Returns the function declaration entry:
398 [<func name>, <return value C-type>, <list of modifiers>, <list of arguments>, <original return type>, <docstring>] (see above)
402 if not (("CV_EXPORTS_AS" in decl_str) or ("CV_EXPORTS_W" in decl_str) or ("CV_WRAP" in decl_str)):
405 # ignore old API in the documentation check (for now)
406 if "CVAPI(" in decl_str and self.wrap_mode:
409 top = self.block_stack[-1]
412 npos = decl_str.find("CV_EXPORTS_AS")
414 arg, npos3 = self.get_macro_arg(decl_str, npos)
415 func_modlist.append("="+arg)
416 decl_str = decl_str[:npos] + decl_str[npos3+1:]
417 npos = decl_str.find("CV_WRAP_AS")
419 arg, npos3 = self.get_macro_arg(decl_str, npos)
420 func_modlist.append("="+arg)
421 decl_str = decl_str[:npos] + decl_str[npos3+1:]
422 npos = decl_str.find("CV_WRAP_PHANTOM")
424 decl_str, _ = self.get_macro_arg(decl_str, npos)
425 func_modlist.append("/phantom")
426 npos = decl_str.find("CV_WRAP_MAPPABLE")
428 mappable, npos3 = self.get_macro_arg(decl_str, npos)
429 func_modlist.append("/mappable="+mappable)
431 return ['.'.join([classname, classname]), None, func_modlist, [], None, None]
433 virtual_method = False
434 pure_virtual_method = False
437 # filter off some common prefixes, which are meaningless for Python wrappers.
438 # note that we do not strip "static" prefix, which does matter;
439 # it means class methods, not instance methods
440 decl_str = self.batch_replace(decl_str, [("static inline", ""), ("inline", ""), ("explicit ", ""),
441 ("CV_EXPORTS_W", ""), ("CV_EXPORTS", ""), ("CV_CDECL", ""),
442 ("CV_WRAP ", " "), ("CV_INLINE", ""),
443 ("CV_DEPRECATED", ""), ("CV_DEPRECATED_EXTERNAL", "")]).strip()
446 if decl_str.strip().startswith('virtual'):
447 virtual_method = True
449 decl_str = decl_str.replace('virtual' , '')
451 end_tokens = decl_str[decl_str.rfind(')'):].split()
452 const_method = 'const' in end_tokens
453 pure_virtual_method = '=' in end_tokens and '0' in end_tokens
455 static_method = False
457 if decl_str.startswith("static") and (context == "class" or context == "struct"):
458 decl_str = decl_str[len("static"):].lstrip()
461 args_begin = decl_str.find("(")
462 if decl_str.startswith("CVAPI"):
463 rtype_end = decl_str.find(")", args_begin+1)
465 print("Error at %d. no terminating ) in CVAPI() macro: %s" % (self.lineno, decl_str))
467 decl_str = decl_str[args_begin+1:rtype_end] + " " + decl_str[rtype_end+1:]
468 args_begin = decl_str.find("(")
470 print("Error at %d: no args in '%s'" % (self.lineno, decl_str))
473 decl_start = decl_str[:args_begin].strip()
474 # handle operator () case
475 if decl_start.endswith("operator"):
476 args_begin = decl_str.find("(", args_begin+1)
478 print("Error at %d: no args in '%s'" % (self.lineno, decl_str))
480 decl_start = decl_str[:args_begin].strip()
481 # TODO: normalize all type of operators
482 if decl_start.endswith("()"):
483 decl_start = decl_start[0:-2].rstrip() + " ()"
485 # constructor/destructor case
486 if bool(re.match(r'^(\w+::)*(?P<x>\w+)::~?(?P=x)$', decl_start)):
487 decl_start = "void " + decl_start
489 rettype, funcname, modlist, argno = self.parse_arg(decl_start, -1)
491 # determine original return type, hack for return types with underscore
493 i = decl_start.rfind(funcname)
495 original_type = decl_start[:i].replace("&", "").replace("const", "").strip()
499 if rettype == classname or rettype == "~" + classname:
500 rettype, funcname = "", rettype
502 if bool(re.match('\w+\s+\(\*\w+\)\s*\(.*\)', decl_str)):
503 return [] # function typedef
504 elif bool(re.match('\w+\s+\(\w+::\*\w+\)\s*\(.*\)', decl_str)):
505 return [] # class method typedef
506 elif bool(re.match('[A-Z_]+', decl_start)):
507 return [] # it seems to be a macro instantiation
508 elif "__declspec" == decl_start:
510 elif bool(re.match(r'\w+\s+\(\*\w+\)\[\d+\]', decl_str)):
511 return [] # exotic - dynamic 2d array
513 #print rettype, funcname, modlist, argno
514 print("Error at %s:%d the function/method name is missing: '%s'" % (self.hname, self.lineno, decl_start))
517 if self.wrap_mode and (("::" in funcname) or funcname.startswith("~")):
518 # if there is :: in function name (and this is in the header file),
519 # it means, this is inline implementation of a class method.
520 # Thus the function has been already declared within the class and we skip this repeated
522 # Also, skip the destructors, as they are always wrapped
525 funcname = self.get_dotted_name(funcname)
527 if not self.wrap_mode:
528 decl = self.parse_func_decl_no_wrap(decl_str, static_method, docstring)
532 arg_start = args_begin+1
536 # scan the argument list; handle nested parentheses
543 t, npos = self.find_next_token(decl_str, ["(", ")", ",", "<", ">"], npos)
545 print("Error: no closing ')' at %d" % (self.lineno,))
556 if (t == "," and balance == 1 and angle_balance == 0) or balance == 0:
557 # process next function argument
558 a = decl_str[arg_start:npos].strip()
566 defval = a[eqpos+1:].strip()
568 eqpos = a.find("CV_DEFAULT")
570 defval, pos3 = self.get_macro_arg(a, eqpos)
572 eqpos = a.find("CV_WRAP_DEFAULT")
574 defval, pos3 = self.get_macro_arg(a, eqpos)
578 a = a[:eqpos].strip()
579 arg_type, arg_name, modlist, argno = self.parse_arg(a, argno)
581 # TODO: Vectors should contain UMat, but this is not very easy to support and not very needed
582 vector_mat = "vector_{}".format(mat)
583 vector_mat_template = "vector<{}>".format(mat)
585 if arg_type == "InputArray":
587 elif arg_type == "InputOutputArray":
589 modlist.append("/IO")
590 elif arg_type == "OutputArray":
593 elif arg_type == "InputArrayOfArrays":
594 arg_type = vector_mat
595 elif arg_type == "InputOutputArrayOfArrays":
596 arg_type = vector_mat
597 modlist.append("/IO")
598 elif arg_type == "OutputArrayOfArrays":
599 arg_type = vector_mat
601 defval = self.batch_replace(defval, [("InputArrayOfArrays", vector_mat_template),
602 ("InputOutputArrayOfArrays", vector_mat_template),
603 ("OutputArrayOfArrays", vector_mat_template),
605 ("InputOutputArray", mat),
606 ("OutputArray", mat),
607 ("noArray", arg_type)]).strip()
608 args.append([arg_type, arg_name, defval, modlist])
612 func_modlist.append("/S")
614 func_modlist.append("/C")
616 func_modlist.append("/V")
617 if pure_virtual_method:
618 func_modlist.append("/PV")
620 return [funcname, rettype, func_modlist, args, original_type, docstring]
622 def get_dotted_name(self, name):
624 adds the dot-separated container class/namespace names to the bare function/class name, e.g. when we have
633 the function will convert "A" to "cv.A" and "f" to "cv.A.f".
635 if not self.block_stack:
637 if name.startswith("cv."):
639 qualified_name = (("." in name) or ("::" in name))
641 for b in self.block_stack:
642 block_type, block_name = b[self.BLOCK_TYPE], b[self.BLOCK_NAME]
643 if block_type in ["file", "enum"]:
645 if block_type in ["enum struct", "enum class"] and block_name == name:
647 if block_type not in ["struct", "class", "namespace", "enum struct", "enum class"]:
648 print("Error at %d: there are non-valid entries in the current block stack %s" % (self.lineno, self.block_stack))
650 if block_name and (block_type == "namespace" or not qualified_name):
651 n += block_name + "."
652 n += name.replace("::", ".")
653 if n.endswith(".Algorithm"):
657 def parse_stmt(self, stmt, end_token, mat="Mat", docstring=""):
659 parses the statement (ending with ';' or '}') or a block head (ending with '{')
661 The function calls parse_class_decl or parse_func_decl when necessary. It returns
662 <block_type>, <block_name>, <parse_flag>, <declaration>
663 where the first 3 values only make sense for blocks (i.e. code blocks, namespaces, classes, enums and such)
665 stack_top = self.block_stack[-1]
666 context = stack_top[self.BLOCK_TYPE]
668 if stmt.startswith('inline namespace'):
669 # emulate anonymous namespace
670 return "namespace", "", True, None
676 if context == "block":
677 print("Error at %d: should not call parse_stmt inside blocks" % (self.lineno,))
680 if context == "class" or context == "struct":
682 colon_pos = stmt.find(":")
685 w = stmt[:colon_pos].strip()
686 if w in ["public", "protected", "private"]:
687 if w == "public" or (not self.wrap_mode and w == "protected"):
688 stack_top[self.PUBLIC_SECTION] = True
690 stack_top[self.PUBLIC_SECTION] = False
691 stmt = stmt[colon_pos+1:].strip()
694 # do not process hidden class members and template classes/functions
695 if not stack_top[self.PUBLIC_SECTION] or stmt.startswith("template"):
696 return stmt_type, "", False, None
699 if not self.wrap_mode and stmt.startswith("typedef struct"):
702 classname, bases, modlist = self.parse_class_decl(stmt[len("typedef "):])
704 print("Error at %s:%d" % (self.hname, self.lineno))
706 if classname.startswith("_Ipl"):
707 classname = classname[1:]
708 decl = [stmt_type + " " + self.get_dotted_name(classname), "", modlist, [], None, docstring]
710 decl[1] = ": " + ", ".join([self.get_dotted_name(b).replace(".","::") for b in bases])
711 return stmt_type, classname, True, decl
713 if stmt.startswith("class") or stmt.startswith("struct"):
714 stmt_type = stmt.split()[0]
715 if stmt.strip() != stmt_type:
717 classname, bases, modlist = self.parse_class_decl(stmt)
719 print("Error at %s:%d" % (self.hname, self.lineno))
722 if ("CV_EXPORTS_W" in stmt) or ("CV_EXPORTS_AS" in stmt) or (not self.wrap_mode):# and ("CV_EXPORTS" in stmt)):
723 decl = [stmt_type + " " + self.get_dotted_name(classname), "", modlist, [], None, docstring]
725 decl[1] = ": " + ", ".join([self.get_dotted_name(b).replace(".","::") for b in bases])
726 return stmt_type, classname, True, decl
728 if stmt.startswith("enum") or stmt.startswith("namespace"):
729 # NB: Drop inheritance syntax for enum
730 stmt = stmt.split(':')[0]
731 stmt_list = stmt.rsplit(" ", 1)
732 if len(stmt_list) < 2:
733 stmt_list.append("<unnamed>")
734 return stmt_list[0], stmt_list[1], True, None
736 if stmt.startswith("extern") and "\"C\"" in stmt:
737 return "namespace", "", True, None
739 if end_token == "}" and context.startswith("enum"):
740 decl = self.parse_enum(stmt)
741 name = stack_top[self.BLOCK_NAME]
742 return context, name, False, decl
744 if end_token == ";" and stmt.startswith("typedef"):
745 # TODO: handle typedef's more intelligently
746 return stmt_type, "", False, None
748 paren_pos = stmt.find("(")
750 # assume it's function or method declaration,
751 # since we filtered off the other places where '(' can normally occur:
753 # - function pointer typedef's
754 decl = self.parse_func_decl(stmt, mat=mat, docstring=docstring)
755 # we return parse_flag == False to prevent the parser to look inside function/method bodies
756 # (except for tracking the nested blocks)
757 return stmt_type, "", False, decl
759 if (context == "struct" or context == "class") and end_token == ";" and stmt:
760 # looks like it's member declaration; append the members to the class declaration
761 class_decl = stack_top[self.CLASS_DECL]
762 if ("CV_PROP" in stmt): # or (class_decl and ("/Map" in class_decl[2])):
764 if "CV_PROP_RW" in stmt:
765 var_modlist.append("/RW")
766 stmt = self.batch_replace(stmt, [("CV_PROP_RW", ""), ("CV_PROP", "")]).strip()
767 var_list = stmt.split(",")
768 var_type, var_name1, modlist, argno = self.parse_arg(var_list[0], -1)
769 var_list = [var_name1] + [i.strip() for i in var_list[1:]]
772 class_decl[3].append([var_type, v, "", var_modlist])
773 return stmt_type, "", False, None
776 return stmt_type, "", False, None
778 def find_next_token(self, s, tlist, p=0):
780 Finds the next token from the 'tlist' in the input 's', starting from position 'p'.
781 Returns the first occurred token and its position, or ("", len(s)) when no token is found
794 def parse(self, hname, wmode=True):
796 The main method. Parses the input file.
797 Returns the list of declarations (that can be print using print_decls)
801 f = io.open(hname, 'rt', encoding='utf-8')
802 linelist = list(f.readlines())
806 SCAN = 0 # outside of a comment or preprocessor directive
807 COMMENT = 1 # inside a multi-line comment
808 DIRECTIVE = 2 # inside a multi-line preprocessor directive
809 DOCSTRING = 3 # inside a multi-line docstring
810 DIRECTIVE_IF_0 = 4 # inside a '#if 0' directive
814 self.block_stack = [["file", hname, True, True, None]]
818 self.wrap_mode = wmode
824 #print(state, self.lineno, l0)
828 # G-API specific aliases
829 l = self.batch_replace(l, [
830 ("GAPI_EXPORTS", "CV_EXPORTS"),
831 ("GAPI_EXPORTS_W", "CV_EXPORTS_W"),
832 ("GAPI_EXPORTS_W_SIMPLE","CV_EXPORTS_W_SIMPLE"),
833 ("GAPI_WRAP", "CV_WRAP"),
834 ("GAPI_PROP", "CV_PROP"),
835 ('defined(GAPI_STANDALONE)', '0'),
838 if state == SCAN and l.startswith("#"):
840 # fall through to the if state == DIRECTIVE check
842 if state == DIRECTIVE:
846 l = re.sub(r'//(.+)?', '', l).strip() # drop // comment
849 '#if defined(__OPENCV_BUILD)', '#ifdef __OPENCV_BUILD',
850 '#if !defined(OPENCV_BINDING_PARSER)', '#ifndef OPENCV_BINDING_PARSER',
852 state = DIRECTIVE_IF_0
856 if state == DIRECTIVE_IF_0:
857 if l.startswith('#'):
859 if l.startswith("if"):
862 if l.startswith("endif"):
867 # print('---- {:30s}:{:5d}: {}'.format(hname[-30:], self.lineno, l))
878 if state == DOCSTRING:
883 docstring += l[:pos] + "\n"
887 if l.startswith('CV__') or l.startswith('__CV_'): # just ignore these lines
888 #print('IGNORE: ' + l)
893 print("Error at %d: invalid state = %d" % (self.lineno, state))
897 # NB: Avoid parsing '{' for case:
899 if re.search(r'=\s*\{\s*\}', l):
900 token, pos = ';', len(l)
902 token, pos = self.find_next_token(l, [";", "\"", "{", "}", "//", "/*"])
905 block_head += " " + l
906 block_head = block_head.strip()
907 if len(block_head) > 0 and block_head[-1] == ')' and block_head.startswith('CV_ENUM_FLAGS('):
914 block_head += " " + l[:pos]
919 block_head += " " + l[:pos]
920 end_pos = l.find("*/", pos+2)
921 if len(l) > pos + 2 and l[pos+2] == "*":
922 # '/**', it's a docstring
925 docstring = l[pos+3:] + "\n"
928 docstring = l[pos+3:end_pos]
939 t2, pos2 = self.find_next_token(l, ["\\", "\""], pos2)
941 print("Error at %d: no terminating '\"'" % (self.lineno,))
947 block_head += " " + l[:pos2+1]
951 stmt = (block_head + " " + l[:pos]).strip()
952 stmt = " ".join(stmt.split()) # normalize the statement
954 stack_top = self.block_stack[-1]
956 if stmt.startswith("@"):
961 if stack_top[self.PROCESS_FLAG]:
962 # even if stack_top[PUBLIC_SECTION] is False, we still try to process the statement,
963 # since it can start with "public:"
964 docstring = docstring.strip()
965 stmt_type, name, parse_flag, decl = self.parse_stmt(stmt, token, docstring=docstring)
967 if stmt_type.startswith("enum"):
968 decls.append([stmt_type + " " + self.get_dotted_name(name), "", [], decl, None, ""])
972 if self._generate_gpumat_decls and ("cv.cuda" in decl[0] or decl[0] in [
973 "cv.imshow", # https://github.com/opencv/opencv/issues/18553
975 # If function takes as one of arguments Mat or vector<Mat> - we want to create the
976 # same declaration working with GpuMat
978 has_mat = len(list(filter(lambda x: x[0] in {"Mat", "vector_Mat"}, args))) > 0
980 _, _, _, gpumat_decl = self.parse_stmt(stmt, token, mat="cuda::GpuMat", docstring=docstring)
981 decls.append(gpumat_decl)
983 if self._generate_umat_decls:
984 # If function takes as one of arguments Mat or vector<Mat> - we want to create the
985 # same declaration working with UMat (this is important for T-Api access)
987 has_mat = len(list(filter(lambda x: x[0] in {"Mat", "vector_Mat"}, args))) > 0
989 _, _, _, umat_decl = self.parse_stmt(stmt, token, mat="UMat", docstring=docstring)
990 decls.append(umat_decl)
993 if stmt_type == "namespace":
994 chunks = [block[1] for block in self.block_stack if block[0] == 'namespace'] + [name]
995 self.namespaces.add('.'.join(chunks))
997 stmt_type, name, parse_flag = "block", "", False
1000 if stmt_type == "class":
1001 public_section = False
1003 public_section = True
1004 self.block_stack.append([stmt_type, name, parse_flag, public_section, decl])
1007 if not self.block_stack:
1008 print("Error at %d: the block stack is empty" % (self.lineno,))
1009 self.block_stack[-1:] = []
1010 if pos+1 < len(l) and l[pos+1] == ';':
1018 def print_decls(self, decls):
1020 Prints the list of declarations, retrieived by the parse() method
1023 print(d[0], d[1], ";".join(d[2]))
1024 # Uncomment below line to see docstrings
1025 # print('"""\n' + d[5] + '\n"""')
1027 print(" ", a[0], a[1], a[2], end="")
1029 print("; ".join(a[3]))
1033 if __name__ == '__main__':
1034 parser = CppHeaderParser(generate_umat_decls=True, generate_gpumat_decls=True)
1036 for hname in opencv_hdr_list:
1037 decls += parser.parse(hname)
1038 #for hname in sys.argv[1:]:
1039 #decls += parser.parse(hname, wmode=False)
1040 parser.print_decls(decls)
1042 print("namespaces:", " ".join(sorted(parser.namespaces)))