4 from __future__ 
import print_function
 
    7 from xml_docstring 
import XmlDocString
 
   10 template_file_header = 
"""#ifndef DOXYGEN_AUTODOC_{header_guard} 
   11 #define DOXYGEN_AUTODOC_{header_guard} 
   13 #include "{path}/doxygen.hh" 
   15 template_file_footer = 
""" 
   16 #endif // DOXYGEN_AUTODOC_{header_guard} 
   19 template_class_doc = 
""" 
   21 struct class_doc_impl< {classname} > 
   23 static inline const char* run () 
   27 static inline const char* attribute (const char* attrib) 
   29   (void)attrib; // turn off unused parameter warning. 
   33 template_class_attribute_body = 
""" 
   34   if (strcmp(attrib, "{attribute}") == 0) 
   35     return "{docstring}";""" 
   36 template_constructor_doc = 
""" 
   38 struct constructor_{nargs}_impl< {classname_prefix}{comma}{argsstring} > 
   40 static inline const char* doc () 
   44 static inline boost::python::detail::keywords<{nargs}+1> args () 
   46   return ({argnamesstring}); 
   49 template_destructor_doc = 
""" 
   51 struct destructor_doc_impl < {classname_prefix} > 
   53 static inline const char* run () 
   58 template_member_func_doc = 
""" 
   59 {template}inline const char* member_func_doc ({rettype} ({classname_prefix}*function_ptr) {argsstring}) 
   63 template_member_func_doc_body = 
""" 
   64   if (function_ptr == static_cast<{rettype} ({classname_prefix}*) {argsstring}>(&{classname_prefix}{membername})) 
   65     return "{docstring}";""" 
   66 template_member_func_args = 
""" 
   67 {template}inline boost::python::detail::keywords<{n}> member_func_args ({rettype} ({classname_prefix}*function_ptr) {argsstring}) 
   69   return ({default_args}); 
   71 template_member_func_args_body = 
""" 
   72   if (function_ptr == static_cast<{rettype} ({classname_prefix}*) {argsstring}>(&{classname_prefix}{membername})) 
   74 template_static_func_doc = 
""" 
   75 {template}inline const char* member_func_doc ({rettype} (*function_ptr) {argsstring}) 
   79 template_static_func_doc_body = 
""" 
   80   if (function_ptr == static_cast<{rettype} (*) {argsstring}>(&{namespace}::{membername})) 
   81     return "{docstring}";""" 
   82 template_open_namespace = 
"""namespace {namespace} {{""" 
   83 template_close_namespace = 
"""}} // namespace {namespace}""" 
   84 template_include_intern = 
"""#include <doxygen_autodoc/{filename}> 
   86 template_include_extern = 
"""#include <{filename}> 
   91     type_ = param.find(
"type")
 
   92     declname = param.find(
"declname")
 
   93     defname = param.find(
"defname")
 
   97     if defname 
is None and declname 
is None:
 
  101         for c 
in type_.iter():
 
  104             if c.text 
is not None:
 
  106             if c.tail 
is not None:
 
  108         if typetext.startswith(
"typename") 
or typetext.startswith(
"class"):
 
  109             if sys.version_info.major == 2:
 
  111                 return {
"type": s[0].strip(), 
"name": typetext[len(s[0]) :].strip()}
 
  113                 s = typetext.split(maxsplit=1)
 
  115                 return {
"type": s[0].strip(), 
"name": s[1].strip()}
 
  117             return {
"type": type_.text, 
"name": 
""}
 
  119         if type_.text 
is None:
 
  121             type_ = type_.find(
"ref")
 
  122         assert defname.text == declname.text
 
  123         return {
"type": type_.text, 
"name": defname.text}
 
  127     return filename.upper().replace(
".", 
"_").replace(
"/", 
"_").replace(
"-", 
"_")
 
  131     b = [el.text.strip() 
for el 
in brief.iter() 
if el.text] 
if brief 
is not None else []
 
  133         [el.text.strip() 
for el 
in detailed.iter() 
if el.text]
 
  134         if detailed 
is not None 
  139         text += 
"\n" + 
"".join(d)
 
  149     def xmlToType(self, node, array=None, parentClass=None, tplargs=None):
 
  152         - parentClass: a class 
  153         - tplargs: if one of the args is parentClass and no template arguments are provided, 
  154                    set the template arguments to this value 
  155         - array: content of the sibling tag 'array' 
  157         if node.text 
is not None:
 
  158             t = node.text.strip()
 
  161         for c 
in node.iterchildren():
 
  163                 refid = c.attrib[
"refid"]
 
  164                 if parentClass 
is not None and refid == parentClass.id:
 
  165                     t += 
" " + parentClass.name
 
  166                     if c.tail 
is not None and c.tail.lstrip()[0] != 
"<":
 
  167                         if tplargs 
is not None:
 
  170                     parentClass 
is not None 
  171                     and isinstance(parentClass, ClassCompound)
 
  172                     and parentClass.hasTypeDef(c.text.strip())
 
  174                     parent_has_templates = len(parentClass.template_params) > 0
 
  175                     if parent_has_templates:
 
  176                         t += 
" typename " + parentClass._className() + 
"::" 
  178                         t += 
" " + parentClass._className() + 
"::" 
  179                     self_has_templates = (
 
  180                         c.tail 
is not None and c.tail.strip().find(
"<") != -1
 
  182                     if self_has_templates:
 
  185                 elif self.
index.hasref(refid):
 
  186                     t += 
" " + self.
index.getref(refid).name
 
  188                     self.
index.output.warn(
"Unknown reference: ", c.text, refid)
 
  189                     t += 
" " + c.text.strip()
 
  191                 if c.text 
is not None:
 
  192                     t += 
" " + c.text.strip()
 
  193             if c.tail 
is not None:
 
  194                 t += 
" " + c.tail.strip()
 
  195         if array 
is not None:
 
  205             id=memberdefxml.attrib[
"id"],
 
  206             name=memberdefxml.find(
"definition").text,
 
  211         self.
const = memberdefxml.attrib[
"const"] == 
"yes" 
  212         self.
static = memberdefxml.attrib[
"static"] == 
"yes" 
  216                 (param.find(
"type"), param.find(
"declname"), param.find(
"array"))
 
  217                 for param 
in self.
xml.findall(
"param")
 
  221             self.
rettype.text 
is None and len(self.
rettype.getchildren()) == 0
 
  242                     for param 
in self.
xml.findall(
"param")
 
  250         return "({0}){1}".format(self.
s_args(), 
" const" if self.
const else "")
 
  256         if len(self.
parent.template_params) > 0:
 
  259                 + 
", ".join([d[
"name"] 
for d 
in self.
parent.template_params])
 
  265                         type, array, parentClass=self.
parent, tplargs=tplargs
 
  267                     for type, declname, array 
in self.
params 
  274                     for type, declname, array 
in self.
params 
  282         return ", ".join([d[
"type"] + 
" " + d[
"name"] 
for d 
in self.
template_params])
 
  287         ), 
"Member {} ({}) is a special function and no return type".format(
 
  290         if len(self.
parent.template_params) > 0:
 
  293                 + 
", ".join([d[
"name"] 
for d 
in self.
parent.template_params])
 
  298         if isinstance(self.
parent, ClassCompound):
 
  306         return self.
xml.find(
"name").text.strip()
 
  309         return self.
index.xml_docstring.getDocString(
 
  310             self.
xml.find(
"briefdescription"),
 
  311             self.
xml.find(
"detaileddescription"),
 
  319         def getdeclname(i, declname):
 
  320             if declname 
is None or declname.text 
is None or declname.text.strip() == 
"":
 
  321                 return "arg{}".format(i)
 
  322             return declname.text.strip()
 
  324         arg = 
"""boost::python::arg("{}")""" 
  327         ] + [getdeclname(i, declname) 
for i, (_, declname, _) 
in enumerate(self.
params)]
 
  328         return ", ".join([arg.format(n) 
for n 
in argnames])
 
  331         loc = self.
xml.find(
"location")
 
  333         return loc.attrib[
"file"].split(
"/", 1)[1]
 
  339         self.
filename = path.join(index.directory, compound.attrib[
"refid"] + 
".xml")
 
  345             name=self.
definition.find(
"compoundname").text,
 
  351         super(NamespaceCompound, self).
__init__(*args)
 
  358         for section 
in self.
definition.iterchildren(
"sectiondef"):
 
  359             assert "kind" in section.attrib
 
  360             kind = section.attrib[
"kind"]
 
  363             elif kind == 
"typedef":
 
  369         for member 
in section.iterchildren(
"memberdef"):
 
  372                 id=member.attrib[
"id"],
 
  373                 name=self.
name + 
"::" + member.find(
"name").text,
 
  375             self.
index.registerReference(ref)
 
  376             self.
enums.append(member)
 
  377             for value 
in member.iterchildren(
"enumvalue"):
 
  380                     id=value.attrib[
"id"],
 
  381                     name=self.
name + 
"::" + member.find(
"name").text,
 
  385         for member 
in section.iterchildren(
"memberdef"):
 
  388                 id=member.attrib[
"id"],
 
  389                 name=self.
name + 
"::" + member.find(
"name").text,
 
  391             self.
index.registerReference(ref)
 
  395         for member 
in section.iterchildren(
"memberdef"):
 
  405 class ClassCompound(CompoundBase):
 
  407         super(ClassCompound, self).
__init__(*args)
 
  420         for memberdef 
in self.
definition.iter(tag=
"memberdef"):
 
  421             if memberdef.attrib[
"prot"] != 
"public":
 
  423             if memberdef.attrib[
"kind"] == 
"variable":
 
  425             elif memberdef.attrib[
"kind"] == 
"typedef":
 
  428                     id=memberdef.attrib[
"id"],
 
  429                     name=self.
_className() + 
"::" + memberdef.find(
"name").text,
 
  431                 self.
index.registerReference(ref)
 
  432                 self.
typedef[memberdef.find(
"name").text.strip()] = 
True 
  434             elif memberdef.attrib[
"kind"] == 
"enum":
 
  435                 if memberdef.find(
"name").text 
is None:
 
  436                     ref_name = self.
_className() + 
"::" + 
"anonymous_enum" 
  438                     ref_name = self.
_className() + 
"::" + memberdef.find(
"name").text
 
  441                     id=memberdef.attrib[
"id"],
 
  444                 self.
index.registerReference(ref)
 
  445                 for value 
in memberdef.iterchildren(
"enumvalue"):
 
  448                         id=value.attrib[
"id"],
 
  451                     self.
index.registerReference(value_ref)
 
  452             elif memberdef.attrib[
"kind"] == 
"function":
 
  464         if not hasattr(self, 
"template_params") 
or len(self.
template_params) == 0:
 
  466         return ", ".join([d[
"type"] + 
" " + d[
"name"] 
for d 
in self.
template_params])
 
  469         if not hasattr(self, 
"template_params") 
or len(self.
template_params) == 0:
 
  479         return typename 
in self.
typedef 
  494         docstring = self.
index.xml_docstring.getDocString(
 
  499         attribute_docstrings = 
"" 
  501             _dc = self.
index.xml_docstring.getDocString(
 
  502                 member.find(
"briefdescription"),
 
  503                 member.find(
"detaileddescription"),
 
  508             attribute_docstrings += template_class_attribute_body.format(
 
  509                 attribute=member.find(
"name").text,
 
  512         if len(docstring) == 0 
and len(attribute_docstrings) == 0:
 
  515             template_class_doc.format(
 
  519                 attributes=attribute_docstrings,
 
  528                 "Disable class {} because template argument are not resolved for templated class specialization.".format(
 
  536             output.err(
"Does not know where to write doc of", self.
name)
 
  538         output.open(include.text)
 
  539         output.out(template_include_extern.format(filename=include.text))
 
  540         output.out(template_open_namespace.format(namespace=
"doxygen"))
 
  546         member_funcs = dict()
 
  548             prototype = m.prototypekey()
 
  549             if prototype 
in member_funcs:
 
  550                 member_funcs[prototype].append(m)
 
  552                 member_funcs[prototype] = [
 
  559             docstring = member.s_docstring()
 
  560             argnamesstring = member.s_argnamesstring()
 
  561             if len(docstring) == 0 
and len(argnamesstring) == 0:
 
  563             if member.s_name()[0] == 
"~":
 
  565                     template_destructor_doc.format(
 
  573                     template_constructor_doc.format(
 
  576                                 d[
"type"] + 
" " + d[
"name"]
 
  580                         nargs=len(member.params),
 
  581                         comma=
", " if len(member.params) > 0 
else "",
 
  583                         argsstring=member.s_args(),
 
  585                         argnamesstring=argnamesstring,
 
  589         for prototype, members 
in member_funcs.items():
 
  591             documented_members = []
 
  594             for member 
in members:
 
  595                 docstring = member.s_docstring()
 
  596                 argnamesstring = member.s_argnamesstring()
 
  597                 if len(docstring) == 0 
and len(argnamesstring) == 0:
 
  599                 documented_members.append(member)
 
  600                 docstrings.append(docstring)
 
  601                 argnamesstrings.append(argnamesstring)
 
  602             if len(documented_members) == 0:
 
  608                     template_member_func_doc_body.format(
 
  609                         classname_prefix=classname_prefix,
 
  610                         membername=member.s_name(),
 
  612                         rettype=member.s_rettype(),
 
  613                         argsstring=member.s_prototypeArgs(),
 
  615                     for member, docstring 
in zip(documented_members, docstrings)
 
  622                     d[
"type"] + 
" " + d[
"name"]
 
  627                 template_member_func_doc.format(
 
  629                         "template <{}>\n".format(tplargs) 
if len(tplargs) > 0 
else "" 
  631                     rettype=member.s_rettype(),
 
  632                     classname_prefix=classname_prefix,
 
  633                     argsstring=member.s_prototypeArgs(),
 
  641                     template_member_func_args_body.format(
 
  642                         classname_prefix=classname_prefix,
 
  643                         membername=member.s_name(),
 
  645                         rettype=member.s_rettype(),
 
  646                         argsstring=member.s_prototypeArgs(),
 
  648                     for member, argnamesstring 
in zip(
 
  649                         documented_members, argnamesstrings
 
  654             n_args = member.n_args()
 
  656             default_args = 
", ".join(
 
  658                     """boost::python::arg("self")""",
 
  660                 + [
"""boost::python::arg("arg{}")""".format(i) 
for i 
in range(n_args)]
 
  663                 template_member_func_args.format(
 
  665                         "template <{}>\n".format(tplargs) 
if len(tplargs) > 0 
else "" 
  667                     rettype=member.s_rettype(),
 
  669                     default_args=default_args,
 
  670                     classname_prefix=classname_prefix,
 
  671                     argsstring=member.s_prototypeArgs(),
 
  676         output.out(template_close_namespace.format(namespace=
"doxygen"))
 
  685     This class is responsible for generating the list of all C++-usable documented elements. 
  697         for compound 
in self.
tree.getroot().iterchildren(
"compound"):
 
  698             if compound.attrib[
"kind"] 
in [
"class", 
"struct"]:
 
  700             elif compound.attrib[
"kind"] == 
"namespace":
 
  709         self.
output.open(
"doxygen_xml_parser_for_cmake.hh")
 
  716             compound.write(self.
output)
 
  718         self.
output.open(
"functions.h")
 
  721         static_funcs = dict()
 
  726             for m 
in compound.static_funcs:
 
  727                 include = m.include()
 
  728                 if include 
not in includes:
 
  729                     includes.append(include)
 
  730                 docstring = m.s_docstring()
 
  731                 if len(docstring) == 0:
 
  733                 prototype = m.prototypekey()
 
  734                 if prototype 
in static_funcs:
 
  735                     static_funcs[prototype].append((m, docstring))
 
  737                     static_funcs[prototype] = [
 
  740                     prototypes.append(prototype)
 
  745                     template_include_extern.format(filename=filename)
 
  746                     for filename 
in includes
 
  751         self.
output.out(template_open_namespace.format(namespace=
"doxygen"))
 
  753         for prototype 
in prototypes:
 
  754             member_and_docstring_s = static_funcs[prototype]
 
  757                     template_static_func_doc_body.format(
 
  758                         namespace=member.parent.innerNamespace(),
 
  759                         membername=member.s_name(),
 
  761                         rettype=member.s_rettype(),
 
  762                         argsstring=member.s_prototypeArgs(),
 
  764                     for member, docstring 
in member_and_docstring_s
 
  768             member = member_and_docstring_s[0][0]
 
  772                     d[
"type"] + 
" " + d[
"name"]
 
  773                     for d 
in member.parent.template_params + member.template_params
 
  777                 template_static_func_doc.format(
 
  779                         "template <{}>\n".format(tplargs) 
if len(tplargs) > 0 
else "" 
  781                     rettype=member.s_rettype(),
 
  782                     argsstring=member.s_prototypeArgs(),
 
  787         self.
output.out(template_close_namespace.format(namespace=
"doxygen"))
 
  794                     "!!!! Compounds " + obj.id + 
" already exists.",
 
  799                 self.
output.warn(
"Reference " + obj.id + 
" already exists.", obj.name)
 
  812     def __init__(self, output_dir, warn, error, errorPrefix=""):
 
  822         assert self.
_out is None, 
"You did not close the previous file" 
  825         fullname = os.path.join(self.
output_dir, name)
 
  826         dirname = os.path.dirname(fullname)
 
  827         if not os.path.isdir(dirname):
 
  835             if sys.version_info >= (3,):
 
  839             self.
_out = codecs.open(fullname, mode=
"w", encoding=encoding)
 
  844                 template_file_header.format(
 
  845                     path=os.path.dirname(os.path.abspath(__file__)),
 
  858                 template_file_footer.format(
 
  867         if sys.version_info >= (3,):
 
  868             print(*args, file=self.
_out)
 
  870             print(
" ".join(
str(arg) 
for arg 
in args).decode(
"latin1"), file=self.
_out)
 
  879 if __name__ == 
"__main__":
 
  882     parser = argparse.ArgumentParser(
 
  883         description=
"Process Doxygen XML documentation and generate C++ code." 
  885     parser.add_argument(
"doxygen_index_xml", type=str, help=
"the Doxygen XML index.")
 
  886     parser.add_argument(
"output_directory", type=str, help=
"the output directory.")
 
  887     args = parser.parse_args()
 
  891         output=
OutputStreams(args.output_directory, sys.stdout, sys.stderr),
 
  893     index.parseCompound()
 
  895     index.output.writeFooterAndCloseFiles()
 
  896     assert index.output._out 
is None