Improve function arguments parsing and checking

* always use "argN" names for unnamed arguments
* honor space symbol between typename and "*", "&" symbols
* fix indent errors
This commit is contained in:
Andrey Kamaev 2012-11-12 14:42:28 +04:00
parent 5f41971305
commit aabbe11e64
3 changed files with 41 additions and 35 deletions

View File

@ -116,6 +116,8 @@ def compareSignatures(f, s):
sarg = arg[1] sarg = arg[1]
ftype = re.sub(r"\b(cv|std)::", "", (farg[0] or "")) ftype = re.sub(r"\b(cv|std)::", "", (farg[0] or ""))
stype = re.sub(r"\b(cv|std)::", "", (sarg[0] or "")) stype = re.sub(r"\b(cv|std)::", "", (sarg[0] or ""))
ftype = re.sub(r" (&|\*)$", "\\1", ftype)
stype = re.sub(r" (&|\*)$", "\\1", stype)
if ftype != stype: if ftype != stype:
return False, "type of argument #" + str(idx+1) + " mismatch" return False, "type of argument #" + str(idx+1) + " mismatch"
fname = farg[1] or "arg" + str(idx) fname = farg[1] or "arg" + str(idx)
@ -151,6 +153,7 @@ def formatSignature(s):
if idx > 0: if idx > 0:
_str += ", " _str += ", "
argtype = re.sub(r"\bcv::", "", arg[0]) argtype = re.sub(r"\bcv::", "", arg[0])
argtype = re.sub(r" (&|\*)$", "\\1", argtype)
bidx = argtype.find('[') bidx = argtype.find('[')
if bidx < 0: if bidx < 0:
_str += argtype + " " _str += argtype + " "

View File

@ -11,7 +11,7 @@ params_blacklist = {
"fromarray" : ("object", "allowND"), # python only function "fromarray" : ("object", "allowND"), # python only function
"reprojectImageTo3D" : ("ddepth"), # python only argument "reprojectImageTo3D" : ("ddepth"), # python only argument
"composeRT" : ("d*d*"), # wildchards in parameter names are not supported by this parser "composeRT" : ("d*d*"), # wildchards in parameter names are not supported by this parser
"CvSVM::train_auto" : ("\*Grid"), # wildchards in parameter names are not supported by this parser "CvSVM::train_auto" : ("\\*Grid"), # wildchards in parameter names are not supported by this parser
"error" : "args", # parameter of supporting macro "error" : "args", # parameter of supporting macro
"getConvertElem" : ("from", "cn", "to", "beta", "alpha"), # arguments of returned functions "getConvertElem" : ("from", "cn", "to", "beta", "alpha"), # arguments of returned functions
"gpu::swapChannels" : ("dstOrder") # parameter is not parsed correctly by the hdr_parser "gpu::swapChannels" : ("dstOrder") # parameter is not parsed correctly by the hdr_parser
@ -71,7 +71,8 @@ class DeclarationParser(object):
def isready(self): def isready(self):
return self.balance == 0 return self.balance == 0
def getLang(self, line): @classmethod
def getLang(cls, line):
if line.startswith(".. ocv:function::"): if line.startswith(".. ocv:function::"):
return "C++" return "C++"
if line.startswith(".. ocv:cfunction::"): if line.startswith(".. ocv:cfunction::"):
@ -98,7 +99,7 @@ class ParamParser(object):
offset = line.find(":param") offset = line.find(":param")
assert offset > 0 assert offset > 0
self.prefix = line[:offset] self.prefix = line[:offset]
assert self.prefix==" "*len(self.prefix), ":param definition should be prefixed with spaces" assert self.prefix == " "*len(self.prefix), ":param definition should be prefixed with spaces"
line = line[offset + 6:].lstrip() line = line[offset + 6:].lstrip()
name_end = line.find(":") name_end = line.find(":")
assert name_end > 0 assert name_end > 0
@ -115,7 +116,8 @@ class ParamParser(object):
else: else:
self.active = False self.active = False
def hasDeclaration(self, line): @classmethod
def hasDeclaration(cls, line):
return line.lstrip().startswith(":param") return line.lstrip().startswith(":param")
class RstParser(object): class RstParser(object):
@ -177,6 +179,7 @@ class RstParser(object):
was_code_line = False was_code_line = False
fdecl = DeclarationParser() fdecl = DeclarationParser()
pdecl = ParamParser() pdecl = ParamParser()
ll = None
for l in lines: for l in lines:
# read tail of function/method declaration if needed # read tail of function/method declaration if needed
@ -189,7 +192,7 @@ class RstParser(object):
# continue capture seealso # continue capture seealso
if capturing_seealso: if capturing_seealso:
if not l or l.startswith(" "): if not l or l.startswith(" "):
seealso = func.get("seealso",[]) seealso = func.get("seealso", [])
seealso.extend(l.split(",")) seealso.extend(l.split(","))
func["seealso"] = seealso func["seealso"] = seealso
continue continue
@ -206,9 +209,7 @@ class RstParser(object):
if skip_code_lines: if skip_code_lines:
if not l: if not l:
continue continue
if l.startswith(" "): if not l.startswith(" "):
None
else:
skip_code_lines = False skip_code_lines = False
if ll.startswith(".. code-block::") or ll.startswith(".. image::"): if ll.startswith(".. code-block::") or ll.startswith(".. image::"):
@ -248,7 +249,7 @@ class RstParser(object):
if ll.endswith(".. seealso::"): if ll.endswith(".. seealso::"):
capturing_seealso = True capturing_seealso = True
else: else:
seealso = func.get("seealso",[]) seealso = func.get("seealso", [])
seealso.extend(ll[ll.find("::")+2:].split(",")) seealso.extend(ll[ll.find("::")+2:].split(","))
func["seealso"] = seealso func["seealso"] = seealso
continue continue
@ -300,12 +301,12 @@ class RstParser(object):
if (was_code_line): if (was_code_line):
func["long"] = func.get("long", "") + "\n" + ll + "\n" func["long"] = func.get("long", "") + "\n" + ll + "\n"
else: else:
was_code_line = True; was_code_line = True
func["long"] = func.get("long", "") + ll +"\n<code>\n\n // C++ code:\n\n" func["long"] = func.get("long", "") + ll +"\n<code>\n\n // C++ code:\n\n"
else: else:
if (was_code_line): if (was_code_line):
func["long"] = func.get("long", "") + "\n" + ll + "\n</code>\n"; func["long"] = func.get("long", "") + "\n" + ll + "\n</code>\n"
was_code_line = False; was_code_line = False
else: else:
func["long"] = func.get("long", "") + "\n" + ll func["long"] = func.get("long", "") + "\n" + ll
# endfor l in lines # endfor l in lines
@ -377,7 +378,8 @@ class RstParser(object):
if len(lines) > 1: if len(lines) > 1:
self.parse_section_safe(module_name, fname, doc, flineno, lines) self.parse_section_safe(module_name, fname, doc, flineno, lines)
def parse_namespace(self, func, section_name): @classmethod
def parse_namespace(cls, func, section_name):
known_namespaces = ["cv", "gpu", "flann"] known_namespaces = ["cv", "gpu", "flann"]
l = section_name.strip() l = section_name.strip()
for namespace in known_namespaces: for namespace in known_namespaces:
@ -390,7 +392,7 @@ class RstParser(object):
if decl.fdecl.endswith(";"): if decl.fdecl.endswith(";"):
print >> sys.stderr, "RST parser error E%03d: unexpected semicolon at the end of declaration in \"%s\" at %s:%s" \ print >> sys.stderr, "RST parser error E%03d: unexpected semicolon at the end of declaration in \"%s\" at %s:%s" \
% (ERROR_011_EOLEXPECTED, func["name"], func["file"], func["line"]) % (ERROR_011_EOLEXPECTED, func["name"], func["file"], func["line"])
decls = func.get("decls",[]) decls = func.get("decls", [])
if (decl.lang == "C++" or decl.lang == "C"): if (decl.lang == "C++" or decl.lang == "C"):
rst_decl = self.cpp_parser.parse_func_decl_no_wrap(decl.fdecl) rst_decl = self.cpp_parser.parse_func_decl_no_wrap(decl.fdecl)
decls.append( [decl.lang, decl.fdecl, rst_decl] ) decls.append( [decl.lang, decl.fdecl, rst_decl] )
@ -398,8 +400,9 @@ class RstParser(object):
decls.append( [decl.lang, decl.fdecl] ) decls.append( [decl.lang, decl.fdecl] )
func["decls"] = decls func["decls"] = decls
def add_new_pdecl(self, func, decl): @classmethod
params = func.get("params",{}) def add_new_pdecl(cls, func, decl):
params = func.get("params", {})
if decl.name in params: if decl.name in params:
if show_errors: if show_errors:
#check black_list #check black_list
@ -416,8 +419,8 @@ class RstParser(object):
print >> out, "SKIPPED DEFINITION:" print >> out, "SKIPPED DEFINITION:"
print >> out, "name: %s" % (func.get("name","~empty~")) print >> out, "name: %s" % (func.get("name","~empty~"))
print >> out, "file: %s:%s" % (func.get("file","~empty~"), func.get("line","~empty~")) print >> out, "file: %s:%s" % (func.get("file","~empty~"), func.get("line","~empty~"))
print >> out, "is class: %s" % func.get("isclass",False) print >> out, "is class: %s" % func.get("isclass", False)
print >> out, "is struct: %s" % func.get("isstruct",False) print >> out, "is struct: %s" % func.get("isstruct", False)
print >> out, "module: %s" % func.get("module","~unknown~") print >> out, "module: %s" % func.get("module","~unknown~")
print >> out, "namespace: %s" % func.get("namespace", "~empty~") print >> out, "namespace: %s" % func.get("namespace", "~empty~")
print >> out, "class: %s" % (func.get("class","~empty~")) print >> out, "class: %s" % (func.get("class","~empty~"))
@ -426,7 +429,7 @@ class RstParser(object):
if "decls" in func: if "decls" in func:
print >> out, "declarations:" print >> out, "declarations:"
for d in func["decls"]: for d in func["decls"]:
print >> out, " %7s: %s" % (d[0], re.sub(r"[ ]+", " ", d[1])) print >> out, " %7s: %s" % (d[0], re.sub(r"[ ]+", " ", d[1]))
if "seealso" in func: if "seealso" in func:
print >> out, "seealso: ", func["seealso"] print >> out, "seealso: ", func["seealso"]
if "params" in func: if "params" in func:
@ -437,8 +440,8 @@ class RstParser(object):
print >> out print >> out
def validate(self, func): def validate(self, func):
if func.get("decls",None) is None: if func.get("decls", None) is None:
if not func.get("isclass",False) and not func.get("isstruct",False): if not func.get("isclass", False) and not func.get("isstruct", False):
return False return False
if func["name"] in self.definitions: if func["name"] in self.definitions:
if show_errors: if show_errors:
@ -448,7 +451,7 @@ class RstParser(object):
return self.validateParams(func) return self.validateParams(func)
def validateParams(self, func): def validateParams(self, func):
documentedParams = func.get("params",{}).keys() documentedParams = func.get("params", {}).keys()
params = [] params = []
for decl in func.get("decls", []): for decl in func.get("decls", []):
@ -486,11 +489,11 @@ class RstParser(object):
if "class" in func: if "class" in func:
func["class"] = self.normalizeText(func["class"]) func["class"] = self.normalizeText(func["class"])
if "brief" in func: if "brief" in func:
func["brief"] = self.normalizeText(func.get("brief",None)) func["brief"] = self.normalizeText(func.get("brief", None))
if not func["brief"]: if not func["brief"]:
del func["brief"] del func["brief"]
if "long" in func: if "long" in func:
func["long"] = self.normalizeText(func.get("long",None)) func["long"] = self.normalizeText(func.get("long", None))
if not func["long"]: if not func["long"]:
del func["long"] del func["long"]
if "decls" in func: if "decls" in func:
@ -518,7 +521,7 @@ class RstParser(object):
del func["seealso"] del func["seealso"]
# special case for old C functions - section name should omit "cv" prefix # special case for old C functions - section name should omit "cv" prefix
if not func.get("isclass",False) and not func.get("isstruct",False): if not func.get("isclass", False) and not func.get("isstruct", False):
self.fixOldCFunctionName(func) self.fixOldCFunctionName(func)
return func return func
@ -616,7 +619,7 @@ class RstParser(object):
s = re.sub(r" +", " ", s) s = re.sub(r" +", " ", s)
# restore math # restore math
s = re.sub(r" *<BR> *","\n", s) s = re.sub(r" *<BR> *", "\n", s)
# remove extra space before . # remove extra space before .
s = re.sub(r"[\n ]+\.", ".", s) s = re.sub(r"[\n ]+\.", ".", s)
@ -642,13 +645,13 @@ class RstParser(object):
classes = 0 classes = 0
structs = 0 structs = 0
for name, d in self.definitions.items(): for name, d in self.definitions.items():
if d.get("isclass", False): if d.get("isclass", False):
classes += 1 classes += 1
elif d.get("isstruct", False): elif d.get("isstruct", False):
structs += 1 structs += 1
else: else:
for decl in d.get("decls",[]): for decl in d.get("decls", []):
stat[decl[0]] = stat.get(decl[0],0) + 1 stat[decl[0]] = stat.get(decl[0], 0) + 1
print print
print " classes documented: %s" % classes print " classes documented: %s" % classes

View File

@ -337,10 +337,10 @@ class CppHeaderParser(object):
atype = arg[:pos+1].strip() atype = arg[:pos+1].strip()
if aname.endswith("&") or aname.endswith("*") or (aname in ["int", "string", "Mat"]): if aname.endswith("&") or aname.endswith("*") or (aname in ["int", "string", "Mat"]):
atype = (atype + " " + aname).strip() atype = (atype + " " + aname).strip()
aname = "param" aname = ""
else: else:
atype = arg atype = arg
aname = "param" aname = ""
if aname.endswith("]"): if aname.endswith("]"):
bidx = aname.find('[') bidx = aname.find('[')
atype += aname[bidx:] atype += aname[bidx:]