def parse_func_decl()

in modules/python/src2/hdr_parser.py [0:0]


    def parse_func_decl(self, decl_str):
        """
        Parses the function or method declaration in the form:
        [([CV_EXPORTS] <rettype>) | CVAPI(rettype)]
            [~]<function_name>
            (<arg_type1> <arg_name1>[=<default_value1>] [, <arg_type2> <arg_name2>[=<default_value2>] ...])
            [const] {; | <function_body>}

        Returns the function declaration entry:
        [<func name>, <return value C-type>, <list of modifiers>, <list of arguments>] (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)):
                return []

        # ignore old API in the documentation check (for now)
        if "CVAPI(" in decl_str and self.wrap_mode:
            return []

        top = self.block_stack[-1]
        func_modlist = []

        npos = decl_str.find("CV_EXPORTS_AS")
        if npos >= 0:
            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_AS")
        if npos >= 0:
            arg, npos3 = self.get_macro_arg(decl_str, npos)
            func_modlist.append("="+arg)
            decl_str = decl_str[:npos] + decl_str[npos3+1:]

        # 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()

        static_method = False
        context = top[0]
        if decl_str.startswith("static") and (context == "class" or context == "struct"):
            decl_str = decl_str[len("static"):].lstrip()
            static_method = True

        args_begin = decl_str.find("(")
        if decl_str.startswith("CVAPI"):
            rtype_end = decl_str.find(")", args_begin+1)
            if rtype_end < 0:
                print("Error at %d. no terminating ) in CVAPI() macro: %s" % (self.lineno, decl_str))
                sys.exit(-1)
            decl_str = decl_str[args_begin+1:rtype_end] + " " + decl_str[rtype_end+1:]
            args_begin = decl_str.find("(")
        if args_begin < 0:
            print("Error at %d: no args in '%s'" % (self.lineno, decl_str))
            sys.exit(-1)

        decl_start = decl_str[:args_begin].strip()
        # handle operator () case
        if decl_start.endswith("operator"):
            args_begin = decl_str.find("(", args_begin+1)
            if args_begin < 0:
                print("Error at %d: no args in '%s'" % (self.lineno, decl_str))
                sys.exit(-1)
            decl_start = decl_str[:args_begin].strip()
            # TODO: normalize all type of operators
            if decl_start.endswith("()"):
                decl_start = decl_start[0:-2].rstrip() + " ()"

        # 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:
                rettype, funcname = "", rettype
            else:
                if bool(re.match('\w+\s+\(\*\w+\)\s*\(.*\)', decl_str)):
                    return [] # function typedef
                elif bool(re.match('\w+\s+\(\w+::\*\w+\)\s*\(.*\)', decl_str)):
                    return [] # class method typedef
                elif bool(re.match('[A-Z_]+', decl_start)):
                    return [] # it seems to be a macro instantiation
                elif "__declspec" == decl_start:
                    return []
                elif bool(re.match(r'\w+\s+\(\*\w+\)\[\d+\]', decl_str)):
                    return [] # exotic - dynamic 2d array
                else:
                    #print rettype, funcname, modlist, argno
                    print("Error at %s:%d the function/method name is missing: '%s'" % (self.hname, self.lineno, decl_start))
                    sys.exit(-1)

        if self.wrap_mode and (("::" in funcname) or funcname.startswith("~")):
            # if there is :: in function name (and this is in the header file),
            # it means, this is inline implementation of a class method.
            # Thus the function has been already declared within the class and we skip this repeated
            # declaration.
            # Also, skip the destructors, as they are always wrapped
            return []

        funcname = self.get_dotted_name(funcname)

        if not self.wrap_mode:
            decl = self.parse_func_decl_no_wrap(decl_str, static_method)
            decl[0] = funcname
            return decl

        arg_start = args_begin+1
        npos = arg_start-1
        balance = 1
        angle_balance = 0
        # scan the argument list; handle nested parentheses
        args_decls = []
        args = []
        argno = 1

        while balance > 0:
            npos += 1
            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
            if t == ">":
                angle_balance -= 1
            if t == "(":
                balance += 1
            if t == ")":
                balance -= 1

            if (t == "," and balance == 1 and angle_balance == 0) or balance == 0:
                # process next function argument
                a = decl_str[arg_start:npos].strip()
                #print "arg = ", a
                arg_start = npos+1
                if a:
                    eqpos = a.find("=")
                    defval = ""
                    modlist = []
                    if eqpos >= 0:
                        defval = a[eqpos+1:].strip()
                    else:
                        eqpos = a.find("CV_DEFAULT")
                        if eqpos >= 0:
                            defval, pos3 = self.get_macro_arg(a, eqpos)
                        else:
                            eqpos = a.find("CV_WRAP_DEFAULT")
                            if eqpos >= 0:
                                defval, pos3 = self.get_macro_arg(a, eqpos)
                    if defval == "NULL":
                        defval = "0"
                    if eqpos >= 0:
                        a = a[:eqpos].strip()
                    arg_type, arg_name, modlist, argno = self.parse_arg(a, argno)
                    if self.wrap_mode:
                        if arg_type == "InputArray":
                            arg_type = "Mat"
                        elif arg_type == "InputOutputArray":
                            arg_type = "Mat"
                            modlist.append("/IO")
                        elif arg_type == "OutputArray":
                            arg_type = "Mat"
                            modlist.append("/O")
                        elif arg_type == "InputArrayOfArrays":
                            arg_type = "vector_Mat"
                        elif arg_type == "InputOutputArrayOfArrays":
                            arg_type = "vector_Mat"
                            modlist.append("/IO")
                        elif arg_type == "OutputArrayOfArrays":
                            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"),
                                                             ("noArray", arg_type)]).strip()
                    args.append([arg_type, arg_name, defval, modlist])
                npos = arg_start-1

        if static_method:
            func_modlist.append("/S")

        if original_type is None:
            return [funcname, rettype, func_modlist, args]
        else:
            return [funcname, rettype, func_modlist, args, original_type]