Commit 2a3a2356 authored by François Grisez's avatar François Grisez

Add code in wrappers generator for reference handling in docstrings

parent 5e077c08
......@@ -480,6 +480,18 @@ class CParser(object):
else:
self.classesIndex[_class.name] = None
self.methodsIndex = {}
for _class in self.cProject.classes:
for funcname in _class.classMethods:
self.methodsIndex[funcname] = None
for funcname in _class.instanceMethods:
self.methodsIndex[funcname] = None
for _property in _class.properties.values():
if _property.setter is not None:
self.methodsIndex[_property.setter.name] = None
if _property.getter is not None:
self.methodsIndex[_property.getter.name] = None
name = NamespaceName()
name.from_snake_case('linphone')
......@@ -507,9 +519,24 @@ class CParser(object):
pass
except Error as e:
print('Could not parse \'{0}\' class: {1}'.format(_class.name, e.args[0]))
self._clean_all_indexes()
self._fix_all_types()
self._fix_all_docs()
def _clean_all_indexes(self):
for index in [self.classesIndex, self.interfacesIndex, self.methodsIndex]:
self._clean_index(index)
def _clean_index(self, index):
keysToRemove = []
for key in index.keys():
if index[key] is None:
keysToRemove.append(key)
for key in keysToRemove:
del index[key]
def _class_is_refcountable(self, _class):
if _class.name in self.forcedRefcountableClasses:
......@@ -576,6 +603,14 @@ class CParser(object):
else:
raise Error('bctbx_list_t type without specified contained type')
def _fix_all_docs(self):
for _class in self.classesIndex.values():
if _class.briefDescription is not None:
_class.briefDescription.resolve_all_references(self)
for method in self.methodsIndex.values():
if method.briefDescription is not None:
method.briefDescription.resolve_all_references(self)
def parse_enum(self, cenum):
if 'associatedTypedef' in dir(cenum):
nameStr = cenum.associatedTypedef.name
......@@ -750,6 +785,7 @@ class CParser(object):
absArg = Argument(argName, aType)
method.add_arguments(absArg)
self.methodsIndex[cfunction.name] = method
return method
def parse_type(self, cType):
......
......@@ -246,6 +246,7 @@ class Project:
self.__events = []
self.__functions = []
self.classes = []
self.docparser = metadoc.Parser()
def add(self, elem):
if isinstance(elem, CClass):
......@@ -387,7 +388,7 @@ class Project:
if deprecatedNode is not None:
ev.deprecated = True
ev.briefDescription = ''.join(node.find('./briefdescription').itertext()).strip()
ev.briefDoc = metadoc.Description(node.find('./briefdescription'))
ev.briefDoc = self.docparser.parse_description(node.find('./briefdescription'))
ev.detailedDescription = self.__cleanDescription(node.find('./detaileddescription'))
return ev
......@@ -399,7 +400,7 @@ class Project:
if deprecatedNode is not None:
e.deprecated = True
e.briefDescription = ''.join(node.find('./briefdescription').itertext()).strip()
e.briefDoc = metadoc.Description(node.find('./briefdescription'))
e.briefDoc = self.docparser.parse_description(node.find('./briefdescription'))
e.detailedDescription = self.__cleanDescription(node.find('./detaileddescription'))
enumvalues = node.findall("enumvalue[@prot='public']")
for enumvalue in enumvalues:
......@@ -422,7 +423,7 @@ class Project:
if deprecatedNode is not None:
sm.deprecated = True
sm.briefDescription = ''.join(node.find('./briefdescription').itertext()).strip()
sm.briefDoc = metadoc.Description(node.find('./briefdescription'))
sm.briefDoc = self.docparser.parse_description(node.find('./briefdescription'))
sm.detailedDescription = self.__cleanDescription(node.find('./detaileddescription'))
return sm
......@@ -432,7 +433,7 @@ class Project:
if deprecatedNode is not None:
s.deprecated = True
s.briefDescription = ''.join(node.find('./briefdescription').itertext()).strip()
s.briefDoc = metadoc.Description(node.find('./briefdescription'))
s.briefDoc = self.docparser.parse_description(node.find('./briefdescription'))
s.detailedDescription = self.__cleanDescription(node.find('./detaileddescription'))
structmembers = node.findall("sectiondef/memberdef[@kind='variable'][@prot='public']")
for structmember in structmembers:
......@@ -501,7 +502,7 @@ class Project:
if deprecatedNode is not None:
f.deprecated = True
f.briefDescription = ''.join(node.find('./briefdescription').itertext()).strip()
f.briefDoc = metadoc.Description(node.find('./briefdescription'))
f.briefDoc = self.docparser.parse_description(node.find('./briefdescription'))
f.detailedDescription = self.__cleanDescription(node.find('./detaileddescription'))
return f
else:
......@@ -513,7 +514,7 @@ class Project:
if deprecatedNode is not None:
td.deprecated = True
td.briefDescription = ''.join(node.find('./briefdescription').itertext()).strip()
td.briefDoc = metadoc.Description(node.find('./briefdescription'))
td.briefDoc = self.docparser.parse_description(node.find('./briefdescription'))
td.detailedDescription = self.__cleanDescription(node.find('./detaileddescription'))
return td
return None
......@@ -573,7 +574,7 @@ class Project:
if deprecatedNode is not None:
f.deprecated = True
f.briefDescription = ''.join(node.find('./briefdescription').itertext()).strip()
f.briefDoc = metadoc.Description(node.find('./briefdescription'))
f.briefDoc = self.docparser.parse_description(node.find('./briefdescription'))
f.detailedDescription = self.__cleanDescription(node.find('./detaileddescription'))
if f.briefDescription == '' and ''.join(f.detailedDescription.itertext()).strip() == '':
return None
......
......@@ -16,45 +16,95 @@
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
import abstractapi
class Nil:
pass
class Reference:
def __init__(self, name):
self.cObjectName = name
def __init__(self, cname):
self.cname = cname
self.relatedObject = None
class ClassReference(Reference):
def resolve(self, api):
try:
self.relatedObject = api.classesIndex[self.cname]
except KeyError:
print('doc reference pointing on an unknown object ({0})'.format(self.cname))
class FunctionReference(Reference):
def resolve(self, api):
try:
self.relatedObject = api.methodsIndex[self.cname]
except KeyError:
print('doc reference pointing on an unknown object ({0})'.format(self.cname))
class Paragraph:
def __init__(self, node=None):
def __init__(self):
self.parts = []
if node is not None:
self.parse_doxygen_node(node)
def parse_doxygen_node(self, node):
for partNode in node.iter():
text = partNode.text
if text is not None:
self.parts.append(text)
if partNode is not node:
tail = partNode.tail
if tail is not None:
self.parts.append(tail)
def resolve_all_references(self, api):
for part in self.parts:
if isinstance(part, Reference):
part.resolve(api)
class Description:
def __init__(self, node=None):
def __init__(self):
self.paragraphs = []
if node is not None:
self.parse_doxygen_node(node)
def parse_doxygen_node(self, node):
def resolve_all_references(self, api):
for paragraph in self.paragraphs:
paragraph.resolve_all_references(api)
class Parser:
def parse_description(self, node):
desc = Description()
for paraNode in node.findall('./para'):
self.paragraphs.append(Paragraph(paraNode))
desc.paragraphs.append(self._parse_paragraph(paraNode))
return desc
def _parse_paragraph(self, node):
paragraph = Paragraph()
for partNode in node.iter():
if partNode is node:
text = partNode.text
if text is not None:
paragraph.parts.append(text)
else:
if partNode.tag == 'ref':
ref = self._parse_reference(partNode)
if ref is not None:
paragraph.parts.append(ref)
else:
text = partNode.text
if text is not None:
paragraph.parts.append(text)
tail = partNode.tail
if tail is not None:
paragraph.parts.append(tail)
return paragraph
def _parse_reference(self, node):
if node.text.endswith('()'):
return FunctionReference(node.text[0:-2])
else:
return ClassReference(node.text)
class Translator:
def __init__(self):
self.textWidth = 80
def translate(self, description):
if description is None:
return None
......@@ -63,21 +113,77 @@ class Translator:
for para in description.paragraphs:
if para is not description.paragraphs[0]:
lines.append('')
lines.append(''.join(para.parts))
lines.append(self._translate_paragraph(para))
self._tag_as_brief(lines)
lines = self._crop_text(lines, self.textWidth)
translatedDoc = {'lines': []}
for line in lines:
translatedDoc['lines'].append({'line': line})
return translatedDoc
def _translate_paragraph(self, para):
strPara = ''
for part in para.parts:
if isinstance(part, str):
strPara += part
elif isinstance(part, Reference):
try:
strPara += self._translate_reference(part)
except ReferenceTranslationError as e:
print('could not translate one reference in docstrings ({0})'.format(e.args[0]))
strPara += Translator._translate_reference(self, part)
else:
raise TypeError('untranslatable paragraph element ({0})'.format(part))
return strPara
def _translate_reference(self, ref):
if isinstance(ref, FunctionReference):
return ref.cname + '()'
else:
return ref.cname
def _crop_text(self, inputLines, width):
outputLines = []
for line in inputLines:
outputLines += self._split_line(line, width)
return outputLines
def _split_line(self, line, width):
lines = []
while len(line) > width:
cutIndex = line.rfind(' ', 0, width)
if cutIndex != -1:
lines.append(line[0:cutIndex])
line = line[cutIndex+1:]
else:
cutIndex = width
lines.append(line[0:cutIndex])
line = line[cutIndex:]
lines.append(line)
return lines
class ReferenceTranslationError(RuntimeError):
pass
class DoxygenCppTranslator(Translator):
def _tag_as_brief(self, lines):
if len(lines) > 0:
lines[0] = '@brief ' + lines[0]
def _translate_reference(self, ref):
if isinstance(ref.relatedObject, (abstractapi.Class, abstractapi.Enum)):
return '#' + ref.relatedObject.name.to_c()
elif isinstance(ref.relatedObject, abstractapi.Method):
return ref.relatedObject.name.to_c() + '()'
else:
raise ReferenceTranslationError(ref.cname)
class SandcastleCSharpTranslator(Translator):
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment