mirror of
https://github.com/sphinx-doc/sphinx.git
synced 2025-02-25 18:55:22 -06:00
C++, parse explicit casts and typeid in expression
This commit is contained in:
1
CHANGES
1
CHANGES
@@ -35,6 +35,7 @@ Bugs fixed
|
||||
* #4563: autosummary: Incorrect end of line punctuation detection
|
||||
* #4577: Enumerated sublists with explicit start with wrong number
|
||||
* #4641: A external link in TOC cannot contain "?" with ``:glob:`` option
|
||||
* C++, add missing parsing of explicit casts and typeid in expression parsing.
|
||||
|
||||
Testing
|
||||
--------
|
||||
|
||||
@@ -530,6 +530,12 @@ _expression_bin_ops = [
|
||||
_expression_unary_ops = ["++", "--", "*", "&", "+", "-", "!", "~"]
|
||||
_expression_assignment_ops = ["=", "*=", "/=", "%=", "+=", "-=",
|
||||
">>=", "<<=", "&=", "^=", "|="]
|
||||
_id_explicit_cast = {
|
||||
'dynamic_cast': 'dc',
|
||||
'static_cast': 'sc',
|
||||
'const_cast': 'cc',
|
||||
'reinterpret_cast': 'rc'
|
||||
}
|
||||
|
||||
|
||||
class NoOldIdError(UnicodeMixin, Exception):
|
||||
@@ -1027,6 +1033,56 @@ class ASTNoexceptExpr(ASTBase):
|
||||
signode.append(nodes.Text(')'))
|
||||
|
||||
|
||||
class ASTExplicitCast(ASTBase):
|
||||
def __init__(self, cast, typ, expr):
|
||||
assert cast in _id_explicit_cast
|
||||
self.cast = cast
|
||||
self.typ = typ
|
||||
self.expr = expr
|
||||
|
||||
def __unicode__(self):
|
||||
res = [self.cast]
|
||||
res.append('<')
|
||||
res.append(text_type(self.typ))
|
||||
res.append('>(')
|
||||
res.append(text_type(self.expr))
|
||||
res.append(')')
|
||||
return u''.join(res)
|
||||
|
||||
def get_id(self, version):
|
||||
return (_id_explicit_cast[self.cast] +
|
||||
self.typ.get_id(version) +
|
||||
self.expr.get_id(version))
|
||||
|
||||
def describe_signature(self, signode, mode, env, symbol):
|
||||
signode.append(nodes.Text(self.cast))
|
||||
signode.append(nodes.Text('<'))
|
||||
self.typ.describe_signature(signode, mode, env, symbol)
|
||||
signode.append(nodes.Text('>'))
|
||||
signode.append(nodes.Text('('))
|
||||
self.expr.describe_signature(signode, mode, env, symbol)
|
||||
signode.append(nodes.Text(')'))
|
||||
|
||||
|
||||
class ASTTypeId(ASTBase):
|
||||
def __init__(self, typeOrExpr, isType):
|
||||
self.typeOrExpr = typeOrExpr
|
||||
self.isType = isType
|
||||
|
||||
def __unicode__(self):
|
||||
return 'typeid(' + text_type(self.typeOrExpr) + ')'
|
||||
|
||||
def get_id(self, version):
|
||||
prefix = 'ti' if self.isType else 'te'
|
||||
return prefix + self.typeOrExpr.get_id(version)
|
||||
|
||||
def describe_signature(self, signode, mode, env, symbol):
|
||||
signode.append(nodes.Text('typeid'))
|
||||
signode.append(nodes.Text('('))
|
||||
self.typeOrExpr.describe_signature(signode, mode, env, symbol)
|
||||
signode.append(nodes.Text(')'))
|
||||
|
||||
|
||||
class ASTPostfixCallExpr(ASTBase):
|
||||
def __init__(self, exprs):
|
||||
self.exprs = exprs
|
||||
@@ -4096,39 +4152,94 @@ class DefinitionParser(object):
|
||||
# | "typeid" "(" expression ")"
|
||||
# | "typeid" "(" type-id ")"
|
||||
|
||||
# TODO: try the productions with prefixes:
|
||||
# dynamic_cast, static_cast, reinterpret_cast, const_cast, typeid
|
||||
prefixType = None
|
||||
pos = self.pos
|
||||
try:
|
||||
prefix = self._parse_primary_expression()
|
||||
prefixType = 'expr'
|
||||
except DefinitionError as eOuter:
|
||||
self.pos = pos
|
||||
prefix = None # type: Any
|
||||
self.skip_ws()
|
||||
|
||||
cast = None
|
||||
for c in _id_explicit_cast:
|
||||
if self.skip_word_and_ws(c):
|
||||
cast = c
|
||||
break
|
||||
if cast is not None:
|
||||
prefixType = "cast"
|
||||
if not self.skip_string("<"):
|
||||
self.fail("Expected '<' afer '%s'." % cast)
|
||||
typ = self._parse_type(False)
|
||||
self.skip_ws()
|
||||
if not self.skip_string_and_ws(">"):
|
||||
self.fail("Expected '>' after type in '%s'." % cast)
|
||||
if not self.skip_string("("):
|
||||
self.fail("Expected '(' in '%s'." % cast)
|
||||
|
||||
def parser():
|
||||
return self._parse_expression(inTemplate=False)
|
||||
expr = self._parse_expression_fallback([')'], parser)
|
||||
self.skip_ws()
|
||||
if not self.skip_string(")"):
|
||||
self.fail("Expected ')' to end '%s'." % cast)
|
||||
prefix = ASTExplicitCast(cast, typ, expr)
|
||||
elif self.skip_word_and_ws("typeid"):
|
||||
prefixType = "typeid"
|
||||
if not self.skip_string_and_ws('('):
|
||||
self.fail("Expected '(' after 'typeid'.")
|
||||
pos = self.pos
|
||||
try:
|
||||
# we are potentially casting, so save parens for us
|
||||
# TODO: hmm, would we need to try both with operatorCast and with None?
|
||||
prefix = self._parse_type(False, 'operatorCast')
|
||||
prefixType = 'typeOperatorCast'
|
||||
# | simple-type-specifier "(" expression-list [opt] ")"
|
||||
# | simple-type-specifier braced-init-list
|
||||
# | typename-specifier "(" expression-list [opt] ")"
|
||||
# | typename-specifier braced-init-list
|
||||
self.skip_ws()
|
||||
if self.current_char != '(' and self.current_char != '{':
|
||||
self.fail("Expecting '(' or '{' after type in cast expression.")
|
||||
except DefinitionError as eInner:
|
||||
typ = self._parse_type(False)
|
||||
prefix = ASTTypeId(typ, isType=True)
|
||||
if not self.skip_string(')'):
|
||||
self.fail("Expected ')' to end 'typeid' of type.")
|
||||
except DefinitionError as eType:
|
||||
self.pos = pos
|
||||
header = "Error in postfix expression, expected primary expression or type."
|
||||
errors = []
|
||||
errors.append((eOuter, "If primary expression"))
|
||||
errors.append((eInner, "If type"))
|
||||
raise self._make_multi_error(errors, header)
|
||||
try:
|
||||
|
||||
def parser():
|
||||
return self._parse_expression(inTemplate=False)
|
||||
expr = self._parse_expression_fallback([')'], parser)
|
||||
prefix = ASTTypeId(expr, isType=False)
|
||||
if not self.skip_string(')'):
|
||||
self.fail("Expected ')' to end 'typeid' of expression.")
|
||||
except DefinitionError as eExpr:
|
||||
self.pos = pos
|
||||
header = "Error in 'typeid(...)'."
|
||||
header += " Expected type or expression."
|
||||
errors = []
|
||||
errors.append((eType, "If type"))
|
||||
errors.append((eExpr, "If expression"))
|
||||
raise self._make_multi_error(errors, header)
|
||||
else: # a primary expression or a type
|
||||
pos = self.pos
|
||||
try:
|
||||
prefix = self._parse_primary_expression()
|
||||
prefixType = 'expr'
|
||||
except DefinitionError as eOuter:
|
||||
self.pos = pos
|
||||
try:
|
||||
# we are potentially casting, so save parens for us
|
||||
# TODO: hmm, would we need to try both with operatorCast and with None?
|
||||
prefix = self._parse_type(False, 'operatorCast')
|
||||
prefixType = 'typeOperatorCast'
|
||||
# | simple-type-specifier "(" expression-list [opt] ")"
|
||||
# | simple-type-specifier braced-init-list
|
||||
# | typename-specifier "(" expression-list [opt] ")"
|
||||
# | typename-specifier braced-init-list
|
||||
self.skip_ws()
|
||||
if self.current_char != '(' and self.current_char != '{':
|
||||
self.fail("Expecting '(' or '{' after type in cast expression.")
|
||||
except DefinitionError as eInner:
|
||||
self.pos = pos
|
||||
header = "Error in postfix expression,"
|
||||
header += " expected primary expression or type."
|
||||
errors = []
|
||||
errors.append((eOuter, "If primary expression"))
|
||||
errors.append((eInner, "If type"))
|
||||
raise self._make_multi_error(errors, header)
|
||||
|
||||
# and now parse postfixes
|
||||
postFixes = []
|
||||
while True:
|
||||
self.skip_ws()
|
||||
if prefixType == 'expr':
|
||||
if prefixType in ['expr', 'cast', 'typeid']:
|
||||
if self.skip_string_and_ws('['):
|
||||
expr = self._parse_expression(inTemplate=False)
|
||||
self.skip_ws()
|
||||
|
||||
@@ -137,7 +137,12 @@ def test_expressions():
|
||||
exprCheck('a->b->c', 'ptpt1a1b1c')
|
||||
exprCheck('i++', 'pp1i')
|
||||
exprCheck('i--', 'mm1i')
|
||||
# TODO, those with prefixes
|
||||
exprCheck('dynamic_cast<T&>(i)++', 'ppdcR1T1i')
|
||||
exprCheck('static_cast<T&>(i)++', 'ppscR1T1i')
|
||||
exprCheck('reinterpret_cast<T&>(i)++', 'pprcR1T1i')
|
||||
exprCheck('const_cast<T&>(i)++', 'ppccR1T1i')
|
||||
exprCheck('typeid(T).name', 'dtti1T4name')
|
||||
exprCheck('typeid(a + b).name', 'dttepl1a1b4name')
|
||||
# unary
|
||||
exprCheck('++5', 'pp_L5E')
|
||||
exprCheck('--5', 'mm_L5E')
|
||||
|
||||
Reference in New Issue
Block a user