56 Parses <arg_type> [arg_name]
57 Returns arg_type, arg_name, modlist, argno, where
58 modlist is the list of wrapper-related modifiers (such as "output argument", "has counter", ...)
59 and argno is the new index of an anonymous argument.
60 That is, if no arg_str is just an argument type without argument name, the argument name is set to
61 "arg" + str(argno), and then argno is incremented.
66 if "CV_OUT" in arg_str:
68 arg_str = arg_str.replace(
"CV_OUT",
"")
70 if "CV_IN_OUT" in arg_str:
72 arg_str = arg_str.replace(
"CV_IN_OUT",
"")
75 npos = arg_str.find(
"CV_CARRAY")
80 modlist.append(
"/A " + macro_arg)
81 arg_str = arg_str[:npos] + arg_str[npos3 + 1:]
83 npos = arg_str.find(
"CV_CUSTOM_CARRAY")
88 modlist.append(
"/CA " + macro_arg)
89 arg_str = arg_str[:npos] + arg_str[npos3 + 1:]
91 npos = arg_str.find(
"const")
95 npos = arg_str.find(
"&")
97 modlist.append(
"/Ref")
99 arg_str = arg_str.strip()
109 t, npos = self.
find_next_token(arg_str, [
" ",
"&",
"*",
"<",
">",
","], npos)
110 w = arg_str[word_start:npos].strip()
112 word_list.append(
"operator " + arg_str[npos:].strip())
114 if w
not in [
"",
"const"]:
116 if t
not in [
"",
" ",
"&"]:
120 word_start = npos + 1
121 npos = word_start - 1
135 if prev_w ==
"char" and not isarray:
136 arg_type = arg_type[:-len(
"char")] +
"c_string"
142 angle_stack.append(0)
143 elif w ==
"," or w ==
'>':
145 print(
"Error at %d: argument contains ',' or '>' not within template arguments" % (self.
lineno,))
150 if angle_stack[0] == 0:
151 print(
"Error at %s:%d: template has no arguments" % (self.
hname, self.
lineno))
153 if angle_stack[0] > 1:
155 angle_stack[-1:] = []
159 elif arg_type ==
"struct":
161 elif arg_type
and arg_type !=
"~":
162 arg_name =
" ".join(word_list[wi:])
170 if (
"[" in arg_name)
and not (
"operator" in arg_str):
172 p1 = arg_name.find(
"[")
173 p2 = arg_name.find(
"]", p1 + 1)
175 print(
"Error at %d: no closing ]" % (self.
lineno,))
177 counter_str = arg_name[p1 + 1:p2].strip()
178 if counter_str ==
"":
181 modlist.append(
"/A " + counter_str.strip())
182 arg_name = arg_name[:p1]
186 if arg_type.startswith(
"operator"):
187 arg_type, arg_name =
"", arg_type
189 arg_name =
"arg" + str(argno)
192 while arg_type.endswith(
"_end_"):
193 arg_type = arg_type[:-len(
"_end_")]
198 arg_type = self.
batch_replace(arg_type, [(
"std::",
""), (
"cv::",
""), (
"::",
"_")])
200 return arg_type, arg_name, modlist, argno
253 decl_str = (decl_str
or "").strip()
254 virtual_method =
False
255 explicit_method =
False
256 if decl_str.startswith(
"explicit"):
257 decl_str = decl_str[len(
"explicit"):].lstrip()
258 explicit_method =
True
259 if decl_str.startswith(
"virtual"):
260 decl_str = decl_str[len(
"virtual"):].lstrip()
261 virtual_method =
True
262 if decl_str.startswith(
"static"):
263 decl_str = decl_str[len(
"static"):].lstrip()
266 fdecl = decl_str.replace(
"CV_OUT",
"").replace(
"CV_IN_OUT",
"")
267 fdecl = fdecl.strip().replace(
"\t",
" ")
269 fdecl = fdecl.replace(
" ",
" ")
270 fname = fdecl[:fdecl.find(
"(")].strip()
271 fnpos = fname.rfind(
" ")
274 fname = fname[fnpos:].strip()
275 rettype = fdecl[:fnpos].strip()
277 if rettype.endswith(
"operator"):
278 fname = (
"operator " + fname).strip()
279 rettype = rettype[:rettype.rfind(
"operator")].strip()
280 if rettype.endswith(
"::"):
281 rpos = rettype.rfind(
" ")
283 fname = rettype[rpos + 1:].strip() + fname
284 rettype = rettype[:rpos].strip()
286 fname = rettype + fname
289 apos = fdecl.find(
"(")
290 if fname.endswith(
"operator"):
292 apos = fdecl.find(
"(", apos + 1)
294 fname =
"cv." + fname.replace(
"::",
".")
295 decl = [fname, rettype, [], [],
None, docstring]
298 implmatch = re.match(
r"(\(.*?\))\s*:\s*(\w+\(.*?\),?\s*)+", fdecl[apos:])
300 fdecl = fdecl[:apos] + implmatch.group(1)
302 args0str = fdecl[apos + 1:fdecl.rfind(
")")].strip()
304 if args0str !=
"" and args0str !=
"void":
305 args0str = re.sub(
r"\([^)]*\)",
lambda m: m.group(0).replace(
',',
"@comma@"), args0str)
306 args0 = args0str.split(
",")
312 balance_paren = narg.count(
"(") - narg.count(
")")
313 balance_angle = narg.count(
"<") - narg.count(
">")
314 if balance_paren == 0
and balance_angle == 0:
315 args.append(narg.strip())
319 dfpos = arg.find(
"=")
322 defval = arg[dfpos + 1:].strip()
324 dfpos = arg.find(
"CV_DEFAULT")
328 dfpos = arg.find(
"CV_WRAP_DEFAULT")
332 defval = defval.replace(
"@comma@",
",")
333 arg = arg[:dfpos].strip()
335 while pos >= 0
and (arg[pos]
in "_[]" or arg[pos].isalpha()
or arg[pos].isdigit()):
338 aname = arg[pos + 1:].strip()
339 atype = arg[:pos + 1].strip()
340 if aname.endswith(
"&")
or aname.endswith(
"*")
or (aname
in [
"int",
"String",
"Mat"]):
341 atype = (atype +
" " + aname).strip()
346 if aname.endswith(
"]"):
347 bidx = aname.find(
'[')
348 atype += aname[bidx:]
350 decl[3].append([atype, aname, defval, []])
358 if bool(re.match(
r".*\)\s*(const)?\s*=\s*0", decl_str)):
360 if bool(re.match(
r".*\)\s*const(\s*=\s*0)?", decl_str)):
362 if "virtual" in decl_str:
368 Parses the function or method declaration in the form:
369 [[VISP_EXPORTS] <rettype>]
371 (<arg_type1> <arg_name1>[=<default_value1>] [, <arg_type2> <arg_name2>[=<default_value2>] ...])
372 [const] {; | <function_body>}
374 Returns the function declaration entry:
375 [<func name>, <return value C-type>, <list of modifiers>, <list of arguments>, <original return type>, <docstring>] (see above)
383 static_method =
False
384 if "VISP_EXPORT" in decl_str:
390 virtual_method =
False
391 pure_virtual_method =
False
400 decl_str = self.
batch_replace(decl_str, [(
"static inline",
""),(
"inline",
""),
401 (
"VISP_EXPORT",
""), (
"VP_EXPLICIT",
""), (
"friend",
""),(
'explicit',
'')
402 ,(
"unsigned",
"")]).strip()
404 if decl_str.strip().startswith(
'virtual'):
405 virtual_method =
True
407 decl_str = decl_str.replace(
'virtual',
'')
409 end_tokens = decl_str[decl_str.rfind(
')'):].split()
410 const_method =
'const' in end_tokens
411 pure_virtual_method =
'=' in end_tokens
and '0' in end_tokens
414 if decl_str.startswith(
"static")
and (context ==
"class" or context ==
"struct"):
415 decl_str = decl_str[len(
"static"):].lstrip()
418 args_begin = decl_str.find(
"(")
421 print(
"Error at %d: no args in '%s'" % (self.
lineno, decl_str))
424 decl_start = decl_str[:args_begin].strip()
426 if decl_start.endswith(
"operator"):
427 args_begin = decl_str.find(
"(", args_begin + 1)
429 print(
"Error at %d: no args in '%s'" % (self.
lineno, decl_str))
431 decl_start = decl_str[:args_begin].strip()
433 if decl_start.endswith(
"()"):
434 decl_start = decl_start[0:-2].rstrip() +
" ()"
437 if 'operator' in decl_str:
438 return decl_str,
"operator",
"",
"",
"",
""
441 if bool(re.match(
r"^(\w+::)*(?P<x>\w+)::~?(?P=x)$", decl_start)):
442 decl_start =
"void " + decl_start
444 rettype, funcname, modlist, argno = self.
parse_arg(decl_start, -1)
448 i = decl_start.rfind(funcname)
450 original_type = decl_start[:i].replace(
"&",
"").replace(
"const",
"").strip()
454 if rettype == classname
or rettype ==
"~" + classname:
455 rettype, funcname =
"", rettype
457 if bool(re.match(
r"\w+\s+\(\*\w+\)\s*\(.*\)", decl_str)):
459 elif bool(re.match(
r"\w+\s+\(\w+::\*\w+\)\s*\(.*\)", decl_str)):
461 elif bool(re.match(
"[A-Z_]+", decl_start)):
463 elif "__declspec" == decl_start:
465 elif bool(re.match(
r"\w+\s+\(\*\w+\)\[\d+\]", decl_str)):
469 print(
"Error at %s:%d the function/method name is missing: '%s'" % (
476 if self.
wrap_mode and ((
"::" in funcname)
or funcname.startswith(
"~")):
491 arg_start = args_begin + 1
502 t, npos = self.
find_next_token(decl_str, [
"(",
")",
",",
"<",
">"], npos)
504 print(
"Error: no closing ')' at %d" % (self.
lineno,))
506 print(decl_str[arg_start:])
517 if (t ==
"," and balance == 1
and angle_balance == 0)
or balance == 0:
519 a = decl_str[arg_start:npos].strip()
527 defval = a[eqpos + 1:].strip()
529 eqpos = a.find(
"CV_DEFAULT")
533 eqpos = a.find(
"CV_WRAP_DEFAULT")
536 if defval ==
"nullptr":
539 a = a[:eqpos].strip()
540 arg_type, arg_name, modlist, argno = self.
parse_arg(a, argno)
544 vector_mat =
"vector_{}".format(
"vpMatrix")
545 vector_mat_template =
"vector<{}>".format(
"vpMatrix")
547 if arg_type ==
"InputArray":
549 elif arg_type ==
"InputOutputArray":
551 modlist.append(
"/IO")
552 elif arg_type ==
"OutputArray":
555 elif arg_type ==
"InputArrayOfArrays":
556 arg_type = vector_mat
557 elif arg_type ==
"InputOutputArrayOfArrays":
558 arg_type = vector_mat
559 modlist.append(
"/IO")
560 elif arg_type ==
"OutputArrayOfArrays":
561 arg_type = vector_mat
563 defval = self.
batch_replace(defval, [(
"InputArrayOfArrays", vector_mat_template),
564 (
"InputOutputArrayOfArrays", vector_mat_template),
565 (
"OutputArrayOfArrays", vector_mat_template),
567 (
"InputOutputArray", mat),
568 (
"OutputArray", mat),
569 (
"noArray", arg_type)]).strip()
570 args.append([arg_type, arg_name, defval, modlist])
574 func_modlist.append(
"/S")
576 func_modlist.append(
"/C")
578 func_modlist.append(
"/V")
579 if pure_virtual_method:
580 func_modlist.append(
"/PV")
582 return [funcname, rettype, func_modlist, args, original_type, docstring]
619 parses the statement (ending with ';' or '}') or a block head (ending with '{')
621 The function calls parse_class_decl or parse_func_decl when necessary. It returns
622 <block_type>, <block_name>, <parse_flag>, <declaration>
623 where the first 3 values only make sense for blocks (i.e. code blocks, namespaces, classes, enums and such)
632 if context ==
"block":
633 print(
"Error at %d: should not call parse_stmt inside blocks" % (self.
lineno,))
636 if context ==
"class" or context ==
"struct":
638 colon_pos = stmt.find(
":")
641 w = stmt[:colon_pos].strip()
642 if w
in [
"public",
"protected",
"private"]:
643 if w ==
"public" or (
not self.
wrap_mode and w ==
"protected"):
647 stmt = stmt[colon_pos + 1:].strip()
651 if not stack_top[self.
PUBLIC_SECTION]
or stmt.startswith(
"template"):
652 return stmt_type,
"",
False,
None
655 if not self.
wrap_mode and stmt.startswith(
"typedef struct"):
660 print(
"Error at %s:%d" % (self.
hname, self.
lineno))
662 if classname.startswith(
"_Ipl"):
663 classname = classname[1:]
664 decl = [stmt_type +
" " + self.
get_dotted_name(classname),
"", modlist, [],
None, docstring]
666 decl[1] =
": " +
", ".join([self.
get_dotted_name(b).replace(
".",
"::")
for b
in bases])
667 return stmt_type, classname,
True, decl
669 if stmt.startswith(
"class")
or stmt.startswith(
"struct"):
670 stmt_type = stmt.split()[0]
671 if stmt.strip() != stmt_type:
675 print(
"Error at %s:%d" % (self.
hname, self.
lineno))
678 if (
"CV_EXPORTS_W" in stmt)
or (
"CV_EXPORTS_AS" in stmt)
or (
680 decl = [stmt_type +
" " + self.
get_dotted_name(classname),
"", modlist, [],
None, docstring]
682 decl[1] =
": " +
", ".join([self.
get_dotted_name(b).replace(
".",
"::")
for b
in bases])
683 return stmt_type, classname,
True, decl
687 if stmt.startswith(
"enum")
or stmt.startswith(
"typedef enum"):
688 return "enum",
"",
True,
None
690 if stmt.startswith(
"namespace"):
691 stmt_list = stmt.split()
692 if len(stmt_list) < 2:
693 stmt_list.append(
"<unnamed>")
694 return stmt_list[0], stmt_list[1],
True,
None
695 if stmt.startswith(
"extern")
and "\"C\"" in stmt:
696 return "namespace",
"",
True,
None
698 if end_token ==
"}" and context ==
"enum":
700 return "enum",
"",
False, decl
702 if end_token ==
";" and stmt.startswith(
"typedef"):
704 return stmt_type,
"",
False,
None
706 paren_pos = stmt.find(
"(")
715 return stmt_type,
"",
False, decl
717 if (context ==
"struct" or context ==
"class")
and end_token ==
";" and stmt:
720 if (
"CV_PROP" in stmt):
722 if "CV_PROP_RW" in stmt:
723 var_modlist.append(
"/RW")
724 stmt = self.
batch_replace(stmt, [(
"CV_PROP_RW",
""), (
"CV_PROP",
"")]).strip()
725 var_list = stmt.split(
",")
726 var_type, var_name1, modlist, argno = self.
parse_arg(var_list[0], -1)
727 var_list = [var_name1] + [i.strip()
for i
in var_list[1:]]
730 class_decl[3].append([var_type, v,
"", var_modlist])
731 return stmt_type,
"",
False,
None
734 return stmt_type,
"",
False,
None
754 The main method. Parses the input file.
755 Returns the list of declarations (that can be print using print_decls)
759 f = io.open(hname,
'rt', encoding=
'utf-8')
760 linelist = list(f.readlines())
771 self.
block_stack = [[
"file", hname,
True,
True,
None]]
782 if state == SCAN
and l.startswith(
"#"):
787 if state == DIRECTIVE:
788 if not l.endswith(
"\\"):
799 if state == DOCSTRING:
802 docstring += l +
"\n"
804 docstring += l[:pos] +
"\n"
809 print(
"Error at %d: invalid state = %d" % (self.
lineno, state))
813 token, pos = self.
find_next_token(l, [
";",
"\"",
"{",
"}",
"//",
"/*"])
816 block_head +=
" " + l
820 block_head +=
" " + l[:pos]
824 block_head +=
" " + l[:pos]
825 end_pos = l.find(
"*/", pos + 2)
828 if len(l) > pos + 2
and ((l[pos + 2] ==
"!")
or (l[pos + 2] ==
"*")):
832 docstring = l[pos + 3:] +
"\n"
835 docstring = l[pos + 3:end_pos]
848 print(
"Error at %d: no terminating '\"'" % (self.
lineno,))
854 block_head +=
" " + l[:pos2 + 1]
860 stmt = (block_head +
" " + l[:pos]).strip()
861 stmt =
" ".join(stmt.split())
865 if stmt.startswith(
"@"):
870 if "BEGIN_VISP_NAMESPACE" in stmt:
871 stmt = stmt.replace(
"BEGIN_VISP_NAMESPACE",
"")
873 if "END_VISP_NAMESPACE" in stmt:
874 stmt = stmt.replace(
"END_VISP_NAMESPACE",
"")
879 docstring = docstring.strip()
880 stmt_type, name, parse_flag, decl = self.
parse_stmt(stmt, token, docstring=docstring)
882 if stmt_type ==
"enum":
888 if stmt_type ==
"namespace":
889 chunks = [block[1]
for block
in self.
block_stack if block[0] ==
'namespace'] + [name]
890 for i
in range(len(chunks)):
891 if chunks[i] ==
"VISP_NAMESPACE_NAME":
895 stmt_type, name, parse_flag =
"block",
"",
False
898 if stmt_type ==
"class":
899 public_section =
False
901 public_section =
True
902 self.
block_stack.append([stmt_type, name, parse_flag, public_section, decl])
906 print(
"Error at %d: the block stack is empty" % (self.
lineno,))
908 if pos + 1 < len(l)
and l[pos + 1] ==
';':