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


hpp-fcl
Author(s):
autogenerated on Fri Jan 26 2024 03:46:13