3 from __future__
import print_function
6 from xml_docstring
import XmlDocString
9 template_file_header =
"""#ifndef DOXYGEN_AUTODOC_{header_guard} 10 #define DOXYGEN_AUTODOC_{header_guard} 12 #include "{path}/doxygen.hh" 14 template_file_footer =
""" 15 #endif // DOXYGEN_AUTODOC_{header_guard} 18 template_class_doc =
""" 20 struct class_doc_impl< {classname} > 22 static inline const char* run () 26 static inline const char* attribute (const char* attrib) 28 (void)attrib; // turn off unused parameter warning. 32 template_class_attribute_body =
""" 33 if (strcmp(attrib, "{attribute}") == 0) 34 return "{docstring}";""" 35 template_constructor_doc =
""" 37 struct constructor_{nargs}_impl< {classname_prefix}{comma}{argsstring} > 39 static inline const char* doc () 43 static inline boost::python::detail::keywords<{nargs}+1> args () 45 return ({argnamesstring}); 48 template_destructor_doc =
""" 50 struct destructor_doc_impl < {classname_prefix} > 52 static inline const char* run () 57 template_member_func_doc =
""" 58 {template}inline const char* member_func_doc ({rettype} ({classname_prefix}*function_ptr) {argsstring}) 62 template_member_func_doc_body =
""" 63 if (function_ptr == static_cast<{rettype} ({classname_prefix}*) {argsstring}>(&{classname_prefix}{membername})) 64 return "{docstring}";""" 65 template_member_func_args =
""" 66 {template}inline boost::python::detail::keywords<{n}> member_func_args ({rettype} ({classname_prefix}*function_ptr) {argsstring}) 68 return ({default_args}); 70 template_member_func_args_body =
""" 71 if (function_ptr == static_cast<{rettype} ({classname_prefix}*) {argsstring}>(&{classname_prefix}{membername})) 73 template_static_func_doc =
""" 74 {template}inline const char* member_func_doc ({rettype} (*function_ptr) {argsstring}) 78 template_static_func_doc_body =
""" 79 if (function_ptr == static_cast<{rettype} (*) {argsstring}>(&{namespace}::{membername})) 80 return "{docstring}";""" 81 template_open_namespace =
"""namespace {namespace} {{""" 82 template_close_namespace =
"""}} // namespace {namespace}""" 83 template_include_intern =
"""#include <doxygen_autodoc/{filename}> 85 template_include_extern =
"""#include <{filename}> 90 type = param.find(
"type")
91 declname = param.find(
"declname")
92 defname = param.find(
"defname")
96 if defname
is None and declname
is None:
101 if c.text
is not None:
103 if c.tail
is not None:
105 if typetext.startswith(
"typename")
or typetext.startswith(
"class"):
106 if sys.version_info.major == 2:
108 return {
"type": s[0].strip(),
"name": typetext[len(s[0]) :].strip()}
110 s = typetext.split(maxsplit=1)
112 return {
"type": s[0].strip(),
"name": s[1].strip()}
114 return {
"type": type.text,
"name":
""}
116 assert defname.text == declname.text
117 return {
"type": type.text,
"name": defname.text}
123 return filename.upper().replace(
".",
"_").replace(
"/",
"_").replace(
"-",
"_")
127 b = [el.text.strip()
for el
in brief.iter()
if el.text]
if brief
is not None else []
129 [el.text.strip()
for el
in detailed.iter()
if el.text]
130 if detailed
is not None 135 text +=
"\n" +
"".join(d)
145 def xmlToType(self, node, array=None, parentClass=None, tplargs=None):
148 - parentClass: a class 149 - tplargs: if one of the args is parentClass and no template arguments are provided, 150 set the template arguments to this value 151 - array: content of the sibling tag 'array' 153 if node.text
is not None:
154 t = node.text.strip()
157 for c
in node.iterchildren():
159 refid = c.attrib[
"refid"]
160 if parentClass
is not None and refid == parentClass.id:
161 t +=
" " + parentClass.name
162 if c.tail
is not None and c.tail.lstrip()[0] !=
"<":
163 if tplargs
is not None:
166 parentClass
is not None 167 and isinstance(parentClass, ClassCompound)
168 and parentClass.hasTypeDef(c.text.strip())
170 parent_has_templates = len(parentClass.template_params) > 0
171 if parent_has_templates:
172 t +=
" typename " + parentClass._className() +
"::" 174 t +=
" " + parentClass._className() +
"::" 175 self_has_templates = (
176 c.tail
is not None and c.tail.strip().find(
"<") != -1
178 if self_has_templates:
181 elif self.
index.hasref(refid):
182 t +=
" " + self.
index.getref(refid).name
184 self.
index.output.warn(
"Unknown reference: ", c.text, refid)
185 t +=
" " + c.text.strip()
187 if c.text
is not None:
188 t +=
" " + c.text.strip()
189 if c.tail
is not None:
190 t +=
" " + c.tail.strip()
191 if array
is not None:
201 id=memberdefxml.attrib[
"id"],
202 name=memberdefxml.find(
"definition").text,
207 self.
const = memberdefxml.attrib[
"const"] ==
"yes" 208 self.
static = memberdefxml.attrib[
"static"] ==
"yes" 212 (param.find(
"type"), param.find(
"declname"), param.find(
"array"))
213 for param
in self.
xml.findall(
"param")
217 self.
rettype.text
is None and len(self.
rettype.getchildren()) == 0
238 for param
in self.
xml.findall(
"param")
246 return "({0}){1}".format(self.
s_args(),
" const" if self.
const else "")
252 if len(self.
parent.template_params) > 0:
255 +
", ".join([d[
"name"]
for d
in self.
parent.template_params])
261 type, array, parentClass=self.
parent, tplargs=tplargs
263 for type, declname, array
in self.
params 270 for type, declname, array
in self.
params 278 return ", ".join([d[
"type"] +
" " + d[
"name"]
for d
in self.
template_params])
283 ),
"Member {} ({}) is a special function and no return type".format(
286 if len(self.
parent.template_params) > 0:
289 +
", ".join([d[
"name"]
for d
in self.
parent.template_params])
294 if isinstance(self.
parent, ClassCompound):
302 return self.
xml.find(
"name").text.strip()
305 return self.
index.xml_docstring.getDocString(
306 self.
xml.find(
"briefdescription"),
307 self.
xml.find(
"detaileddescription"),
315 def getdeclname(i, declname):
316 if declname
is None or declname.text
is None or declname.text.strip() ==
"":
317 return "arg{}".format(i)
318 return declname.text.strip()
320 arg =
"""boost::python::arg("{}")""" 323 ] + [getdeclname(i, declname)
for i, (_, declname, _)
in enumerate(self.
params)]
324 return ", ".join([arg.format(n)
for n
in argnames])
329 loc = self.
xml.find(
"location")
331 return loc.attrib[
"file"].split(
"/", 1)[1]
337 self.
filename = path.join(index.directory, compound.attrib[
"refid"] +
".xml")
343 name=self.
definition.find(
"compoundname").text,
349 super(NamespaceCompound, self).
__init__(*args)
356 for section
in self.
definition.iterchildren(
"sectiondef"):
357 assert "kind" in section.attrib
358 kind = section.attrib[
"kind"]
361 elif kind ==
"typedef":
367 for member
in section.iterchildren(
"memberdef"):
370 id=member.attrib[
"id"],
371 name=self.
name +
"::" + member.find(
"name").text,
373 self.
index.registerReference(ref)
374 self.
enums.append(member)
375 for value
in member.iterchildren(
"enumvalue"):
378 id=value.attrib[
"id"],
379 name=self.
name +
"::" + member.find(
"name").text,
383 for member
in section.iterchildren(
"memberdef"):
386 id=member.attrib[
"id"],
387 name=self.
name +
"::" + member.find(
"name").text,
389 self.
index.registerReference(ref)
393 for member
in section.iterchildren(
"memberdef"):
403 class ClassCompound(CompoundBase):
405 super(ClassCompound, self).
__init__(*args)
418 for memberdef
in self.
definition.iter(tag=
"memberdef"):
419 if memberdef.attrib[
"prot"] !=
"public":
421 if memberdef.attrib[
"kind"] ==
"variable":
423 elif memberdef.attrib[
"kind"] ==
"typedef":
426 id=memberdef.attrib[
"id"],
427 name=self.
_className() +
"::" + memberdef.find(
"name").text,
429 self.
index.registerReference(ref)
430 self.
typedef[memberdef.find(
"name").text.strip()] =
True 432 elif memberdef.attrib[
"kind"] ==
"enum":
435 id=memberdef.attrib[
"id"],
436 name=self.
_className() +
"::" + memberdef.find(
"name").text,
438 self.
index.registerReference(ref)
439 for value
in memberdef.iterchildren(
"enumvalue"):
442 id=value.attrib[
"id"],
443 name=self.
_className() +
"::" + memberdef.find(
"name").text,
445 self.
index.registerReference(ref)
446 elif memberdef.attrib[
"kind"] ==
"function":
458 if not hasattr(self,
"template_params")
or len(self.
template_params) == 0:
460 return ", ".join([d[
"type"] +
" " + d[
"name"]
for d
in self.
template_params])
463 if not hasattr(self,
"template_params")
or len(self.
template_params) == 0:
473 return typename
in self.
typedef 488 docstring = self.
index.xml_docstring.getDocString(
493 attribute_docstrings =
"" 495 _dc = self.
index.xml_docstring.getDocString(
496 member.find(
"briefdescription"),
497 member.find(
"detaileddescription"),
502 attribute_docstrings += template_class_attribute_body.format(
503 attribute=member.find(
"name").text,
506 if len(docstring) == 0
and len(attribute_docstrings) == 0:
509 template_class_doc.format(
513 attributes=attribute_docstrings,
522 "Disable class {} because template argument are not resolved for templated class specialization.".format(
530 output.err(
"Does not know where to write doc of", self.
name)
532 output.open(include.text)
533 output.out(template_include_extern.format(filename=include.text))
534 output.out(template_open_namespace.format(namespace=
"doxygen"))
540 member_funcs = dict()
542 prototype = m.prototypekey()
543 if prototype
in member_funcs:
544 member_funcs[prototype].append(m)
546 member_funcs[prototype] = [
553 docstring = member.s_docstring()
554 argnamesstring = member.s_argnamesstring()
555 if len(docstring) == 0
and len(argnamesstring) == 0:
557 if member.s_name()[0] ==
"~":
559 template_destructor_doc.format(
567 template_constructor_doc.format(
570 d[
"type"] +
" " + d[
"name"]
574 nargs=len(member.params),
575 comma=
", " if len(member.params) > 0
else "",
577 argsstring=member.s_args(),
579 argnamesstring=argnamesstring,
583 for prototype, members
in member_funcs.items():
585 documented_members = []
588 for member
in members:
589 docstring = member.s_docstring()
590 argnamesstring = member.s_argnamesstring()
591 if len(docstring) == 0
and len(argnamesstring) == 0:
593 documented_members.append(member)
594 docstrings.append(docstring)
595 argnamesstrings.append(argnamesstring)
596 if len(documented_members) == 0:
602 template_member_func_doc_body.format(
603 classname_prefix=classname_prefix,
604 membername=member.s_name(),
606 rettype=member.s_rettype(),
607 argsstring=member.s_prototypeArgs(),
609 for member, docstring
in zip(documented_members, docstrings)
616 d[
"type"] +
" " + d[
"name"]
621 template_member_func_doc.format(
622 template=
"template <{}>\n".format(tplargs)
625 rettype=member.s_rettype(),
626 classname_prefix=classname_prefix,
627 argsstring=member.s_prototypeArgs(),
635 template_member_func_args_body.format(
636 classname_prefix=classname_prefix,
637 membername=member.s_name(),
639 rettype=member.s_rettype(),
640 argsstring=member.s_prototypeArgs(),
642 for member, argnamesstring
in zip(
643 documented_members, argnamesstrings
648 n_args = member.n_args()
650 default_args =
", ".join(
652 """boost::python::arg("self")""",
654 + [
"""boost::python::arg("arg{}")""".format(i)
for i
in range(n_args)]
657 template_member_func_args.format(
658 template=
"template <{}>\n".format(tplargs)
661 rettype=member.s_rettype(),
663 default_args=default_args,
664 classname_prefix=classname_prefix,
665 argsstring=member.s_prototypeArgs(),
670 output.out(template_close_namespace.format(namespace=
"doxygen"))
679 This class is responsible for generating the list of all C++-usable documented elements. 691 for compound
in self.
tree.getroot().iterchildren(
"compound"):
692 if compound.attrib[
"kind"]
in [
"class",
"struct"]:
694 elif compound.attrib[
"kind"] ==
"namespace":
702 from os.path
import abspath, dirname
703 from time
import asctime
705 self.
output.open(
"doxygen_xml_parser_for_cmake.hh")
712 compound.write(self.
output)
714 self.
output.open(
"functions.h")
717 static_funcs = dict()
722 for m
in compound.static_funcs:
723 include = m.include()
724 if include
not in includes:
725 includes.append(include)
726 docstring = m.s_docstring()
727 if len(docstring) == 0:
729 prototype = m.prototypekey()
730 if prototype
in static_funcs:
731 static_funcs[prototype].append((m, docstring))
733 static_funcs[prototype] = [
736 prototypes.append(prototype)
741 template_include_extern.format(filename=filename)
742 for filename
in includes
747 self.
output.out(template_open_namespace.format(namespace=
"doxygen"))
749 for prototype
in prototypes:
750 member_and_docstring_s = static_funcs[prototype]
753 template_static_func_doc_body.format(
754 namespace=member.parent.innerNamespace(),
755 membername=member.s_name(),
757 rettype=member.s_rettype(),
758 argsstring=member.s_prototypeArgs(),
760 for member, docstring
in member_and_docstring_s
764 member = member_and_docstring_s[0][0]
768 d[
"type"] +
" " + d[
"name"]
769 for d
in member.parent.template_params + member.template_params
773 template_static_func_doc.format(
774 template=
"template <{}>\n".format(tplargs)
777 rettype=member.s_rettype(),
778 argsstring=member.s_prototypeArgs(),
783 self.
output.out(template_close_namespace.format(namespace=
"doxygen"))
790 "!!!! Compounds " + obj.id +
" already exists.",
795 self.
output.warn(
"Reference " + obj.id +
" already exists.", obj.name)
808 def __init__(self, output_dir, warn, error, errorPrefix=""):
818 assert self.
_out ==
None,
"You did not close the previous file" 821 fullname = os.path.join(self.
output_dir, name)
822 dirname = os.path.dirname(fullname)
823 if not os.path.isdir(dirname):
831 if sys.version_info >= (3,):
835 self.
_out = codecs.open(fullname, mode=
"w", encoding=encoding)
840 template_file_header.format(
841 path=os.path.dirname(os.path.abspath(__file__)),
854 template_file_footer.format(
863 if sys.version_info >= (3,):
864 print(*args, file=self.
_out)
866 print(
" ".join(
str(arg)
for arg
in args).decode(
"latin1"), file=self.
_out)
875 if __name__ ==
"__main__":
878 parser = argparse.ArgumentParser(
879 description=
"Process Doxygen XML documentation and generate C++ code." 881 parser.add_argument(
"doxygen_index_xml", type=str, help=
"the Doxygen XML index.")
882 parser.add_argument(
"output_directory", type=str, help=
"the output directory.")
883 args = parser.parse_args()
887 output=
OutputStreams(args.output_directory, sys.stdout, sys.stderr),
889 index.parseCompound()
891 index.output.writeFooterAndCloseFiles()
892 assert index.output._out ==
None
def _templateParams(self, tpl)
def format_description(brief, detailed)
def _templateParamToDict(param)
def __init__(self, index, id=None, name=None)
def parseFuncSection(self, section)
def writeFooterAndCloseFiles(self)
def registerReference(self, obj, overwrite=True)
def xmlToType(self, node, array=None, parentClass=None, tplargs=None)
def __init__(self, index, memberdefxml, parent)
def hasTypeDef(self, typename)
def s_argnamesstring(self)
def s_prototypeArgs(self)
def parseEnumSection(self, section)
def makeHeaderGuard(filename)
def _writeClassDoc(self, output)
def __init__(self, input, output)
def __init__(self, compound, index)
def parseTypedefSection(self, section)
def _memberfunc(self, member)
def _attribute(self, member)
def _templateParams(self, tpl)
def __init__(self, output_dir, warn, error, errorPrefix="")