doxygen_xml_parser.py
Go to the documentation of this file.
1 #!/usr/bin/python3
2 # ruff: noqa: E501
3 
4 from __future__ import print_function
5 from lxml import etree
6 from os import path
7 from xml_docstring import XmlDocString
8 import sys
9 
10 template_file_header = """#ifndef DOXYGEN_AUTODOC_{header_guard}
11 #define DOXYGEN_AUTODOC_{header_guard}
12 
13 #include "{path}/doxygen.hh"
14 """
15 template_file_footer = """
16 #endif // DOXYGEN_AUTODOC_{header_guard}
17 """
18 
19 template_class_doc = """
20 template <{tplargs}>
21 struct class_doc_impl< {classname} >
22 {{
23 static inline const char* run ()
24 {{
25  return "{docstring}";
26 }}
27 static inline const char* attribute (const char* attrib)
28 {{{attributes}
29  (void)attrib; // turn off unused parameter warning.
30  return "";
31 }}
32 }};"""
33 template_class_attribute_body = """
34  if (strcmp(attrib, "{attribute}") == 0)
35  return "{docstring}";"""
36 template_constructor_doc = """
37 template <{tplargs}>
38 struct constructor_{nargs}_impl< {classname_prefix}{comma}{argsstring} >
39 {{
40 static inline const char* doc ()
41 {{
42  return "{docstring}";
43 }}
44 static inline boost::python::detail::keywords<{nargs}+1> args ()
45 {{
46  return ({argnamesstring});
47 }}
48 }};"""
49 template_destructor_doc = """
50 template <{tplargs}>
51 struct destructor_doc_impl < {classname_prefix} >
52 {{
53 static inline const char* run ()
54 {{
55  return "{docstring}";
56 }}
57 }};"""
58 template_member_func_doc = """
59 {template}inline const char* member_func_doc ({rettype} ({classname_prefix}*function_ptr) {argsstring})
60 {{{body}
61  return "";
62 }}"""
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})
68 {{{body}
69  return ({default_args});
70 }}"""
71 template_member_func_args_body = """
72  if (function_ptr == static_cast<{rettype} ({classname_prefix}*) {argsstring}>(&{classname_prefix}{membername}))
73  return ({args});"""
74 template_static_func_doc = """
75 {template}inline const char* member_func_doc ({rettype} (*function_ptr) {argsstring})
76 {{{body}
77  return "";
78 }}"""
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}>
85 """
86 template_include_extern = """#include <{filename}>
87 """
88 
89 
91  type_ = param.find("type")
92  declname = param.find("declname")
93  defname = param.find("defname")
94  # FIXME type may contain references in two ways:
95  # - the real param type
96  # - the name of the template argument is recognized as the name of a type...
97  if defname is None and declname is None:
98  typetext = type_.text
99  if typetext is None:
100  typetext = ""
101  for c in type_.iter():
102  if c == type_:
103  continue
104  if c.text is not None:
105  typetext += c.text
106  if c.tail is not None:
107  typetext += c.tail
108  if typetext.startswith("typename") or typetext.startswith("class"):
109  if sys.version_info.major == 2:
110  s = typetext.split()
111  return {"type": s[0].strip(), "name": typetext[len(s[0]) :].strip()}
112  else:
113  s = typetext.split(maxsplit=1)
114  assert len(s) == 2
115  return {"type": s[0].strip(), "name": s[1].strip()}
116  else:
117  return {"type": type_.text, "name": ""}
118  else:
119  if type_.text is None:
120  # type_ is not a typename but an existing type
121  type_ = type_.find("ref")
122  assert defname.text == declname.text
123  return {"type": type_.text, "name": defname.text}
124 
125 
126 def makeHeaderGuard(filename):
127  return filename.upper().replace(".", "_").replace("/", "_").replace("-", "_")
128 
129 
130 def format_description(brief, detailed):
131  b = [el.text.strip() for el in brief.iter() if el.text] if brief is not None else []
132  d = (
133  [el.text.strip() for el in detailed.iter() if el.text]
134  if detailed is not None
135  else []
136  )
137  text = "".join(b)
138  if d:
139  text += "\n" + "".join(d)
140  return text
141 
142 
143 class Reference(object):
144  def __init__(self, index, id=None, name=None):
145  self.id = id
146  self.name = name
147  self.index = index
148 
149  def xmlToType(self, node, array=None, parentClass=None, tplargs=None):
150  """
151  - node:
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'
156  """
157  if node.text is not None:
158  t = node.text.strip()
159  else:
160  t = ""
161  for c in node.iterchildren():
162  if c.tag == "ref":
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:
168  t += tplargs
169  elif (
170  parentClass is not None
171  and isinstance(parentClass, ClassCompound)
172  and parentClass.hasTypeDef(c.text.strip())
173  ):
174  parent_has_templates = len(parentClass.template_params) > 0
175  if parent_has_templates:
176  t += " typename " + parentClass._className() + "::"
177  else:
178  t += " " + parentClass._className() + "::"
179  self_has_templates = (
180  c.tail is not None and c.tail.strip().find("<") != -1
181  )
182  if self_has_templates:
183  t += " template "
184  t += c.text.strip()
185  elif self.index.hasref(refid):
186  t += " " + self.index.getref(refid).name
187  else:
188  self.index.output.warn("Unknown reference: ", c.text, refid)
189  t += " " + c.text.strip()
190  else:
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:
196  t += array.text
197  return t
198 
199 
200 # Only for function as of now.
202  def __init__(self, index, memberdefxml, parent):
203  super(MemberDef, self).__init__(
204  index=index,
205  id=memberdefxml.attrib["id"],
206  name=memberdefxml.find("definition").text,
207  )
208  self.parent = parent
209 
210  self.xml = memberdefxml
211  self.const = memberdefxml.attrib["const"] == "yes"
212  self.static = memberdefxml.attrib["static"] == "yes"
213  self.rettype = memberdefxml.find("type")
214  self.params = tuple(
215  [
216  (param.find("type"), param.find("declname"), param.find("array"))
217  for param in self.xml.findall("param")
218  ]
219  )
220  self.special = (
221  self.rettype.text is None and len(self.rettype.getchildren()) == 0
222  )
223  # assert self.special or len(self.rettype.text) > 0
224 
225  self._templateParams(self.xml.find("templateparamlist"))
226 
227  def _templateParams(self, tpl):
228  if tpl is not None:
229  self.template_params = tuple(
230  [_templateParamToDict(param) for param in tpl.iterchildren(tag="param")]
231  )
232  else:
233  self.template_params = tuple()
234 
235  def prototypekey(self):
236  prototype = (
237  self.xmlToType(self.rettype, parentClass=self.parent),
238  tuple([tuple(t.items()) for t in self.template_params]),
239  tuple(
240  [
241  self.xmlToType(param.find("type"), parentClass=self.parent)
242  for param in self.xml.findall("param")
243  ]
244  ),
245  self.const,
246  )
247  return prototype
248 
249  def s_prototypeArgs(self):
250  return "({0}){1}".format(self.s_args(), " const" if self.const else "")
251 
252  def s_args(self):
253  # If the class is templated, check if one of the argument is the class itself.
254  # If so, we must add the template arguments to the class (if there is none)
255 
256  if len(self.parent.template_params) > 0:
257  tplargs = (
258  " <"
259  + ", ".join([d["name"] for d in self.parent.template_params])
260  + " > "
261  )
262  args = ", ".join(
263  [
264  self.xmlToType(
265  type, array, parentClass=self.parent, tplargs=tplargs
266  )
267  for type, declname, array in self.params
268  ]
269  )
270  else:
271  args = ", ".join(
272  [
273  self.xmlToType(type, array, parentClass=self.parent)
274  for type, declname, array in self.params
275  ]
276  )
277  return args
278 
279  def s_tpldecl(self):
280  if len(self.template_params) == 0:
281  return ""
282  return ", ".join([d["type"] + " " + d["name"] for d in self.template_params])
283 
284  def s_rettype(self):
285  assert (
286  not self.special
287  ), "Member {} ({}) is a special function and no return type".format(
288  self.name, self.id
289  )
290  if len(self.parent.template_params) > 0:
291  tplargs = (
292  " <"
293  + ", ".join([d["name"] for d in self.parent.template_params])
294  + " > "
295  )
296  else:
297  tplargs = None
298  if isinstance(self.parent, ClassCompound):
299  return self.xmlToType(
300  self.rettype, parentClass=self.parent, tplargs=tplargs
301  )
302  else:
303  return self.xmlToType(self.rettype)
304 
305  def s_name(self):
306  return self.xml.find("name").text.strip()
307 
308  def s_docstring(self):
309  return self.index.xml_docstring.getDocString(
310  self.xml.find("briefdescription"),
311  self.xml.find("detaileddescription"),
312  self.index.output,
313  )
314 
315  def n_args(self):
316  return len(self.params)
317 
318  def s_argnamesstring(self):
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()
323 
324  arg = """boost::python::arg("{}")"""
325  argnames = [
326  "self",
327  ] + [getdeclname(i, declname) for i, (_, declname, _) in enumerate(self.params)]
328  return ", ".join([arg.format(n) for n in argnames])
329 
330  def include(self):
331  loc = self.xml.find("location")
332  # The location is based on $CMAKE_SOURCE_DIR. Remove first directory.
333  return loc.attrib["file"].split("/", 1)[1]
334 
335 
337  def __init__(self, compound, index):
338  self.compound = compound
339  self.filename = path.join(index.directory, compound.attrib["refid"] + ".xml")
340  self.tree = etree.parse(self.filename)
341  self.definition = self.tree.getroot().find("compounddef")
342  super(CompoundBase, self).__init__(
343  index,
344  id=self.definition.attrib["id"],
345  name=self.definition.find("compoundname").text,
346  )
347 
348 
350  def __init__(self, *args):
351  super(NamespaceCompound, self).__init__(*args)
352  self.typedefs = []
353  self.enums = []
354  self.static_funcs = []
355  self.template_params = tuple()
356 
357  # Add references
358  for section in self.definition.iterchildren("sectiondef"):
359  assert "kind" in section.attrib
360  kind = section.attrib["kind"]
361  if kind == "enum":
362  self.parseEnumSection(section)
363  elif kind == "typedef":
364  self.parseTypedefSection(section)
365  elif kind == "func":
366  self.parseFuncSection(section)
367 
368  def parseEnumSection(self, section):
369  for member in section.iterchildren("memberdef"):
370  ref = Reference(
371  index=self.index,
372  id=member.attrib["id"],
373  name=self.name + "::" + member.find("name").text,
374  )
375  self.index.registerReference(ref)
376  self.enums.append(member)
377  for value in member.iterchildren("enumvalue"):
378  ref = Reference(
379  index=self.index,
380  id=value.attrib["id"],
381  name=self.name + "::" + member.find("name").text,
382  )
383 
384  def parseTypedefSection(self, section):
385  for member in section.iterchildren("memberdef"):
386  ref = Reference(
387  index=self.index,
388  id=member.attrib["id"],
389  name=self.name + "::" + member.find("name").text,
390  )
391  self.index.registerReference(ref)
392  self.typedefs.append(member)
393 
394  def parseFuncSection(self, section):
395  for member in section.iterchildren("memberdef"):
396  self.static_funcs.append(MemberDef(self.index, member, self))
397 
398  def innerNamespace(self):
399  return self.name
400 
401  def write(self, output):
402  pass
403 
404 
405 class ClassCompound(CompoundBase):
406  def __init__(self, *args):
407  super(ClassCompound, self).__init__(*args)
408  self.member_funcs = list()
409  self.static_funcs = list()
410  self.special_funcs = list()
411  self.attributes = list()
412 
413  self.struct = self.compound.attrib["kind"] == "struct"
414  self.public = self.definition.attrib["prot"] == "public"
415  self.template_specialization = self.name.find("<") > 0
416  self.typedef = dict()
417 
418  # Handle templates
419  self._templateParams(self.definition.find("templateparamlist"))
420  for memberdef in self.definition.iter(tag="memberdef"):
421  if memberdef.attrib["prot"] != "public":
422  continue
423  if memberdef.attrib["kind"] == "variable":
424  self._attribute(memberdef)
425  elif memberdef.attrib["kind"] == "typedef":
426  ref = Reference(
427  index=self.index,
428  id=memberdef.attrib["id"],
429  name=self._className() + "::" + memberdef.find("name").text,
430  )
431  self.index.registerReference(ref)
432  self.typedef[memberdef.find("name").text.strip()] = True
433 
434  elif memberdef.attrib["kind"] == "enum":
435  if memberdef.find("name").text is None:
436  ref_name = self._className() + "::" + "anonymous_enum"
437  else:
438  ref_name = self._className() + "::" + memberdef.find("name").text
439  ref = Reference(
440  index=self.index,
441  id=memberdef.attrib["id"],
442  name=ref_name,
443  )
444  self.index.registerReference(ref)
445  for value in memberdef.iterchildren("enumvalue"):
446  value_ref = Reference(
447  index=self.index,
448  id=value.attrib["id"],
449  name=ref.name,
450  )
451  self.index.registerReference(value_ref)
452  elif memberdef.attrib["kind"] == "function":
453  self._memberfunc(memberdef)
454 
455  def _templateParams(self, tpl):
456  if tpl is not None:
457  self.template_params = tuple(
458  [_templateParamToDict(param) for param in tpl.iterchildren(tag="param")]
459  )
460  else:
461  self.template_params = tuple()
462 
463  def _templateDecl(self):
464  if not hasattr(self, "template_params") or len(self.template_params) == 0:
465  return ""
466  return ", ".join([d["type"] + " " + d["name"] for d in self.template_params])
467 
468  def _className(self):
469  if not hasattr(self, "template_params") or len(self.template_params) == 0:
470  return self.name
471  return (
472  self.name
473  + " <"
474  + ", ".join([d["name"] for d in self.template_params])
475  + " >"
476  )
477 
478  def hasTypeDef(self, typename):
479  return typename in self.typedef
480 
481  def innerNamespace(self):
482  return self._className()
483 
484  def _memberfunc(self, member):
485  m = MemberDef(self.index, member, self)
486  if m.special:
487  self.special_funcs.append(m)
488  elif m.static:
489  self.static_funcs.append(m)
490  else:
491  self.member_funcs.append(m)
492 
493  def _writeClassDoc(self, output):
494  docstring = self.index.xml_docstring.getDocString(
495  self.definition.find("briefdescription"),
496  self.definition.find("detaileddescription"),
497  self.index.output,
498  )
499  attribute_docstrings = ""
500  for member in self.attributes:
501  _dc = self.index.xml_docstring.getDocString(
502  member.find("briefdescription"),
503  member.find("detaileddescription"),
504  self.index.output,
505  )
506  if len(_dc) == 0:
507  continue
508  attribute_docstrings += template_class_attribute_body.format(
509  attribute=member.find("name").text,
510  docstring=_dc,
511  )
512  if len(docstring) == 0 and len(attribute_docstrings) == 0:
513  return
514  output.out(
515  template_class_doc.format(
516  tplargs=self._templateDecl(),
517  classname=self._className(),
518  docstring=docstring,
519  attributes=attribute_docstrings,
520  )
521  )
522 
523  def write(self, output):
524  if not self.public:
525  return
526  if self.template_specialization:
527  output.warn(
528  "Disable class {} because template argument are not resolved for templated class specialization.".format(
529  self.name
530  )
531  )
532  return
533 
534  include = self.definition.find("includes")
535  if include is None:
536  output.err("Does not know where to write doc of", self.name)
537  return
538  output.open(include.text)
539  output.out(template_include_extern.format(filename=include.text))
540  output.out(template_open_namespace.format(namespace="doxygen"))
541 
542  # Write class doc
543  self._writeClassDoc(output)
544 
545  # Group member function by prototype
546  member_funcs = dict()
547  for m in self.member_funcs:
548  prototype = m.prototypekey()
549  if prototype in member_funcs:
550  member_funcs[prototype].append(m)
551  else:
552  member_funcs[prototype] = [
553  m,
554  ]
555 
556  classname_prefix = self._className() + "::"
557 
558  for member in self.special_funcs:
559  docstring = member.s_docstring()
560  argnamesstring = member.s_argnamesstring()
561  if len(docstring) == 0 and len(argnamesstring) == 0:
562  continue
563  if member.s_name()[0] == "~":
564  output.out(
565  template_destructor_doc.format(
566  tplargs=self._templateDecl(),
567  classname_prefix=self._className(),
568  docstring=docstring,
569  )
570  )
571  else:
572  output.out(
573  template_constructor_doc.format(
574  tplargs=", ".join(
575  [
576  d["type"] + " " + d["name"]
577  for d in self.template_params + member.template_params
578  ]
579  ),
580  nargs=len(member.params),
581  comma=", " if len(member.params) > 0 else "",
582  classname_prefix=self._className(),
583  argsstring=member.s_args(),
584  docstring=docstring,
585  argnamesstring=argnamesstring,
586  )
587  )
588 
589  for prototype, members in member_funcs.items():
590  # remove undocumented members
591  documented_members = []
592  docstrings = []
593  argnamesstrings = []
594  for member in members:
595  docstring = member.s_docstring()
596  argnamesstring = member.s_argnamesstring()
597  if len(docstring) == 0 and len(argnamesstring) == 0:
598  continue
599  documented_members.append(member)
600  docstrings.append(docstring)
601  argnamesstrings.append(argnamesstring)
602  if len(documented_members) == 0:
603  continue
604 
605  # Write docstrings
606  body = "".join(
607  [
608  template_member_func_doc_body.format(
609  classname_prefix=classname_prefix,
610  membername=member.s_name(),
611  docstring=docstring,
612  rettype=member.s_rettype(),
613  argsstring=member.s_prototypeArgs(),
614  )
615  for member, docstring in zip(documented_members, docstrings)
616  ]
617  )
618 
619  member = members[0]
620  tplargs = ", ".join(
621  [
622  d["type"] + " " + d["name"]
623  for d in self.template_params + member.template_params
624  ]
625  )
626  output.out(
627  template_member_func_doc.format(
628  template=(
629  "template <{}>\n".format(tplargs) if len(tplargs) > 0 else ""
630  ),
631  rettype=member.s_rettype(),
632  classname_prefix=classname_prefix,
633  argsstring=member.s_prototypeArgs(),
634  body=body,
635  )
636  )
637 
638  # Write argnamesstrings
639  body = "".join(
640  [
641  template_member_func_args_body.format(
642  classname_prefix=classname_prefix,
643  membername=member.s_name(),
644  args=argnamesstring,
645  rettype=member.s_rettype(),
646  argsstring=member.s_prototypeArgs(),
647  )
648  for member, argnamesstring in zip(
649  documented_members, argnamesstrings
650  )
651  ]
652  )
653 
654  n_args = member.n_args()
655 
656  default_args = ", ".join(
657  [
658  """boost::python::arg("self")""",
659  ]
660  + ["""boost::python::arg("arg{}")""".format(i) for i in range(n_args)]
661  )
662  output.out(
663  template_member_func_args.format(
664  template=(
665  "template <{}>\n".format(tplargs) if len(tplargs) > 0 else ""
666  ),
667  rettype=member.s_rettype(),
668  n=n_args + 1,
669  default_args=default_args,
670  classname_prefix=classname_prefix,
671  argsstring=member.s_prototypeArgs(),
672  body=body,
673  )
674  )
675 
676  output.out(template_close_namespace.format(namespace="doxygen"))
677  output.close()
678 
679  def _attribute(self, member):
680  self.attributes.append(member)
681 
682 
683 class Index:
684  """
685  This class is responsible for generating the list of all C++-usable documented elements.
686  """
687 
688  def __init__(self, input, output):
689  self.tree = etree.parse(input)
690  self.directory = path.dirname(input)
692  self.compounds = list()
693  self.references = dict()
694  self.output = output
695 
696  def parseCompound(self):
697  for compound in self.tree.getroot().iterchildren("compound"):
698  if compound.attrib["kind"] in ["class", "struct"]:
699  obj = ClassCompound(compound, self)
700  elif compound.attrib["kind"] == "namespace":
701  obj = NamespaceCompound(compound, self)
702  if obj.id not in self.compounds:
703  self.compounds.append(obj.id)
704  self.registerReference(obj)
705 
706  def write(self):
707  # Header
708 
709  self.output.open("doxygen_xml_parser_for_cmake.hh")
710  # self.output.out ("// Generated on {}".format (asctime()))
711  self.output.close()
712 
713  # Implement template specialization for classes and member functions
714  for id in self.compounds:
715  compound = self.references[id]
716  compound.write(self.output)
717 
718  self.output.open("functions.h")
719 
720  # Implement template specialization for static functions
721  static_funcs = dict()
722  prototypes = list()
723  includes = list()
724  for id in self.compounds:
725  compound = self.references[id]
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:
732  continue
733  prototype = m.prototypekey()
734  if prototype in static_funcs:
735  static_funcs[prototype].append((m, docstring))
736  else:
737  static_funcs[prototype] = [
738  (m, docstring),
739  ]
740  prototypes.append(prototype)
741 
742  self.output.out(
743  "".join(
744  [
745  template_include_extern.format(filename=filename)
746  for filename in includes
747  ]
748  )
749  )
750 
751  self.output.out(template_open_namespace.format(namespace="doxygen"))
752 
753  for prototype in prototypes:
754  member_and_docstring_s = static_funcs[prototype]
755  body = "".join(
756  [
757  template_static_func_doc_body.format(
758  namespace=member.parent.innerNamespace(),
759  membername=member.s_name(),
760  docstring=docstring,
761  rettype=member.s_rettype(),
762  argsstring=member.s_prototypeArgs(),
763  )
764  for member, docstring in member_and_docstring_s
765  ]
766  )
767 
768  member = member_and_docstring_s[0][0]
769  # TODO fix case of static method in templated class.
770  tplargs = ", ".join(
771  [
772  d["type"] + " " + d["name"]
773  for d in member.parent.template_params + member.template_params
774  ]
775  )
776  self.output.out(
777  template_static_func_doc.format(
778  template=(
779  "template <{}>\n".format(tplargs) if len(tplargs) > 0 else ""
780  ),
781  rettype=member.s_rettype(),
782  argsstring=member.s_prototypeArgs(),
783  body=body,
784  )
785  )
786 
787  self.output.out(template_close_namespace.format(namespace="doxygen"))
788  self.output.close()
789 
790  def registerReference(self, obj, overwrite=True):
791  if obj.id in self.references:
792  if obj.name != self.references[obj.id].name:
793  self.output.warn(
794  "!!!! Compounds " + obj.id + " already exists.",
795  obj.name,
796  self.references[obj.id].name,
797  )
798  else:
799  self.output.warn("Reference " + obj.id + " already exists.", obj.name)
800  if not overwrite:
801  return
802  self.references[obj.id] = obj
803 
804  def hasref(self, id):
805  return id in self.references
806 
807  def getref(self, id):
808  return self.references[id]
809 
810 
811 class OutputStreams(object):
812  def __init__(self, output_dir, warn, error, errorPrefix=""):
813  self.output_dir = output_dir
814  self._out = None
815  self._warn = warn
816  self._err = error
817  self.errorPrefix = errorPrefix
818 
819  self._created_files = dict()
820 
821  def open(self, name):
822  assert self._out is None, "You did not close the previous file"
823  import os
824 
825  fullname = os.path.join(self.output_dir, name)
826  dirname = os.path.dirname(fullname)
827  if not os.path.isdir(dirname):
828  os.makedirs(dirname)
829 
830  if name in self._created_files:
831  self._out = self._created_files[name]
832  else:
833  import codecs
834 
835  if sys.version_info >= (3,):
836  encoding = "utf-8"
837  else:
838  encoding = "latin1"
839  self._out = codecs.open(fullname, mode="w", encoding=encoding)
840  self._created_files[name] = self._out
841 
842  # Header
843  self.out(
844  template_file_header.format(
845  path=os.path.dirname(os.path.abspath(__file__)),
846  header_guard=makeHeaderGuard(name),
847  )
848  )
849 
850  def close(self):
851  self._out = None
852 
854  for n, f in self._created_files.items():
855  # Footer
856  self._out = f
857  self.out(
858  template_file_footer.format(
859  header_guard=makeHeaderGuard(n),
860  )
861  )
862  f.close()
863  self._created_files.clear()
864  self._out = None
865 
866  def out(self, *args):
867  if sys.version_info >= (3,):
868  print(*args, file=self._out)
869  else:
870  print(" ".join(str(arg) for arg in args).decode("latin1"), file=self._out)
871 
872  def warn(self, *args):
873  print(self.errorPrefix, *args, file=self._warn)
874 
875  def err(self, *args):
876  print(self.errorPrefix, *args, file=self._err)
877 
878 
879 if __name__ == "__main__":
880  import argparse
881 
882  parser = argparse.ArgumentParser(
883  description="Process Doxygen XML documentation and generate C++ code."
884  )
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()
888 
889  index = Index(
890  input=sys.argv[1],
891  output=OutputStreams(args.output_directory, sys.stdout, sys.stderr),
892  )
893  index.parseCompound()
894  index.write()
895  index.output.writeFooterAndCloseFiles()
896  assert index.output._out is None
doxygen_xml_parser.ClassCompound
Definition: doxygen_xml_parser.py:405
doxygen_xml_parser.NamespaceCompound.template_params
template_params
Definition: doxygen_xml_parser.py:355
doxygen_xml_parser.ClassCompound.member_funcs
member_funcs
Definition: doxygen_xml_parser.py:408
doxygen_xml_parser.Reference.name
name
Definition: doxygen_xml_parser.py:146
doxygen_xml_parser.MemberDef.s_argnamesstring
def s_argnamesstring(self)
Definition: doxygen_xml_parser.py:318
doxygen_xml_parser.MemberDef.const
const
Definition: doxygen_xml_parser.py:211
doxygen_xml_parser.ClassCompound.struct
struct
Definition: doxygen_xml_parser.py:413
doxygen_xml_parser.OutputStreams.output_dir
output_dir
Definition: doxygen_xml_parser.py:813
doxygen_xml_parser.CompoundBase.tree
tree
Definition: doxygen_xml_parser.py:340
doxygen_xml_parser.NamespaceCompound.__init__
def __init__(self, *args)
Definition: doxygen_xml_parser.py:350
doxygen_xml_parser.OutputStreams.errorPrefix
errorPrefix
Definition: doxygen_xml_parser.py:817
doxygen_xml_parser.ClassCompound.template_params
template_params
Definition: doxygen_xml_parser.py:457
doxygen_xml_parser.OutputStreams._out
_out
Definition: doxygen_xml_parser.py:814
doxygen_xml_parser.NamespaceCompound.parseEnumSection
def parseEnumSection(self, section)
Definition: doxygen_xml_parser.py:368
doxygen_xml_parser.ClassCompound.special_funcs
special_funcs
Definition: doxygen_xml_parser.py:410
doxygen_xml_parser.NamespaceCompound.write
def write(self, output)
Definition: doxygen_xml_parser.py:401
doxygen_xml_parser._templateParamToDict
def _templateParamToDict(param)
Definition: doxygen_xml_parser.py:90
doxygen_xml_parser.OutputStreams.writeFooterAndCloseFiles
def writeFooterAndCloseFiles(self)
Definition: doxygen_xml_parser.py:853
doxygen_xml_parser.ClassCompound._templateParams
def _templateParams(self, tpl)
Definition: doxygen_xml_parser.py:455
doxygen_xml_parser.MemberDef.__init__
def __init__(self, index, memberdefxml, parent)
Definition: doxygen_xml_parser.py:202
doxygen_xml_parser.MemberDef.rettype
rettype
Definition: doxygen_xml_parser.py:213
doxygen_xml_parser.MemberDef.prototypekey
def prototypekey(self)
Definition: doxygen_xml_parser.py:235
doxygen_xml_parser.ClassCompound.hasTypeDef
def hasTypeDef(self, typename)
Definition: doxygen_xml_parser.py:478
doxygen_xml_parser.Index.__init__
def __init__(self, input, output)
Definition: doxygen_xml_parser.py:688
doxygen_xml_parser.MemberDef.s_tpldecl
def s_tpldecl(self)
Definition: doxygen_xml_parser.py:279
doxygen_xml_parser.OutputStreams.__init__
def __init__(self, output_dir, warn, error, errorPrefix="")
Definition: doxygen_xml_parser.py:812
doxygen_xml_parser.CompoundBase.filename
filename
Definition: doxygen_xml_parser.py:339
doxygen_xml_parser.NamespaceCompound.innerNamespace
def innerNamespace(self)
Definition: doxygen_xml_parser.py:398
doxygen_xml_parser.Index.compounds
compounds
Definition: doxygen_xml_parser.py:692
doxygen_xml_parser.Index
Definition: doxygen_xml_parser.py:683
doxygen_xml_parser.OutputStreams
Definition: doxygen_xml_parser.py:811
doxygen_xml_parser.CompoundBase.compound
compound
Definition: doxygen_xml_parser.py:338
doxygen_xml_parser.Index.write
def write(self)
Definition: doxygen_xml_parser.py:706
doxygen_xml_parser.MemberDef.s_docstring
def s_docstring(self)
Definition: doxygen_xml_parser.py:308
doxygen_xml_parser.Reference
Definition: doxygen_xml_parser.py:143
doxygen_xml_parser.MemberDef._templateParams
def _templateParams(self, tpl)
Definition: doxygen_xml_parser.py:227
doxygen_xml_parser.ClassCompound.template_specialization
template_specialization
Definition: doxygen_xml_parser.py:415
doxygen_xml_parser.ClassCompound._className
def _className(self)
Definition: doxygen_xml_parser.py:468
doxygen_xml_parser.CompoundBase.definition
definition
Definition: doxygen_xml_parser.py:341
xml_docstring.XmlDocString
Definition: xml_docstring.py:1
doxygen_xml_parser.CompoundBase
Definition: doxygen_xml_parser.py:336
doxygen_xml_parser.MemberDef.template_params
template_params
Definition: doxygen_xml_parser.py:229
doxygen_xml_parser.Index.xml_docstring
xml_docstring
Definition: doxygen_xml_parser.py:691
doxygen_xml_parser.OutputStreams.open
def open(self, name)
Definition: doxygen_xml_parser.py:821
doxygen_xml_parser.ClassCompound.static_funcs
static_funcs
Definition: doxygen_xml_parser.py:409
doxygen_xml_parser.MemberDef.params
params
Definition: doxygen_xml_parser.py:214
doxygen_xml_parser.makeHeaderGuard
def makeHeaderGuard(filename)
Definition: doxygen_xml_parser.py:126
doxygen_xml_parser.NamespaceCompound
Definition: doxygen_xml_parser.py:349
doxygen_xml_parser.ClassCompound.attributes
attributes
Definition: doxygen_xml_parser.py:411
doxygen_xml_parser.MemberDef.xml
xml
Definition: doxygen_xml_parser.py:210
doxygen_xml_parser.Reference.id
id
Definition: doxygen_xml_parser.py:145
doxygen_xml_parser.ClassCompound.innerNamespace
def innerNamespace(self)
Definition: doxygen_xml_parser.py:481
doxygen_xml_parser.MemberDef
Definition: doxygen_xml_parser.py:201
doxygen_xml_parser.ClassCompound.public
public
Definition: doxygen_xml_parser.py:414
doxygen_xml_parser.OutputStreams.out
def out(self, *args)
Definition: doxygen_xml_parser.py:866
doxygen_xml_parser.MemberDef.s_prototypeArgs
def s_prototypeArgs(self)
Definition: doxygen_xml_parser.py:249
doxygen_xml_parser.Index.getref
def getref(self, id)
Definition: doxygen_xml_parser.py:807
doxygen_xml_parser.Index.output
output
Definition: doxygen_xml_parser.py:694
doxygen_xml_parser.Index.hasref
def hasref(self, id)
Definition: doxygen_xml_parser.py:804
doxygen_xml_parser.NamespaceCompound.enums
enums
Definition: doxygen_xml_parser.py:353
doxygen_xml_parser.ClassCompound.typedef
typedef
Definition: doxygen_xml_parser.py:416
doxygen_xml_parser.Index.parseCompound
def parseCompound(self)
Definition: doxygen_xml_parser.py:696
doxygen_xml_parser.OutputStreams.warn
def warn(self, *args)
Definition: doxygen_xml_parser.py:872
doxygen_xml_parser.Index.registerReference
def registerReference(self, obj, overwrite=True)
Definition: doxygen_xml_parser.py:790
doxygen_xml_parser.MemberDef.include
def include(self)
Definition: doxygen_xml_parser.py:330
doxygen_xml_parser.NamespaceCompound.typedefs
typedefs
Definition: doxygen_xml_parser.py:352
doxygen_xml_parser.ClassCompound._templateDecl
def _templateDecl(self)
Definition: doxygen_xml_parser.py:463
doxygen_xml_parser.Reference.xmlToType
def xmlToType(self, node, array=None, parentClass=None, tplargs=None)
Definition: doxygen_xml_parser.py:149
doxygen_xml_parser.MemberDef.n_args
def n_args(self)
Definition: doxygen_xml_parser.py:315
doxygen_xml_parser.Index.references
references
Definition: doxygen_xml_parser.py:693
doxygen_xml_parser.ClassCompound._writeClassDoc
def _writeClassDoc(self, output)
Definition: doxygen_xml_parser.py:493
doxygen_xml_parser.Reference.index
index
Definition: doxygen_xml_parser.py:147
doxygen_xml_parser.Index.tree
tree
Definition: doxygen_xml_parser.py:689
doxygen_xml_parser.format_description
def format_description(brief, detailed)
Definition: doxygen_xml_parser.py:130
doxygen_xml_parser.ClassCompound.write
def write(self, output)
Definition: doxygen_xml_parser.py:523
doxygen_xml_parser.str
str
Definition: doxygen_xml_parser.py:885
doxygen_xml_parser.OutputStreams._warn
_warn
Definition: doxygen_xml_parser.py:815
doxygen_xml_parser.MemberDef.s_rettype
def s_rettype(self)
Definition: doxygen_xml_parser.py:284
doxygen_xml_parser.NamespaceCompound.static_funcs
static_funcs
Definition: doxygen_xml_parser.py:354
doxygen_xml_parser.OutputStreams.err
def err(self, *args)
Definition: doxygen_xml_parser.py:875
doxygen_xml_parser.OutputStreams._err
_err
Definition: doxygen_xml_parser.py:816
doxygen_xml_parser.ClassCompound._memberfunc
def _memberfunc(self, member)
Definition: doxygen_xml_parser.py:484
doxygen_xml_parser.OutputStreams._created_files
_created_files
Definition: doxygen_xml_parser.py:819
doxygen_xml_parser.MemberDef.s_args
def s_args(self)
Definition: doxygen_xml_parser.py:252
doxygen_xml_parser.Reference.__init__
def __init__(self, index, id=None, name=None)
Definition: doxygen_xml_parser.py:144
doxygen_xml_parser.MemberDef.special
special
Definition: doxygen_xml_parser.py:220
doxygen_xml_parser.NamespaceCompound.parseTypedefSection
def parseTypedefSection(self, section)
Definition: doxygen_xml_parser.py:384
doxygen_xml_parser.ClassCompound.__init__
def __init__(self, *args)
Definition: doxygen_xml_parser.py:406
doxygen_xml_parser.OutputStreams.close
def close(self)
Definition: doxygen_xml_parser.py:850
doxygen_xml_parser.MemberDef.static
static
Definition: doxygen_xml_parser.py:212
doxygen_xml_parser.NamespaceCompound.parseFuncSection
def parseFuncSection(self, section)
Definition: doxygen_xml_parser.py:394
doxygen_xml_parser.CompoundBase.__init__
def __init__(self, compound, index)
Definition: doxygen_xml_parser.py:337
doxygen_xml_parser.MemberDef.parent
parent
Definition: doxygen_xml_parser.py:208
doxygen_xml_parser.Index.directory
directory
Definition: doxygen_xml_parser.py:690
doxygen_xml_parser.MemberDef.s_name
def s_name(self)
Definition: doxygen_xml_parser.py:305
doxygen_xml_parser.ClassCompound._attribute
def _attribute(self, member)
Definition: doxygen_xml_parser.py:679


hpp-fcl
Author(s):
autogenerated on Sat Nov 23 2024 03:44:58