C++, add parsing of basic new expressions.

This commit is contained in:
Jakob Lykke Andersen 2018-08-17 13:49:44 +02:00
parent 6433e08069
commit 73ae1ac834
3 changed files with 140 additions and 23 deletions

View File

@ -213,7 +213,7 @@ Bugs fixed
* #5191: C++, prevent nested declarations in functions to avoid lookup problems.
* #5126: C++, add missing isPack method for certain template parameter types.
* #5187: C++, parse attributes on declerators as well.
* C++, parse delete expressions as well.
* C++, parse delete expressions and basic new expressions as well.
* #5002: graphviz: SVGs do not adapt to the column width
Testing

View File

@ -1106,6 +1106,80 @@ class ASTNoexceptExpr(ASTBase):
signode.append(nodes.Text(')'))
class ASTNewExpr(ASTBase):
def __init__(self, rooted, isNewTypeId, typ, initList, initType):
# type: (bool, bool, ASTType, List[Any], unicode) -> None
self.rooted = rooted
self.isNewTypeId = isNewTypeId
self.typ = typ
self.initList = initList
self.initType = initType
if self.initList is not None:
assert self.initType in ')}'
def _stringify(self, transform):
res = []
if self.rooted:
res.append('::')
res.append('new ')
# TODO: placement
if self.isNewTypeId:
res.append(transform(self.typ))
else:
assert False
if self.initList is not None:
if self.initType == ')':
res.append('(')
first = True
for e in self.initList:
if not first:
res.append(', ')
first = False
res.append(transform(e))
res.append(self.initType)
return u''.join(res)
def get_id(self, version):
# the array part will be in the type mangling, so na is not used
res = ['nw']
# TODO: placement
res.append('_')
res.append(self.typ.get_id(version))
if self.initList is not None:
if self.initType == ')':
res.append('pi')
for e in self.initList:
res.append(e.get_id(version))
res.append('E')
else:
assert False
else:
res.append('E')
return u''.join(res)
def describe_signature(self, signode, mode, env, symbol):
if self.rooted:
signode.append(nodes.Text('::'))
signode.append(nodes.Text('new '))
# TODO: placement
if self.isNewTypeId:
self.typ.describe_signature(signode, mode, env, symbol)
else:
assert False
if self.initList is not None:
if self.initType == ')':
signode.append(nodes.Text('('))
first = True
for e in self.initList:
if not first:
signode.append(nodes.Text(', '))
first = False
e.describe_signature(signode, mode, env, symbol)
signode.append(nodes.Text(')'))
else:
assert False
class ASTDeleteExpr(ASTBase):
def __init__(self, rooted, array, expr):
self.rooted = rooted
@ -4381,6 +4455,36 @@ class DefinitionParser(object):
return res
return self._parse_nested_name()
def _parse_expression_list_or_braced_init_list(self):
# type: () -> Tuple[List[Any], unicode]
self.skip_ws()
if self.skip_string_and_ws('('):
close = ')'
name = 'parenthesized expression-list'
elif self.skip_string_and_ws('{'):
close = '}'
name = 'braced-init-list'
self.fail('Sorry, braced-init-list not yet supported.')
else:
return None, None
exprs = []
self.skip_ws()
if not self.skip_string(close):
while True:
self.skip_ws()
expr = self._parse_expression(inTemplate=False)
self.skip_ws()
if self.skip_string('...'):
exprs.append(ASTPackExpansionExpr(expr))
else:
exprs.append(expr)
self.skip_ws()
if self.skip_string(close):
break
if not self.skip_string(','):
self.fail("Error in %s, expected ',' or '%s'." % (name, close))
return exprs, close
def _parse_postfix_expression(self):
# -> primary
# | postfix "[" expression "]"
@ -4523,25 +4627,13 @@ class DefinitionParser(object):
if self.skip_string('--'):
postFixes.append(ASTPostfixDec()) # type: ignore
continue
if self.skip_string_and_ws('('):
# TODO: handled braced init
exprs = []
self.skip_ws()
if not self.skip_string(')'):
while True:
self.skip_ws()
expr = self._parse_expression(inTemplate=False)
self.skip_ws()
if self.skip_string('...'):
exprs.append(ASTPackExpansionExpr(expr))
else:
exprs.append(expr)
self.skip_ws()
if self.skip_string(')'):
break
if not self.skip_string(','):
self.fail("Error in cast or call, expected ',' or ')'.")
postFixes.append(ASTPostfixCallExpr(exprs)) # type: ignore
lst, typ = self._parse_expression_list_or_braced_init_list()
if lst is not None:
if typ == ')':
postFixes.append(ASTPostfixCallExpr(lst)) # type: ignore
else:
assert typ == '}'
assert False
continue
break
if len(postFixes) == 0:
@ -4610,7 +4702,24 @@ class DefinitionParser(object):
if not self.skip_word_and_ws('new'):
self.pos = pos
else:
self.fail("Sorry, new-expressions not yet supported.")
# new-placement[opt] new-type-id new-initializer[opt]
# new-placement[opt] ( type-id ) new-initializer[opt]
isNewTypeId = True
if self.skip_string_and_ws('('):
# either this is a new-placement or it's the second production
# without placement, and it's actually the ( type-id ) part
self.fail("Sorry, neither new-placement nor parenthesised type-id "
"in new-epression is supported yet.")
# set isNewTypeId = False if it's (type-id)
if isNewTypeId:
declSpecs = self._parse_decl_specs(outer=None)
decl = self._parse_declarator(named=False, paramMode="new")
else:
self.fail("Sorry, parenthesised type-id in new expression not yet supported.")
lst, typ = self._parse_expression_list_or_braced_init_list()
if lst:
assert typ in ")}"
return ASTNewExpr(rooted, isNewTypeId, ASTType(declSpecs, decl), lst, typ)
# delete-expression
pos = self.pos
rooted = self.skip_string('::')
@ -4972,6 +5081,8 @@ class DefinitionParser(object):
def _parse_parameters_and_qualifiers(self, paramMode):
# type: (unicode) -> ASTParametersQualifiers
if paramMode == 'new':
return None
self.skip_ws()
if not self.skip_string('('):
if paramMode == 'function':
@ -5213,7 +5324,7 @@ class DefinitionParser(object):
def _parse_declarator(self, named, paramMode, typed=True):
# type: (Union[bool, unicode], unicode, bool) -> Any
# 'typed' here means 'parse return type stuff'
if paramMode not in ('type', 'function', 'operatorCast'):
if paramMode not in ('type', 'function', 'operatorCast', 'new'):
raise Exception(
"Internal error, unknown paramMode '%s'." % paramMode)
prevErrors = []

View File

@ -171,7 +171,13 @@ def test_expressions():
exprCheck('sizeof -42', 'szngL42E')
exprCheck('alignof(T)', 'at1T')
exprCheck('noexcept(-42)', 'nxngL42E')
# TODO: new-expression
# new-expression
exprCheck('new int', 'nw_iE')
exprCheck('new volatile int', 'nw_ViE')
exprCheck('new int[42]', 'nw_AL42E_iE')
exprCheck('new int()', 'nw_ipiE')
exprCheck('new int(5, 42)', 'nw_ipiL5EL42EE')
# delete-expression
exprCheck('delete p', 'dl1p')
exprCheck('delete [] p', 'da1p')
exprCheck('::delete p', 'dl1p')