Properly parses operator definitions now. 'std:string

module::class::operator std::string()' is picked up properly.
This commit is contained in:
Armin Ronacher
2010-02-28 21:04:35 +01:00
parent be39ba81e6
commit bd576bbe5d

View File

@@ -23,10 +23,16 @@ from sphinx.util.nodes import make_refnode
from sphinx.util.docfields import Field, TypedField
_identifier_re = re.compile(r'[a-zA-Z_][a-zA-Z0-9_]*')
_identifier_re = re.compile(r'(~?[a-zA-Z_][a-zA-Z0-9_]*)')
_whitespace_re = re.compile(r'\s+(?u)')
_string_re = re.compile(r"[LuU8]?('([^'\\]*(?:\\.[^'\\]*)*)'"
r'|"([^"\\]*(?:\\.[^"\\]*)*)")', re.S)
_operator_re = re.compile(r'''(?x)
\[\s*\]
| \(\s*\)
| [!<>=/*%+-|&^]=?
| <<=? | >>=? | ~ | ^ | & | && | \| | \|\|
''')
class DefinitionError(Exception):
@@ -99,6 +105,15 @@ class _RefDefExpr(_DefExpr):
return u'%s&' % self.typename
class _CastOpDefExpr(_DefExpr):
def __init__(self, typename):
self.typename = typename
def __unicode__(self):
return u'operator %s' % self.typename
class _TemplateDefExpr(_DefExpr):
def __init__(self, typename, args):
@@ -153,7 +168,7 @@ class DefinitionParser(object):
'typename': None,
'unsigned': set(('char', 'int', 'long')),
'signed': set(('char', 'int', 'long')),
'short': set(('int',)),
'short': set(('int', 'short')),
'long': set(('int', 'long'))
}
@@ -206,10 +221,30 @@ class DefinitionParser(object):
if self.last_match is not None:
return self.last_match.group()
def _parse_operator(self):
# thank god, a regular operator definition
if self.match(_operator_re):
return _NameDefExpr('operator' +
_whitespace_re.sub('', self.matched_text))
# oh well, looks like a cast operator definition.
# In that case, eat another type.
type = self._parse_type()
return _CastOpDefExpr(type)
def _parse_name(self):
if not self.match(_identifier_re):
self.fail('expected name')
return _NameDefExpr(self.matched_text)
identifier = self.matched_text
# strictly speaking, operators are not regular identifiers
# but because operator is a keyword, it might not be used
# for variable names anyways, so we can safely parse the
# operator here as identifier
if identifier == 'operator':
return self._parse_operator()
return _NameDefExpr(identifier)
def _parse_type_expr(self):
typename = self._parse_name()
@@ -387,6 +422,9 @@ class DefinitionParser(object):
name = self._parse_type()
return rv, _FunctionDefExpr(name, *self._parse_signature())
def parse_typename(self):
return self._parse_type()
def assert_end(self):
self.skip_ws()
if not self.eof:
@@ -397,11 +435,49 @@ class DefinitionParser(object):
class CPPObject(ObjectDescription):
"""Description of a C++ language object."""
def _attach_return_type(self, node, return_type):
def _attach_type(self, node, type):
# XXX: link? how could we do that
text = unicode(return_type) + u' '
tnode = nodes.Text(text, text)
node += tnode
text = unicode(type) + u' '
pnode = addnodes.pending_xref(
'', refdomain='cpp', reftype='type',
reftarget=text, modname=None, classname=None)
pnode += nodes.Text(text)
node += pnode
def handle_signature(self, sig, signode):
"""Transform a C++ signature into RST nodes."""
parser = DefinitionParser(sig)
typename = parser.parse_typename()
parser.assert_end()
signode += addnodes.desc_type('', '')
self._attach_type(signode, typename)
return unicode(typename)
class CPPTypedObject(CPPObject):
def _attach_var(self, node, var):
owner, name = var.name.split_owner()
varname = unicode(name)
if owner is not None:
owner = unicode(owner) + '::'
node += addnodes.desc_addname(owner, owner)
node += addnodes.desc_name(varname, varname)
def handle_signature(self, sig, signode):
"""Transform a C++ signature into RST nodes."""
parser = DefinitionParser(sig)
rv, var = parser.parse_variable()
parser.assert_end()
signode += addnodes.desc_type('', '')
self._attach_type(signode, rv)
self._attach_var(signode, var)
return str(func.name)
class CPPFunctionObject(CPPTypedObject):
def _attach_function(self, node, func):
owner, name = func.name.split_owner()
@@ -409,16 +485,17 @@ class CPPObject(ObjectDescription):
if owner is not None:
owner = unicode(owner) + '::'
node += addnodes.desc_addname(owner, owner)
node += addnodes.desc_name(funcname, funcname)
else:
node += addnodes.desc_name(funcname, funcname)
node += addnodes.desc_name(funcname, funcname)
paramlist = addnodes.desc_parameterlist()
for arg in func.signature:
# XXX: is that okay? maybe more semantic here
strarg = unicode(arg)
param = addnodes.desc_parameter('', '', noemph=True)
param += nodes.emphasis(strarg, strarg)
if arg.type is not None:
self._attach_type(param, arg.type)
param += nodes.emphasis(unicode(arg.name), unicode(arg.name))
if arg.default is not None:
def_ = u'=' + unicode(arg.default)
param += nodes.emphasis(def_, def_)
paramlist += param
node += paramlist
@@ -428,13 +505,13 @@ class CPPObject(ObjectDescription):
node += addnodes.desc_addname(' = 0', ' = 0')
def handle_signature(self, sig, signode):
"""Transform a C (or C++) signature into RST nodes."""
"""Transform a C++ signature into RST nodes."""
parser = DefinitionParser(sig)
rv, func = parser.parse_function()
parser.assert_end()
signode += addnodes.desc_type('', '')
self._attach_return_type(signode, rv)
self._attach_type(signode, rv)
self._attach_function(signode, func)
return str(func.name)
@@ -447,18 +524,16 @@ class CPPDomain(Domain):
'class': ObjType(l_('C++ class'), 'class'),
'function': ObjType(l_('C++ function'), 'func'),
'member': ObjType(l_('C++ member'), 'member'),
'macro': ObjType(l_('C++ macro'), 'macro'),
'type': ObjType(l_('C++ type'), 'type'),
'var': ObjType(l_('C++ variable'), 'data'),
}
directives = {
'class': CPPObject,
'function': CPPObject,
'member': CPPObject,
'macro': CPPObject,
'type': CPPObject,
'var': CPPObject,
'function': CPPFunctionObject,
'member': CPPTypedObject,
'type': CPPTypedObject,
'var': CPPTypedObject,
}
roles = {
'class': XRefRole(),