mirror of
https://github.com/sphinx-doc/sphinx.git
synced 2025-02-25 18:55:22 -06:00
C++, parse all fold expressions
This commit is contained in:
parent
8eb4ab0681
commit
e9df857531
1
CHANGES
1
CHANGES
@ -23,6 +23,7 @@ Bugs fixed
|
|||||||
* C++, fix hyperlinks for declarations involving east cv-qualifiers.
|
* C++, fix hyperlinks for declarations involving east cv-qualifiers.
|
||||||
* #5755: C++, fix duplicate declaration error on function templates with constraints
|
* #5755: C++, fix duplicate declaration error on function templates with constraints
|
||||||
in the return type.
|
in the return type.
|
||||||
|
* C++, parse unary right fold expressions and binary fold expressions.
|
||||||
|
|
||||||
Testing
|
Testing
|
||||||
--------
|
--------
|
||||||
|
@ -872,6 +872,7 @@ class ASTParenExpr(ASTBase):
|
|||||||
|
|
||||||
class ASTFoldExpr(ASTBase):
|
class ASTFoldExpr(ASTBase):
|
||||||
def __init__(self, leftExpr, op, rightExpr):
|
def __init__(self, leftExpr, op, rightExpr):
|
||||||
|
# type: (Any, str, Any) -> None
|
||||||
assert leftExpr is not None or rightExpr is not None
|
assert leftExpr is not None or rightExpr is not None
|
||||||
self.leftExpr = leftExpr
|
self.leftExpr = leftExpr
|
||||||
self.op = op
|
self.op = op
|
||||||
@ -895,10 +896,24 @@ class ASTFoldExpr(ASTBase):
|
|||||||
|
|
||||||
def get_id(self, version):
|
def get_id(self, version):
|
||||||
assert version >= 3
|
assert version >= 3
|
||||||
if version == 3 or version == 4:
|
if version == 3:
|
||||||
return text_type(self)
|
return text_type(self)
|
||||||
# TODO: find the right mangling scheme
|
# https://github.com/itanium-cxx-abi/cxx-abi/pull/67
|
||||||
assert False
|
res = []
|
||||||
|
if self.leftExpr is None: # (... op expr)
|
||||||
|
res.append('fl')
|
||||||
|
elif self.rightExpr is None: # (expr op ...)
|
||||||
|
res.append('fr')
|
||||||
|
else: # (expr op ... op expr)
|
||||||
|
# we don't check where the parameter pack is,
|
||||||
|
# we just always call this a binary left fold
|
||||||
|
res.append('fL')
|
||||||
|
res.append(_id_operator_v2[self.op])
|
||||||
|
if self.leftExpr:
|
||||||
|
res.append(self.leftExpr.get_id(version))
|
||||||
|
if self.rightExpr:
|
||||||
|
res.append(self.rightExpr.get_id(version))
|
||||||
|
return ''.join(res)
|
||||||
|
|
||||||
def describe_signature(self, signode, mode, env, symbol):
|
def describe_signature(self, signode, mode, env, symbol):
|
||||||
signode.append(nodes.Text('('))
|
signode.append(nodes.Text('('))
|
||||||
@ -4632,13 +4647,45 @@ class DefinitionParser(object):
|
|||||||
if not self.skip_string(')'):
|
if not self.skip_string(')'):
|
||||||
self.fail("Expected ')' in end of fold expression.")
|
self.fail("Expected ')' in end of fold expression.")
|
||||||
return ASTFoldExpr(None, op, rightExpr)
|
return ASTFoldExpr(None, op, rightExpr)
|
||||||
# TODO: actually try to parse fold expression
|
# try first parsing a unary right fold, or a binary fold
|
||||||
# fall back to a paren expression
|
pos = self.pos
|
||||||
res = self._parse_expression(inTemplate=False)
|
try:
|
||||||
|
self.skip_ws()
|
||||||
|
leftExpr = self._parse_cast_expression()
|
||||||
|
self.skip_ws()
|
||||||
|
if not self.match(_fold_operator_re):
|
||||||
|
self.fail("Expected fold operator after left expression in fold expression.")
|
||||||
|
op = self.matched_text
|
||||||
|
self.skip_ws()
|
||||||
|
if not self.skip_string_and_ws('...'):
|
||||||
|
self.fail("Expected '...' after fold operator in fold expression.")
|
||||||
|
except DefinitionError as eFold:
|
||||||
|
self.pos = pos
|
||||||
|
# fall back to a paren expression
|
||||||
|
try:
|
||||||
|
res = self._parse_expression(inTemplate=False)
|
||||||
|
self.skip_ws()
|
||||||
|
if not self.skip_string(')'):
|
||||||
|
self.fail("Expected ')' in end of parenthesized expression.")
|
||||||
|
except DefinitionError as eExpr:
|
||||||
|
raise self._make_multi_error([
|
||||||
|
(eFold, "If fold expression"),
|
||||||
|
(eExpr, "If parenthesized expression")
|
||||||
|
], "Error in fold expression or parenthesized expression.")
|
||||||
|
return ASTParenExpr(res)
|
||||||
|
# now it definitely is a fold expression
|
||||||
|
if self.skip_string(')'):
|
||||||
|
return ASTFoldExpr(leftExpr, op, None)
|
||||||
|
if not self.match(_fold_operator_re):
|
||||||
|
self.fail("Expected fold operator or ')' after '...' in fold expression.")
|
||||||
|
if op != self.matched_text:
|
||||||
|
self.fail("Operators are different in binary fold: '%s' and '%s'."
|
||||||
|
% (op, self.matched_text))
|
||||||
|
rightExpr = self._parse_cast_expression()
|
||||||
self.skip_ws()
|
self.skip_ws()
|
||||||
if not self.skip_string(')'):
|
if not self.skip_string(')'):
|
||||||
self.fail("Expected ')' in end of fold expression or parenthesized expression.")
|
self.fail("Expected ')' to end binary fold expression.")
|
||||||
return ASTParenExpr(res)
|
return ASTFoldExpr(leftExpr, op, rightExpr)
|
||||||
|
|
||||||
def _parse_primary_expression(self):
|
def _parse_primary_expression(self):
|
||||||
# literal
|
# literal
|
||||||
@ -4947,7 +4994,7 @@ class DefinitionParser(object):
|
|||||||
try:
|
try:
|
||||||
typ = self._parse_type(False)
|
typ = self._parse_type(False)
|
||||||
if not self.skip_string(')'):
|
if not self.skip_string(')'):
|
||||||
raise DefinitionError("Expected ')' in cast expression.")
|
self.fail("Expected ')' in cast expression.")
|
||||||
expr = self._parse_cast_expression()
|
expr = self._parse_cast_expression()
|
||||||
return ASTCastExpr(typ, expr)
|
return ASTCastExpr(typ, expr)
|
||||||
except DefinitionError as exCast:
|
except DefinitionError as exCast:
|
||||||
|
@ -106,9 +106,12 @@ def test_fundamental_types():
|
|||||||
|
|
||||||
|
|
||||||
def test_expressions():
|
def test_expressions():
|
||||||
def exprCheck(expr, id):
|
def exprCheck(expr, id, id4=None):
|
||||||
ids = 'IE1CIA%s_1aE'
|
ids = 'IE1CIA%s_1aE'
|
||||||
check('class', 'template<> C<a[%s]>' % expr, {2: ids % expr, 3: ids % id})
|
idDict = {2: ids % expr, 3: ids % id}
|
||||||
|
if id4 is not None:
|
||||||
|
idDict[4] = ids % id4
|
||||||
|
check('class', 'template<> C<a[%s]>' % expr, idDict)
|
||||||
# primary
|
# primary
|
||||||
exprCheck('nullptr', 'LDnE')
|
exprCheck('nullptr', 'LDnE')
|
||||||
exprCheck('true', 'L1E')
|
exprCheck('true', 'L1E')
|
||||||
@ -155,7 +158,9 @@ def test_expressions():
|
|||||||
exprCheck(p + "'\\U0001F34C'", t + "127820")
|
exprCheck(p + "'\\U0001F34C'", t + "127820")
|
||||||
|
|
||||||
# TODO: user-defined lit
|
# TODO: user-defined lit
|
||||||
exprCheck('(... + Ns)', '(... + Ns)')
|
exprCheck('(... + Ns)', '(... + Ns)', id4='flpl2Ns')
|
||||||
|
exprCheck('(Ns + ...)', '(Ns + ...)', id4='frpl2Ns')
|
||||||
|
exprCheck('(Ns + ... + 0)', '(Ns + ... + 0)', id4='fLpl2NsL0E')
|
||||||
exprCheck('(5)', 'L5E')
|
exprCheck('(5)', 'L5E')
|
||||||
exprCheck('C', '1C')
|
exprCheck('C', '1C')
|
||||||
# postfix
|
# postfix
|
||||||
|
Loading…
Reference in New Issue
Block a user