blob: 6891161e9227b7c97cfe756a6f1a3ac4410e3883 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2002, 2016 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* John Camelon (IBM Corporation) - initial API and implementation
* Markus Schorn (Wind River Systems)
* Bryan Wilkinson (QNX) - https://bugs.eclipse.org/bugs/show_bug.cgi?id=151207
* Ed Swartz (Nokia)
* Mike Kucera (IBM)
* Andrew Ferguson (Symbian)
* Sergey Prigogin (Google)
* Thomas Corbat (IFS)
* Anders Dahlberg (Ericsson) - bug 84144
* Nathan Ridge
* Richard Eames
* Alexander Nyßen (itemis AG) - bug 475908
*******************************************************************************/
package org.eclipse.cdt.internal.core.dom.parser.cpp;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.eclipse.cdt.core.dom.ast.ASTCompletionNode;
import org.eclipse.cdt.core.dom.ast.ASTVisitor;
import org.eclipse.cdt.core.dom.ast.DOMException;
import org.eclipse.cdt.core.dom.ast.IASTAlignmentSpecifier;
import org.eclipse.cdt.core.dom.ast.IASTArrayDeclarator;
import org.eclipse.cdt.core.dom.ast.IASTArrayModifier;
import org.eclipse.cdt.core.dom.ast.IASTArraySubscriptExpression;
import org.eclipse.cdt.core.dom.ast.IASTAttributeSpecifier;
import org.eclipse.cdt.core.dom.ast.IASTBinaryExpression;
import org.eclipse.cdt.core.dom.ast.IASTBinaryTypeIdExpression;
import org.eclipse.cdt.core.dom.ast.IASTCastExpression;
import org.eclipse.cdt.core.dom.ast.IASTCompositeTypeSpecifier;
import org.eclipse.cdt.core.dom.ast.IASTCompoundStatement;
import org.eclipse.cdt.core.dom.ast.IASTDeclSpecifier;
import org.eclipse.cdt.core.dom.ast.IASTDeclaration;
import org.eclipse.cdt.core.dom.ast.IASTDeclarator;
import org.eclipse.cdt.core.dom.ast.IASTElaboratedTypeSpecifier;
import org.eclipse.cdt.core.dom.ast.IASTEqualsInitializer;
import org.eclipse.cdt.core.dom.ast.IASTExpression;
import org.eclipse.cdt.core.dom.ast.IASTForStatement;
import org.eclipse.cdt.core.dom.ast.IASTFunctionCallExpression;
import org.eclipse.cdt.core.dom.ast.IASTFunctionDeclarator;
import org.eclipse.cdt.core.dom.ast.IASTIdExpression;
import org.eclipse.cdt.core.dom.ast.IASTInitializer;
import org.eclipse.cdt.core.dom.ast.IASTInitializerClause;
import org.eclipse.cdt.core.dom.ast.IASTInitializerList;
import org.eclipse.cdt.core.dom.ast.IASTLiteralExpression;
import org.eclipse.cdt.core.dom.ast.IASTName;
import org.eclipse.cdt.core.dom.ast.IASTNamedTypeSpecifier;
import org.eclipse.cdt.core.dom.ast.IASTNode;
import org.eclipse.cdt.core.dom.ast.IASTPointer;
import org.eclipse.cdt.core.dom.ast.IASTPointerOperator;
import org.eclipse.cdt.core.dom.ast.IASTProblem;
import org.eclipse.cdt.core.dom.ast.IASTProblemDeclaration;
import org.eclipse.cdt.core.dom.ast.IASTProblemTypeId;
import org.eclipse.cdt.core.dom.ast.IASTSimpleDeclSpecifier;
import org.eclipse.cdt.core.dom.ast.IASTSimpleDeclaration;
import org.eclipse.cdt.core.dom.ast.IASTStatement;
import org.eclipse.cdt.core.dom.ast.IASTToken;
import org.eclipse.cdt.core.dom.ast.IASTTranslationUnit;
import org.eclipse.cdt.core.dom.ast.IASTTypeId;
import org.eclipse.cdt.core.dom.ast.IASTTypeIdExpression;
import org.eclipse.cdt.core.dom.ast.IASTUnaryExpression;
import org.eclipse.cdt.core.dom.ast.IASTWhileStatement;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTAliasDeclaration;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTAlignmentSpecifier;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTAmbiguousTemplateArgument;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTArrayDeclarator;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTArrayDesignator;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTAttribute;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTAttributeList;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTCapture;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTCastExpression;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTCatchHandler;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTClassVirtSpecifier;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTCompositeTypeSpecifier;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTCompositeTypeSpecifier.ICPPASTBaseSpecifier;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTConstructorChainInitializer;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTConstructorInitializer;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTConversionName;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTDeclSpecifier;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTDeclarator;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTDecltypeSpecifier;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTDeleteExpression;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTDesignatedInitializer;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTDesignator;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTElaboratedTypeSpecifier;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTEnumerationSpecifier;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTExplicitTemplateInstantiation;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTExpression;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTFieldDeclarator;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTFieldDesignator;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTFieldReference;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTForStatement;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTFunctionDeclarator;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTFunctionDeclarator.RefQualifier;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTFunctionDefinition;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTFunctionWithTryBlock;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTIfStatement;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTInitCapture;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTInitializerClause;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTInitializerList;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTLambdaExpression;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTLambdaExpression.CaptureDefault;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTLinkageSpecification;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTLiteralExpression;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTName;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTNameSpecifier;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTNamedTypeSpecifier;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTNamespaceAlias;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTNamespaceDefinition;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTNaryTypeIdExpression;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTNewExpression;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTOperatorName;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTPackExpandable;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTParameterDeclaration;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTQualifiedName;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTRangeBasedForStatement;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTReferenceOperator;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTSimpleDeclSpecifier;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTSimpleTypeConstructorExpression;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTSimpleTypeTemplateParameter;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTStaticAssertDeclaration;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTSwitchStatement;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTTemplateDeclaration;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTTemplateId;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTTemplateParameter;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTTemplateSpecialization;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTTemplatedTypeTemplateParameter;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTTranslationUnit;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTTryBlockStatement;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTTypeId;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTTypeIdExpression;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTTypeTransformationSpecifier;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTUnaryExpression;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTUsingDeclaration;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTUsingDirective;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTVirtSpecifier;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTVirtSpecifier.SpecifierKind;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTVisibilityLabel;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPNodeFactory;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPUnaryTypeTransformation;
import org.eclipse.cdt.core.dom.ast.gnu.cpp.IGPPASTArrayRangeDesignator;
import org.eclipse.cdt.core.dom.parser.IExtensionToken;
import org.eclipse.cdt.core.dom.parser.cpp.ICPPParserExtensionConfiguration;
import org.eclipse.cdt.core.index.IIndex;
import org.eclipse.cdt.core.parser.EndOfFileException;
import org.eclipse.cdt.core.parser.IGCCToken;
import org.eclipse.cdt.core.parser.IParserLogService;
import org.eclipse.cdt.core.parser.IProblem;
import org.eclipse.cdt.core.parser.IScanner;
import org.eclipse.cdt.core.parser.IToken;
import org.eclipse.cdt.core.parser.IToken.ContextSensitiveTokenType;
import org.eclipse.cdt.core.parser.Keywords;
import org.eclipse.cdt.core.parser.ParserMode;
import org.eclipse.cdt.core.parser.util.ArrayUtil;
import org.eclipse.cdt.core.parser.util.CharArrayUtils;
import org.eclipse.cdt.core.parser.util.CollectionUtils;
import org.eclipse.cdt.internal.core.dom.parser.ASTNode;
import org.eclipse.cdt.internal.core.dom.parser.ASTQueries;
import org.eclipse.cdt.internal.core.dom.parser.ASTTranslationUnit;
import org.eclipse.cdt.internal.core.dom.parser.AbstractGNUSourceCodeParser;
import org.eclipse.cdt.internal.core.dom.parser.BacktrackException;
import org.eclipse.cdt.internal.core.dom.parser.DeclarationOptions;
import org.eclipse.cdt.internal.core.dom.parser.IASTAmbiguityParent;
import org.eclipse.cdt.internal.core.dom.parser.IASTAmbiguousDeclarator;
import org.eclipse.cdt.internal.core.dom.parser.IASTAmbiguousExpression;
import org.eclipse.cdt.internal.core.dom.parser.IASTAmbiguousStatement;
import org.eclipse.cdt.internal.core.dom.parser.cpp.NameOrTemplateIDVariants.BranchPoint;
import org.eclipse.cdt.internal.core.dom.parser.cpp.NameOrTemplateIDVariants.Variant;
import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.CPPVisitor;
/**
* This is our implementation of the IParser interface, serving as a parser for
* GNU C and C++. From time to time we will make reference to the ANSI ISO
* specifications.
*/
public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser {
private static final int DEFAULT_PARM_LIST_SIZE = 4;
private static final int DEFAULT_CATCH_HANDLER_LIST_SIZE= 4;
private static final int TEMPLATE_ARGUMENT_NESTING_DEPTH_LIMIT = 256;
// This is a parameter to the protected function {@link #declarator(DtorStrategy, DeclarationOptions)}
// so it needs to be protected too.
protected static enum DtorStrategy {PREFER_FUNCTION, PREFER_NESTED}
private final boolean allowCPPRestrict;
private final boolean supportExtendedTemplateSyntax;
private final boolean supportAutoTypeSpecifier;
private final boolean supportUserDefinedLiterals;
private final boolean supportGCCStyleDesignators;
private final IIndex index;
protected ICPPASTTranslationUnit translationUnit;
private int functionBodyCount;
private int templateArgumentNestingDepth = 0;
private char[] currentClassName;
private char[] additionalNumericalSuffixes;
private TemplateIdStrategy fTemplateParameterListStrategy;
private Map<String, ContextSensitiveTokenType> fContextSensitiveTokens;
public GNUCPPSourceParser(IScanner scanner, ParserMode mode,
IParserLogService log, ICPPParserExtensionConfiguration config) {
this(scanner, mode, log, config, null);
}
public GNUCPPSourceParser(IScanner scanner, ParserMode mode, IParserLogService log,
ICPPParserExtensionConfiguration config, IIndex index) {
super(scanner, log, mode, CPPNodeFactory.getDefault(),
config.supportStatementsInExpressions(),
config.supportTypeofUnaryExpressions(),
config.supportAlignOfUnaryExpression(),
config.supportKnRC(),
config.supportAttributeSpecifiers(),
config.supportDeclspecSpecifiers(),
config.getBuiltinBindingsProvider());
allowCPPRestrict = config.allowRestrictPointerOperators();
supportExtendedTemplateSyntax = config.supportExtendedTemplateSyntax();
supportParameterInfoBlock= config.supportParameterInfoBlock();
supportExtendedSizeofOperator= config.supportExtendedSizeofOperator();
supportFunctionStyleAsm= config.supportFunctionStyleAssembler();
supportGCCStyleDesignators = config.supportGCCStyleDesignators();
functionCallCanBeLValue= true;
supportAutoTypeSpecifier= true;
supportUserDefinedLiterals= config.supportUserDefinedLiterals();
this.index= index;
scanner.setSplitShiftROperator(true);
fContextSensitiveTokens = createContextSensitiveTokenMap(config);
additionalNumericalSuffixes = scanner.getAdditionalNumericLiteralSuffixes();
}
@Override
protected ICPPNodeFactory getNodeFactory() {
return (ICPPNodeFactory) super.getNodeFactory();
}
private Map<String, ContextSensitiveTokenType> createContextSensitiveTokenMap(
ICPPParserExtensionConfiguration config) {
Map<String, ContextSensitiveTokenType> result = new HashMap<>();
result.put(Keywords.OVERRIDE, ContextSensitiveTokenType.OVERRIDE);
result.put(Keywords.FINAL, ContextSensitiveTokenType.FINAL);
result.putAll(config.getAdditionalContextSensitiveKeywords());
return result;
}
private ContextSensitiveTokenType getContextSensitiveType(IToken token) {
if (!(token.getType() == IToken.tIDENTIFIER)) {
return null;
}
return fContextSensitiveTokens.get(new String(token.getCharImage()));
}
@Override
protected IASTName identifier() throws EndOfFileException, BacktrackException {
switch (LT(1)) {
case IToken.tIDENTIFIER:
case IToken.tCOMPLETION:
case IToken.tEOC:
return buildName(-1, consume());
}
throw backtrack;
}
private ICPPASTNameSpecifier nameSpecifier() throws BacktrackException, EndOfFileException {
return ambiguousNameSpecifier(CastExprCtx.eNotInBExpr);
}
private ICPPASTNameSpecifier ambiguousNameSpecifier(CastExprCtx ctx) throws BacktrackException, EndOfFileException {
TemplateIdStrategy strat= new TemplateIdStrategy();
IToken m= mark();
while (true) {
try {
return nameSpecifier(ctx, strat);
} catch (BacktrackException e) {
if (e.isFatal()) {
throw e;
}
if (strat.setNextAlternative(true /* previous alternative failed to parse */)) {
backup(m);
} else {
throw e;
}
}
}
}
/**
* Parses a name specifier.
*/
private ICPPASTNameSpecifier nameSpecifier(CastExprCtx ctx, ITemplateIdStrategy strat) throws BacktrackException, EndOfFileException {
if (strat == null)
return ambiguousNameSpecifier(ctx);
ICPPASTQualifiedName qname= null;
ICPPASTNameSpecifier nameSpec= null;
final int offset= LA(1).getOffset();
int endOffset= offset;
if (LT(1) == IToken.tCOLONCOLON) {
endOffset= consume().getEndOffset();
qname= getNodeFactory().newQualifiedName(null);
qname.setFullyQualified(true);
}
boolean mustBeLast= false;
boolean haveName= false;
loop: while (true) {
boolean keywordTemplate= false;
if (qname != null && LT(1) == IToken.t_template) {
consume();
keywordTemplate= true;
}
int destructorOffset= -1;
if (LT(1) == IToken.tBITCOMPLEMENT) {
destructorOffset= consume().getOffset();
mustBeLast= true;
}
switch (LT(1)) {
case IToken.tIDENTIFIER:
case IToken.tCOMPLETION:
case IToken.tEOC:
IToken nt= consume();
nameSpec = (ICPPASTName) buildName(destructorOffset, nt);
break;
case IToken.t_operator:
nameSpec= (ICPPASTName) operatorId();
break;
case IToken.t_decltype:
// A decltype-specifier must be the first component of a qualified name.
if (qname != null)
throwBacktrack(LA(1));
nameSpec = decltypeSpecifier();
break;
default:
if (!haveName || destructorOffset >= 0 || keywordTemplate) {
throwBacktrack(LA(1));
}
nameSpec= getNodeFactory().newName(CharArrayUtils.EMPTY);
if (qname != null) {
addNameSpecifier(qname, nameSpec);
}
break loop;
}
haveName= true;
// Check for template-id
if (nameSpec instanceof IASTName && LTcatchEOF(1) == IToken.tLT) {
IASTName name = (IASTName) nameSpec;
final boolean inBinaryExpression = ctx != CastExprCtx.eNotInBExpr;
final int haveArgs = haveTemplateArguments(inBinaryExpression);
boolean templateID= true;
if (!keywordTemplate) {
if (haveArgs == NO_TEMPLATE_ID) {
templateID= false;
} else if (haveArgs == AMBIGUOUS_TEMPLATE_ID) {
templateID= strat.shallParseAsTemplateID(name);
}
}
if (templateID) {
if (haveArgs == NO_TEMPLATE_ID)
throwBacktrack(LA(1));
nameSpec= (ICPPASTName) addTemplateArguments(name, strat);
}
}
endOffset= calculateEndOffset(nameSpec);
if (qname != null) {
addNameSpecifier(qname, nameSpec);
}
if (LTcatchEOF(1) != IToken.tCOLONCOLON)
break loop;
if (mustBeLast)
throwBacktrack(LA(1));
endOffset= consume().getEndOffset(); // ::
if (qname == null) {
qname= getNodeFactory().newQualifiedName(null);
addNameSpecifier(qname, nameSpec);
}
}
if (qname != null) {
setRange(qname, offset, endOffset);
nameSpec= qname;
}
return nameSpec;
}
private ICPPASTName qualifiedName() throws BacktrackException, EndOfFileException {
ICPPASTNameSpecifier nameSpec = nameSpecifier();
if (!(nameSpec instanceof ICPPASTName)) {
// decltype-specifier without following ::
throwBacktrack(nameSpec);
}
return (ICPPASTName) nameSpec;
}
/**
* Parses a qualified name.
*/
private ICPPASTName qualifiedName(CastExprCtx ctx, ITemplateIdStrategy strat) throws BacktrackException, EndOfFileException {
ICPPASTNameSpecifier nameSpec = nameSpecifier(ctx, strat);
if (!(nameSpec instanceof ICPPASTName)) {
// decltype-specifier without following ::
throwBacktrack(nameSpec);
}
return (ICPPASTName) nameSpec;
}
private void addNameSpecifier(ICPPASTQualifiedName qname, ICPPASTNameSpecifier nameSpec) {
if (nameSpec instanceof IASTName)
qname.addName((IASTName) nameSpec);
else
qname.addNameSpecifier(nameSpec);
}
private IASTName buildName(int destructorOffset, IToken nt) {
IASTName name;
if (destructorOffset < 0) {
name= getNodeFactory().newName(nt.getCharImage());
setRange(name, nt.getOffset(), nt.getEndOffset());
} else {
char[] nchars= nt.getCharImage();
final int len= nchars.length;
char[] image = new char[len + 1];
image[0]= '~';
System.arraycopy(nchars, 0, image, 1, len);
name= getNodeFactory().newName(image);
setRange(name, destructorOffset, nt.getEndOffset());
}
switch (nt.getType()) {
case IToken.tEOC:
case IToken.tCOMPLETION:
createCompletionNode(nt).addName(name);
break;
}
return name;
}
private IASTName addTemplateArguments(IASTName templateName, ITemplateIdStrategy strat) throws EndOfFileException, BacktrackException {
// Parse for template arguments
consume(IToken.tLT);
List<IASTNode> list = templateArgumentList(strat);
IToken end= LA(1);
switch (end.getType()) {
case IToken.tGT_in_SHIFTR:
case IToken.tGT:
consume();
break;
case IToken.tEOC:
break;
default:
throw backtrack;
}
return buildTemplateID(templateName, end.getEndOffset(), list);
}
private ICPPASTTemplateId buildTemplateID(IASTName templateName, int endOffset, List<IASTNode> args) {
ICPPASTTemplateId result = getNodeFactory().newTemplateId(templateName);
setRange(result, ((ASTNode) templateName).getOffset(), endOffset);
for (IASTNode n : args) {
if (n instanceof IASTTypeId) {
result.addTemplateArgument((IASTTypeId) n);
} else if (n instanceof IASTExpression) {
result.addTemplateArgument((IASTExpression) n);
} else if (n instanceof ICPPASTAmbiguousTemplateArgument) {
result.addTemplateArgument((ICPPASTAmbiguousTemplateArgument) n);
}
}
return result;
}
/**
* Parses a decltype-specifier.
*/
private ICPPASTDecltypeSpecifier decltypeSpecifier() throws EndOfFileException, BacktrackException {
int start = consume(IToken.t_decltype).getOffset();
consume(IToken.tLPAREN);
ICPPASTExpression decltypeExpression = expression();
int end = consume(IToken.tRPAREN).getEndOffset();
ICPPASTDecltypeSpecifier decltypeSpec = getNodeFactory().newDecltypeSpecifier(decltypeExpression);
setRange(decltypeSpec, start, end);
return decltypeSpec;
}
/**
* Makes a fast check whether there could be template arguments.
* -1: no, 0: ambiguous, 1: yes
*/
private static final int NO_TEMPLATE_ID= -1;
private static final int AMBIGUOUS_TEMPLATE_ID= 0;
private static final int TEMPLATE_ID= 1;
private int haveTemplateArguments(boolean inBinaryExpression) throws EndOfFileException, BacktrackException {
final IToken mark= mark();
try {
consume();
int nk= 0;
int depth= 0;
int angleDepth= 1;
int limit= 10000;
while (--limit > 0) {
switch (consume().getType()) {
case IToken.tEOC:
case IToken.tCOMPLETION:
return AMBIGUOUS_TEMPLATE_ID;
case IToken.tLT:
if (nk == 0) {
angleDepth++;
}
break;
case IToken.tGT_in_SHIFTR:
case IToken.tGT:
if (nk == 0) {
--angleDepth;
if (!inBinaryExpression)
return angleDepth == 0 ? TEMPLATE_ID : AMBIGUOUS_TEMPLATE_ID;
int end= endsTemplateIDInBinaryExpression();
if (end == NO_TEMPLATE_ID) {
if (angleDepth == 0)
return NO_TEMPLATE_ID;
} else {
return AMBIGUOUS_TEMPLATE_ID;
}
}
break;
case IToken.tLBRACKET:
if (nk == 0) {
nk= IToken.tLBRACKET;
depth= 0;
} else if (nk == IToken.tLBRACKET) {
depth++;
}
break;
case IToken.tRBRACKET:
if (nk == IToken.tLBRACKET) {
if (--depth < 0) {
nk= 0;
}
}
break;
case IToken.tLPAREN:
if (nk == 0) {
nk= IToken.tLPAREN;
depth= 0;
} else if (nk == IToken.tLPAREN) {
depth++;
}
break;
case IToken.tRPAREN:
if (nk == IToken.tLPAREN) {
if (--depth < 0) {
nk= 0;
}
}
break;
// In C++11, braces can occur at the top level in a template-argument,
// if an object of class type is being created via uniform initialization,
// and that class type has a constexpr conversion operator to a type
// that's valid as the type of a non-type template parameter.
case IToken.tLBRACE:
if (nk == 0) {
nk = IToken.tLBRACE;
depth = 0;
} else if (nk == IToken.tLBRACE) {
depth++;
}
break;
case IToken.tRBRACE:
if (nk == 0) {
return NO_TEMPLATE_ID;
}
else if (nk == IToken.tLBRACE) {
if (--depth < 0) {
nk = 0;
}
}
break;
case IToken.tSEMI:
if (nk == 0) {
return NO_TEMPLATE_ID;
}
break;
}
}
return AMBIGUOUS_TEMPLATE_ID;
} finally {
backup(mark);
}
}
/**
* If '>' is followed by an expression, then it denotes the binary operator,
* else it is the end of a template-id, or special-cast.
*/
private int endsTemplateIDInBinaryExpression() {
int lt1= LTcatchEOF(1);
switch (lt1) {
// Can be start of expression, or the scope operator applied to the template-id
case IToken.tCOLONCOLON: // 'CT<int>::member' or 'c<1 && 2 > ::g'
return AMBIGUOUS_TEMPLATE_ID;
// Can be start of expression or the function-call operator applied to a template-id
case IToken.tLPAREN: // 'ft<int>(args)' or 'c<1 && 2 > (x+y)'
return AMBIGUOUS_TEMPLATE_ID;
// Start of unary expression
case IToken.tMINUS:
case IToken.tPLUS:
case IToken.tAMPER:
case IToken.tSTAR:
case IToken.tNOT:
case IToken.tBITCOMPLEMENT:
case IToken.tINCR:
case IToken.tDECR:
case IToken.t_new:
case IToken.t_delete:
case IToken.t_sizeof:
case IToken.t_alignof:
case IGCCToken.t___alignof__:
return NO_TEMPLATE_ID;
// Start of a postfix expression
case IToken.t_typename:
case IToken.t_char:
case IToken.t_char16_t:
case IToken.t_char32_t:
case IToken.t_wchar_t:
case IToken.t_bool:
case IToken.t_short:
case IToken.t_int:
case IToken.t_long:
case IToken.t_signed:
case IToken.t_unsigned:
case IToken.t_float:
case IToken.t_double:
case IToken.t_dynamic_cast:
case IToken.t_static_cast:
case IToken.t_reinterpret_cast:
case IToken.t_const_cast:
case IToken.t_typeid:
return NO_TEMPLATE_ID;
// Start of a primary expression
case IToken.tINTEGER:
case IToken.tFLOATINGPT:
case IToken.tSTRING:
case IToken.tLSTRING:
case IToken.tUTF16STRING:
case IToken.tUTF32STRING:
case IToken.tCHAR:
case IToken.tLCHAR:
case IToken.tUTF16CHAR:
case IToken.tUTF32CHAR:
case IToken.t_false:
case IToken.t_true:
case IToken.t_this:
case IToken.tIDENTIFIER:
case IToken.t_operator:
case IToken.tCOMPLETION:
return NO_TEMPLATE_ID;
// Tokens that end an expression
case IToken.tSEMI:
case IToken.tCOMMA:
case IToken.tLBRACE:
case IToken.tRBRACE:
case IToken.tRBRACKET:
case IToken.tRPAREN:
case IToken.tELLIPSIS: // pack-expansion
case IToken.t_struct:
case IToken.t_class:
case IToken.t_template:
return TEMPLATE_ID;
// Binary operator
case IToken.tGT:
case IToken.tGT_in_SHIFTR:
case IToken.tEQUAL:
return TEMPLATE_ID;
default:
return AMBIGUOUS_TEMPLATE_ID;
}
}
private List<IASTNode> templateArgumentList(ITemplateIdStrategy strat) throws EndOfFileException, BacktrackException {
if (templateArgumentNestingDepth >= TEMPLATE_ARGUMENT_NESTING_DEPTH_LIMIT) {
throwBacktrack(createProblem(IProblem.TEMPLATE_ARGUMENT_NESTING_DEPTH_LIMIT_EXCEEDED,
LA(1).getOffset(), 1));
}
++templateArgumentNestingDepth;
try {
int startingOffset = LA(1).getOffset();
int endOffset = 0;
List<IASTNode> list= null;
boolean needComma= false;
int lt1= LT(1);
while (lt1 != IToken.tGT && lt1 != IToken.tGT_in_SHIFTR && lt1 != IToken.tEOC) {
if (needComma) {
if (lt1 != IToken.tCOMMA) {
throwBacktrack(startingOffset, endOffset - startingOffset);
}
consume();
} else {
needComma= true;
}
IASTNode node= templateArgument(strat);
if (list == null) {
list= new ArrayList<>();
}
list.add(node);
lt1= LT(1);
}
if (list == null) {
return Collections.emptyList();
}
return list;
} finally {
--templateArgumentNestingDepth;
}
}
private IASTNode templateArgument(ITemplateIdStrategy strat) throws EndOfFileException, BacktrackException {
IToken argStart = mark();
int markBranchPoint = ((TemplateIdStrategy) strat).getCurrentBranchPoint();
ICPPASTTypeId typeId= null;
int lt1= 0;
try {
typeId= typeId(DeclarationOptions.TYPEID, strat);
lt1 = LT(1);
} catch (BacktrackException e) {
if (e.isFatal()) {
throw e;
}
}
if (typeId != null
&& (lt1 == IToken.tCOMMA || lt1 == IToken.tGT || lt1 == IToken.tGT_in_SHIFTR
|| lt1 == IToken.tEOC || lt1 == IToken.tELLIPSIS)) {
// This is potentially a type-id, now check ambiguity with expression.
IToken typeIdEnd= mark();
IASTNamedTypeSpecifier namedTypeSpec = null;
IASTName name = null;
try {
// If the type-id consists of a name, that name could be or contain
// a template-id, with template arguments of its own, which can
// themselves be ambiguous. If we parse the name anew as an
// id-expression, our complexity becomes exponential in the nesting
// depth of template-ids (bug 316704). To avoid this, we do not
// re-parse the name, but instead synthesize an id-expression from
// it, and then continue parsing an expression from the id-expression
// onwards (as the id-expression could be the beginning of a larger
// expression).
IASTIdExpression idExpression = null;
IASTDeclSpecifier declSpec = typeId.getDeclSpecifier();
if (declSpec instanceof IASTNamedTypeSpecifier) {
namedTypeSpec = (IASTNamedTypeSpecifier) declSpec;
name = namedTypeSpec.getName();
if (name.contains(typeId)) {
idExpression = setRange(getNodeFactory().newIdExpression(name), name);
// If the name was one of the completion names, add it to the completion
// node again now that it has a new parent. This ensures that completion
// proposals are offered for both contexts that the name appears in.
ASTCompletionNode completionNode = (ASTCompletionNode) getCompletionNode();
if (completionNode != null && completionNode.containsName(name)) {
completionNode.addName(name);
}
}
}
// Parse an expression, starting with the id-expression synthesized
// above if there is one, otherwise starting from the beginning of
// the argument.
if (idExpression == null)
backup(argStart);
IASTExpression expression = expression(ExprKind.eAssignment, BinaryExprCtx.eInTemplateID, idExpression, strat);
// At this point we have a valid type-id and a valid expression.
// We prefer the longer one.
if (!typeId.contains(expression)) {
// The expression is longer.
if (LT(1) == IToken.tELLIPSIS) {
expression = addPackExpansion(expression, consume());
}
return expression;
} else if (expression.contains(typeId)) {
// The two are of the same length - ambiguous.
if (LT(1) == IToken.tELLIPSIS) {
IToken ellipsis = consume();
addPackExpansion(typeId, ellipsis);
expression = addPackExpansion(expression, ellipsis);
}
ICPPASTAmbiguousTemplateArgument ambiguity = createAmbiguousTemplateArgument();
ambiguity.addTypeId(typeId);
ambiguity.addExpression(expression);
return ambiguity;
}
// The type-id is longer, use it.
} catch (BacktrackException e) {
if (e.isFatal()) {
throw e;
}
// Failed to parse an expression, use the type id.
}
// Clean up after our failed attempt to parse an expression.
backup(typeIdEnd);
if (name != null && namedTypeSpec != null) {
// When we synthesized the id-expression, it took ownership
// of the name. Give ownership back to the type-id.
namedTypeSpec.setName(name);
}
// Use the type-id.
if (LT(1) == IToken.tELLIPSIS) {
addPackExpansion(typeId, consume());
}
return typeId;
}
// Not a type-id, parse as expression.
backup(argStart);
((TemplateIdStrategy) strat).backupToBranchPoint(markBranchPoint);
IASTExpression expr= expression(ExprKind.eAssignment, BinaryExprCtx.eInTemplateID, null, strat);
if (LT(1) == IToken.tELLIPSIS) {
expr= addPackExpansion(expr, consume());
}
return expr;
}
private void addPackExpansion(ICPPASTTypeId typeId, IToken consume) {
final int endOffset= consume.getEndOffset();
adjustEndOffset(typeId, endOffset);
typeId.setIsPackExpansion(true);
}
private IASTExpression addPackExpansion(IASTExpression expr, IToken ellipsis) {
IASTExpression result= getNodeFactory().newPackExpansionExpression(expr);
return setRange(result, expr, ellipsis.getEndOffset());
}
private IASTName operatorId() throws BacktrackException, EndOfFileException {
final IToken firstToken = consume(IToken.t_operator);
int endOffset= firstToken.getEndOffset();
IASTTypeId typeId = null;
OverloadableOperator op = null;
final int lt1= LT(1);
switch (lt1) {
case IToken.tLPAREN:
op = OverloadableOperator.PAREN; // operator ()
consume();
endOffset = consume(IToken.tRPAREN).getEndOffset();
break;
case IToken.tLBRACKET:
op = OverloadableOperator.BRACKET; // operator []
consume();
endOffset = consume(IToken.tRBRACKET).getEndOffset();
break;
case IToken.t_new:
case IToken.t_delete:
if (LT(2) == IToken.tLBRACKET) {
op= lt1 == IToken.t_new ? OverloadableOperator.NEW_ARRAY : OverloadableOperator.DELETE_ARRAY;
consume();
consume();
endOffset= consume(IToken.tRBRACKET).getEndOffset();
} else {
IToken t= consume();
endOffset= t.getEndOffset();
op= OverloadableOperator.valueOf(t);
}
break;
case IToken.tGT_in_SHIFTR:
consume();
endOffset= consume(IToken.tGT_in_SHIFTR).getEndOffset();
op= OverloadableOperator.SHIFTR;
break;
case IToken.tSTRING: // User defined literal T operator "" SUFFIX
{
IToken strOp = consume();
// Should be an empty string
if (strOp.getLength() == 2) {
endOffset = strOp.getEndOffset();
IToken udlOperator = identifierOrKeyword();
char[] operatorName = CharArrayUtils.concat(firstToken.getCharImage(), " ".toCharArray()); //$NON-NLS-1$
operatorName = CharArrayUtils.concat(operatorName, strOp.getCharImage());
operatorName = CharArrayUtils.concat(operatorName, udlOperator.getCharImage());
IASTName name = getNodeFactory().newOperatorName(operatorName);
setRange(name, firstToken.getOffset(), udlOperator.getEndOffset());
return name;
}
break;
}
case IToken.tUSER_DEFINED_STRING_LITERAL: // User defined literal T operator ""SUFFIX
{
IToken strOp = consume();
String image = strOp.getImage();
int startQuote = image.indexOf('"');
int endQuote = image.lastIndexOf('"');
if (startQuote != -1 && endQuote == startQuote + 1) {
char[] operatorName = CharArrayUtils.concat(firstToken.getCharImage(), " ".toCharArray()); //$NON-NLS-1$
operatorName = CharArrayUtils.concat(operatorName, strOp.getCharImage());
IASTName name = getNodeFactory().newOperatorName(operatorName);
setRange(name, firstToken.getOffset(), strOp.getEndOffset());
return name;
}
break;
}
default:
op= OverloadableOperator.valueOf(LA(1));
if (op != null) {
endOffset= consume().getEndOffset();
}
break;
}
if (op != null) {
IASTName name= getNodeFactory().newOperatorName(op.toCharArray());
setRange(name, firstToken.getOffset(), endOffset);
return name;
}
// must be a conversion function
typeId= typeId(DeclarationOptions.TYPEID_CONVERSION);
IASTName name = getNodeFactory().newConversionName(typeId);
setRange(name, firstToken.getOffset(), calculateEndOffset(typeId));
return name;
}
/**
* Information for the parser, whether a binary expression is parsed in the context of a
* template-id an ambiguous template-id (one where the '<' could be a greater sign) or
* else where.
*/
private enum BinaryExprCtx {eInTemplateID, eNotInTemplateID}
@Override
protected ICPPASTExpression expression() throws BacktrackException, EndOfFileException {
return expression(ExprKind.eExpression, BinaryExprCtx.eNotInTemplateID, null, null);
}
@Override
protected ICPPASTExpression constantExpression() throws BacktrackException, EndOfFileException {
return expression(ExprKind.eConstant, BinaryExprCtx.eNotInTemplateID, null, null);
}
private ICPPASTExpression expression(final ExprKind kind, final BinaryExprCtx ctx, IASTInitializerClause expr, ITemplateIdStrategy strat) throws EndOfFileException, BacktrackException {
final boolean allowComma= kind == ExprKind.eExpression;
boolean allowAssignment= kind != ExprKind.eConstant;
if (allowAssignment && LT(1) == IToken.t_throw) {
return throwExpression();
}
final int startOffset= expr != null ? ((ASTNode) expr).getOffset() : LA(1).getOffset();
int lt1;
int conditionCount= 0;
BinaryOperator lastOperator= null;
NameOrTemplateIDVariants variants= null;
IToken variantMark= mark();
if (expr == null) {
Object e = castExpressionForBinaryExpression(strat);
if (e instanceof IASTExpression) {
expr= (IASTExpression) e;
} else {
variants= new NameOrTemplateIDVariants();
final Variant variant = (Variant) e;
expr= variant.getExpression();
variants.addBranchPoint(variant.getNext(), null, allowAssignment, conditionCount);
}
}
boolean stopWithNextOperator= false;
castExprLoop: for (;;) {
// Typically after a binary operator there cannot be a throw expression
boolean allowThrow= false;
// Brace initializers are allowed on the right hand side of an expression
boolean allowBraceInitializer= false;
boolean doneExpression= false;
BacktrackException failure= null;
final int opOffset= LA().getOffset();
lt1= stopWithNextOperator ? IToken.tSEMI : LT(1);
switch (lt1) {
case IToken.tQUESTION:
conditionCount++;
// <logical-or> ? <expression> : <assignment-expression>
// Precedence: 25 is lower than precedence of logical or; 0 is lower than precedence of expression
lastOperator= new BinaryOperator(lastOperator, expr, lt1, 25, 0);
allowAssignment= true; // assignment expressions will be subsumed by the conditional expression
allowThrow= true;
break;
case IToken.tCOLON:
if (--conditionCount < 0) {
doneExpression= true;
} else {
// <logical-or> ? <expression> : <assignment-expression>
// Precedence: 0 is lower than precedence of expression; 15 is lower than precedence of assignment;
lastOperator= new BinaryOperator(lastOperator, expr, lt1, 0, 15);
allowAssignment= true; // assignment expressions will be subsumed by the conditional expression
allowThrow= true;
}
break;
case IToken.tCOMMA:
allowThrow= true;
if (!allowComma && conditionCount == 0) {
doneExpression= true;
} else {
// Lowest precedence except inside the conditional expression
lastOperator= new BinaryOperator(lastOperator, expr, lt1, 10, 11);
}
break;
case IToken.tASSIGN:
case IToken.tSTARASSIGN:
case IToken.tDIVASSIGN:
case IToken.tMODASSIGN:
case IToken.tPLUSASSIGN:
case IToken.tMINUSASSIGN:
case IToken.tSHIFTRASSIGN:
case IToken.tSHIFTLASSIGN:
case IToken.tAMPERASSIGN:
case IToken.tXORASSIGN:
case IToken.tBITORASSIGN:
if (!allowAssignment && conditionCount == 0) {
doneExpression= true;
} else {
// Assignments group right to left
lastOperator= new BinaryOperator(lastOperator, expr, lt1, 21, 20);
allowBraceInitializer= true;
}
break;
case IToken.tOR:
lastOperator= new BinaryOperator(lastOperator, expr, lt1, 30, 31);
break;
case IToken.tAND:
lastOperator= new BinaryOperator(lastOperator, expr, lt1, 40, 41);
break;
case IToken.tBITOR:
lastOperator= new BinaryOperator(lastOperator, expr, lt1, 50, 51);
break;
case IToken.tXOR:
lastOperator= new BinaryOperator(lastOperator, expr, lt1, 60, 61);
break;
case IToken.tAMPER:
lastOperator= new BinaryOperator(lastOperator, expr, lt1, 70, 71);
break;
case IToken.tEQUAL:
case IToken.tNOTEQUAL:
lastOperator= new BinaryOperator(lastOperator, expr, lt1, 80, 81);
break;
case IToken.tGT:
if (ctx == BinaryExprCtx.eInTemplateID) {
doneExpression= true;
break;
}
//$FALL-THROUGH$
case IToken.tLT:
case IToken.tLTEQUAL:
case IToken.tGTEQUAL:
case IGCCToken.tMAX:
case IGCCToken.tMIN:
lastOperator= new BinaryOperator(lastOperator, expr, lt1, 90, 91);
break;
case IToken.tGT_in_SHIFTR:
if (ctx == BinaryExprCtx.eInTemplateID) {
doneExpression= true;
break;
}
if (LT(2) != IToken.tGT_in_SHIFTR) {
IToken token = LA(1);
backtrack.initialize(token.getOffset(), token.getLength());
failure= backtrack;
break;
}
lt1= IToken.tSHIFTR; // convert back
consume(); // consume the extra token
//$FALL-THROUGH$
case IToken.tSHIFTL:
case IToken.tSHIFTR:
lastOperator= new BinaryOperator(lastOperator, expr, lt1, 100, 101);
break;
case IToken.tPLUS:
case IToken.tMINUS:
lastOperator= new BinaryOperator(lastOperator, expr, lt1, 110, 111);
break;
case IToken.tSTAR:
case IToken.tDIV:
case IToken.tMOD:
lastOperator= new BinaryOperator(lastOperator, expr, lt1, 120, 121);
break;
case IToken.tDOTSTAR:
case IToken.tARROWSTAR:
lastOperator= new BinaryOperator(lastOperator, expr, lt1, 130, 131);
break;
default:
doneExpression= true;
break;
}
// Close variants
if (failure == null) {
if (doneExpression) {
if (variants != null && !variants.hasRightBound(opOffset)) {
// We have a longer variant, ignore this one.
backtrack.initialize(opOffset, 1);
failure= backtrack;
} else {
break castExprLoop;
}
}
// Close variants with matching end
if (variants != null && lastOperator != null) {
variants.closeVariants(opOffset, lastOperator);
}
}
if (failure == null && !doneExpression) {
// Determine next cast-expression
consume(); // consumes the operator
stopWithNextOperator= false;
try {
if (lt1 == IToken.tQUESTION && LT(1) == IToken.tCOLON) {
// Missing sub-expression after '?' (gnu-extension)
expr= null;
} else if (allowThrow && LT(1) == IToken.t_throw) {
// Throw expression
expr= throwExpression();
lt1= LT(1);
if (lt1 != IToken.tCOLON && lt1 != IToken.tCOMMA)
stopWithNextOperator= true;
} else if (allowBraceInitializer && LT(1) == IToken.tLBRACE) {
// Brace initializer
expr= bracedInitList(true, false);
lt1= LT(1);
if (lt1 != IToken.tCOLON && lt1 != IToken.tCOMMA)
stopWithNextOperator= true;
} else {
Object e = castExpressionForBinaryExpression(strat);
if (e instanceof IASTExpression) {
expr= (IASTExpression) e;
} else {
final Variant ae = (Variant) e;
expr= ae.getExpression();
if (variants == null)
variants= new NameOrTemplateIDVariants();
variants.addBranchPoint(ae.getNext(), lastOperator, allowAssignment, conditionCount);
}
}
continue castExprLoop;
} catch (BacktrackException e) {
failure= e;
}
}
// We need a new variant
Variant variant= variants == null ? null : variants.selectFallback();
if (variant == null) {
if (failure != null)
throw failure;
throwBacktrack(LA(1));
} else {
// Restore variant and continue
BranchPoint varPoint= variant.getOwner();
allowAssignment= varPoint.isAllowAssignment();
conditionCount= varPoint.getConditionCount();
lastOperator= varPoint.getLeftOperator();
expr= variant.getExpression();
backup(variantMark);
int offset= variant.getRightOffset();
while (LA().getOffset() < offset) {
consume();
}
variantMark= mark();
}
}
// Check for incomplete conditional expression
if (lt1 != IToken.tEOC && conditionCount > 0)
throwBacktrack(LA(1));
if (variants != null) {
BinaryOperator end = new BinaryOperator(lastOperator, expr, -1, 0, 0);
variants.closeVariants(LA(1).getOffset(), end);
variants.removeInvalid(end);
if (!variants.isEmpty()) {
CPPASTTemplateIDAmbiguity result = new CPPASTTemplateIDAmbiguity(this, end, variants.getOrderedBranchPoints());
setRange(result, startOffset, calculateEndOffset(expr));
return result;
}
}
return (ICPPASTExpression) buildExpression(lastOperator, expr);
}
public Object castExpressionForBinaryExpression(ITemplateIdStrategy s)
throws EndOfFileException, BacktrackException {
if (s != null) {
return castExpression(CastExprCtx.eDirectlyInBExpr, s);
}
TemplateIdStrategy strat= new TemplateIdStrategy();
Variant variants= null;
IASTExpression singleResult= null;
IASTName[] firstNames= null;
final IToken mark= mark();
IToken lastToken= null;
while (true) {
try {
IASTExpression e = castExpression(CastExprCtx.eDirectlyInBExpr, strat);
if (variants == null) {
if (singleResult == null || lastToken == null) {
singleResult= e;
firstNames= strat.getTemplateNames();
} else {
variants= new Variant(null, singleResult, firstNames, lastToken.getOffset());
singleResult= null;
firstNames= null;
}
}
lastToken= LA();
if (variants != null) {
variants = new Variant(variants, e, strat.getTemplateNames(), lastToken.getOffset());
}
if (!strat.setNextAlternative(false /* previous alternative parsed ok */)) {
break;
}
} catch (BacktrackException e) {
if (!strat.setNextAlternative(true /* previous alternative failed to parse */)) {
if (lastToken == null)
throw e;
backup(lastToken);
break;
}
}
backup(mark);
}
return variants != null ? variants : singleResult;
}
@Override
protected IASTExpression buildBinaryExpression(int operator, IASTExpression expr1, IASTInitializerClause expr2, int lastOffset) {
IASTBinaryExpression result = getNodeFactory().newBinaryExpression(operator, expr1, expr2);
int o = ((ASTNode) expr1).getOffset();
((ASTNode) result).setOffsetAndLength(o, lastOffset - o);
return result;
}
private ICPPASTExpression throwExpression() throws EndOfFileException, BacktrackException {
IToken throwToken = consume();
IASTExpression throwExpression = null;
try {
throwExpression = expression();
} catch (BacktrackException bte) {
backup(throwToken);
consume();
}
int o = throwExpression != null ?
calculateEndOffset(throwExpression) : throwToken.getEndOffset();
return (ICPPASTExpression) buildUnaryExpression(ICPPASTUnaryExpression.op_throw,
throwExpression, throwToken.getOffset(), o); // fix for 95225
}
protected IASTExpression deleteExpression() throws EndOfFileException, BacktrackException {
int startingOffset = LA(1).getOffset();
boolean global = false;
if (LT(1) == IToken.tCOLONCOLON) {
// global scope
consume();
global = true;
}
consume(IToken.t_delete);
boolean vectored = false;
if (LT(1) == IToken.tLBRACKET) {
// array delete
consume();
consume(IToken.tRBRACKET);
vectored = true;
}
IASTExpression castExpression = castExpression(CastExprCtx.eNotInBExpr, null);
ICPPASTDeleteExpression deleteExpression = getNodeFactory().newDeleteExpression(castExpression);
((ASTNode) deleteExpression).setOffsetAndLength(startingOffset, calculateEndOffset(castExpression) - startingOffset);
deleteExpression.setIsGlobal(global);
deleteExpression.setIsVectored(vectored);
return deleteExpression;
}
/**
* Parse a new-expression. There is room for ambiguities. With P for placement, T for typeid,
* and I for initializer the potential patterns (with the new omitted) are:
* easy: T, T(I)
* medium: (P) T(I), (P) (T)(I)
* hard: (T), (P) T, (P) (T), (T)(I)
*/
protected IASTExpression newExpression() throws BacktrackException, EndOfFileException {
IToken la = LA(1);
int offset= la.getOffset();
final boolean isGlobal = la.getType() == IToken.tCOLONCOLON;
if (isGlobal) {
consume();
}
consume(IToken.t_new);
if (LT(1) == IToken.tLPAREN) {
consume();
// consider placement first (P) ...
List<ICPPASTInitializerClause> plcmt= null;
IASTTypeId typeid= null;
boolean isNewTypeId= true;
IASTInitializer init= null;
int endOffset= 0;
IToken mark= mark();
IToken end= null;
try {
plcmt= expressionList();
endOffset= consumeOrEOC(IToken.tRPAREN).getEndOffset();
final int lt1= LT(1);
if (lt1 == IToken.tEOC) {
return newExpression(isGlobal, plcmt, typeid, isNewTypeId, init, offset, endOffset);
}
if (lt1 == IToken.tLPAREN) {
// (P)(T) ...
isNewTypeId= false;
consume(IToken.tLPAREN);
typeid= typeId(DeclarationOptions.TYPEID);
endOffset= consumeOrEOC(IToken.tRPAREN).getEndOffset();
} else {
// (P) T ...
typeid= typeId(DeclarationOptions.TYPEID_NEW);
endOffset= calculateEndOffset(typeid);
}
end= LA(1);
} catch (BacktrackException e) {
plcmt= null;
typeid= null;
}
if (typeid != null && plcmt != null) {
// (P)(T)(I) or (P) T (I)
int lt1= LT(1);
if (lt1 == IToken.tEOC)
return newExpression(isGlobal, plcmt, typeid, isNewTypeId, init, offset, endOffset);
if (lt1 == IToken.tLPAREN || lt1 == IToken.tLBRACE) {
init= bracedOrCtorStyleInitializer();
endOffset= calculateEndOffset(init);
return newExpression(isGlobal, plcmt, typeid, isNewTypeId, init, offset, endOffset);
}
}
// (T) ...
backup(mark);
IASTTypeId typeid2= null;
IASTInitializer init2= null;
int endOffset2;
try {
typeid2= typeId(DeclarationOptions.TYPEID);
endOffset2= consumeOrEOC(IToken.tRPAREN).getEndOffset();
final int lt1= LT(1);
if (lt1 == IToken.tEOC)
return newExpression(isGlobal, null, typeid2, false, init2, offset, endOffset2);
if (lt1 == IToken.tLPAREN || lt1 == IToken.tLBRACE) {
if (plcmt != null &&
ASTQueries.findTypeRelevantDeclarator(typeid2.getAbstractDeclarator()) instanceof IASTArrayDeclarator) {
throwBacktrack(LA(1));
}
// (T)(I)
init2= bracedOrCtorStyleInitializer();
endOffset2= calculateEndOffset(init2);
}
} catch (BacktrackException e) {
if (plcmt == null)
throw e;
endOffset2= -1;
}
if (plcmt == null || endOffset2 > endOffset)
return newExpression(isGlobal, null, typeid2, false, init2, offset, endOffset2);
if (endOffset != endOffset2) {
backup(end);
return newExpression(isGlobal, plcmt, typeid, isNewTypeId, init, offset, endOffset);
}
// ambiguity:
IASTExpression ex1= newExpression(isGlobal, plcmt, typeid, isNewTypeId, init, offset, endOffset);
IASTExpression ex2= newExpression(isGlobal, null, typeid2, false, init2, offset, endOffset2);
IASTAmbiguousExpression ambiguity= createAmbiguousExpression();
ambiguity.addExpression(ex1);
ambiguity.addExpression(ex2);
((ASTNode) ambiguity).setOffsetAndLength((ASTNode) ex1);
return ambiguity;
}
// T ...
final IASTTypeId typeid = typeId(DeclarationOptions.TYPEID_NEW);
int endOffset = calculateEndOffset(typeid);
IASTInitializer init= null;
final int lt1= LT(1);
if (lt1 == IToken.tLPAREN || lt1 == IToken.tLBRACE) {
// T(I)
init= bracedOrCtorStyleInitializer();
endOffset= calculateEndOffset(init);
}
return newExpression(isGlobal, null, typeid, true, init, offset, endOffset);
}
private IASTExpression newExpression(boolean isGlobal, List<? extends IASTInitializerClause> plcmt, IASTTypeId typeid,
boolean isNewTypeId, IASTInitializer init, int offset, int endOffset) {
IASTInitializerClause[] plcmtArray= null;
if (plcmt != null && !plcmt.isEmpty()) {
plcmtArray= plcmt.toArray(new IASTInitializerClause[plcmt.size()]);
}
ICPPASTNewExpression result = getNodeFactory().newNewExpression(plcmtArray, init, typeid);
result.setIsGlobal(isGlobal);
result.setIsNewTypeId(isNewTypeId);
((ASTNode) result).setOffsetAndLength(offset, endOffset - offset);
return result;
}
@Override
protected IASTExpression unaryExpression(CastExprCtx ctx, ITemplateIdStrategy strat) throws EndOfFileException, BacktrackException {
switch (LT(1)) {
case IToken.tSTAR:
return unaryExpression(IASTUnaryExpression.op_star, ctx, strat);
case IToken.tAMPER:
return unaryExpression(IASTUnaryExpression.op_amper, ctx, strat);
case IToken.tAND:
return unaryExpression(IASTUnaryExpression.op_labelReference, ctx, strat);
case IToken.tPLUS:
return unaryExpression(IASTUnaryExpression.op_plus, ctx, strat);
case IToken.tMINUS:
return unaryExpression(IASTUnaryExpression.op_minus, ctx, strat);
case IToken.tNOT:
return unaryExpression(IASTUnaryExpression.op_not, ctx, strat);
case IToken.tBITCOMPLEMENT:
return unaryExpression(IASTUnaryExpression.op_tilde, ctx, strat);
case IToken.tINCR:
return unaryExpression(IASTUnaryExpression.op_prefixIncr, ctx, strat);
case IToken.tDECR:
return unaryExpression(IASTUnaryExpression.op_prefixDecr, ctx, strat);
case IToken.t_new:
return newExpression();
case IToken.t_delete:
return deleteExpression();
case IToken.tCOLONCOLON:
switch (LT(2)) {
case IToken.t_new:
return newExpression();
case IToken.t_delete:
return deleteExpression();
default:
return postfixExpression(ctx, strat);
}
case IToken.t_sizeof:
if (LTcatchEOF(2) == IToken.tELLIPSIS) {
int offset= consume().getOffset(); // sizeof
consume(); // ...
return parseTypeidInParenthesisOrUnaryExpression(true, offset,
IASTTypeIdExpression.op_sizeofParameterPack,
IASTUnaryExpression.op_sizeofParameterPack, ctx, strat);
}
return parseTypeidInParenthesisOrUnaryExpression(false, consume().getOffset(),
IASTTypeIdExpression.op_sizeof, IASTUnaryExpression.op_sizeof, ctx, strat);
case IToken.t_alignof:
case IGCCToken.t___alignof__:
return parseTypeidInParenthesisOrUnaryExpression(false, consume().getOffset(),
IASTTypeIdExpression.op_alignof, IASTUnaryExpression.op_alignOf, ctx, strat);
case IGCCToken.tTT_has_nothrow_assign:
case IGCCToken.tTT_has_nothrow_constructor:
case IGCCToken.tTT_has_nothrow_copy:
case IGCCToken.tTT_has_trivial_assign:
case IGCCToken.tTT_has_trivial_constructor:
case IGCCToken.tTT_has_trivial_copy:
case IGCCToken.tTT_has_trivial_destructor:
case IGCCToken.tTT_has_virtual_destructor:
case IGCCToken.tTT_is_abstract:
case IGCCToken.tTT_is_base_of:
case IGCCToken.tTT_is_class:
case IGCCToken.tTT_is_empty:
case IGCCToken.tTT_is_enum:
case IGCCToken.tTT_is_final:
case IGCCToken.tTT_is_literal_type:
case IGCCToken.tTT_is_pod:
case IGCCToken.tTT_is_polymorphic:
case IGCCToken.tTT_is_standard_layout:
case IGCCToken.tTT_is_trivial:
case IGCCToken.tTT_is_union:
case IGCCToken.tTT_is_trivially_copyable:
case IGCCToken.tTT_is_trivially_constructible:
case IGCCToken.tTT_is_trivially_assignable:
case IGCCToken.tTT_is_constructible:
return parseTypeTrait();
default:
return postfixExpression(ctx, strat);
}
}
private IASTExpression parseTypeTrait() throws EndOfFileException, BacktrackException {
IToken first= consume();
final boolean isBinary= isBinaryTrait(first);
final boolean isNary = isNaryTrait(first);
consume(IToken.tLPAREN);
ICPPASTTypeId[] operands = new ICPPASTTypeId[isBinary ? 2 : 1];
operands[0] = typeId(DeclarationOptions.TYPEID);
if (isBinary) {
consumeOrEOC(IToken.tCOMMA);
if (LT(1) != IToken.tEOC) {
operands[1] = typeId(DeclarationOptions.TYPEID);
}
} else if (isNary) {
while (LTcatchEOF(1) == IToken.tCOMMA) {
consume();
if (LT(1) != IToken.tEOC) {
ICPPASTTypeId operand = typeId(DeclarationOptions.TYPEID);
// n-ary type traits can contain pack expansions
if (LT(1) == IToken.tELLIPSIS) {
addPackExpansion(operand, consume());
}
operands = ArrayUtil.append(operands, operand);
}
}
operands = ArrayUtil.removeNulls(operands);
}
int endOffset= consumeOrEOC(IToken.tRPAREN).getEndOffset();
IASTExpression result;
if (isNary) {
result= getNodeFactory().newNaryTypeIdExpression(getNaryTypeTraitOperator(first), operands);
} else if (isBinary) {
result= getNodeFactory().newBinaryTypeIdExpression(getBinaryTypeTraitOperator(first), operands[0],
operands[1]);
} else {
result= getNodeFactory().newTypeIdExpression(getUnaryTypeTraitOperator(first), operands[0]);
}
return setRange(result, first.getOffset(), endOffset);
}
private boolean isBinaryTrait(IToken first) {
switch (first.getType()) {
case IGCCToken.tTT_is_base_of:
case IGCCToken.tTT_is_trivially_assignable:
return true;
}
return false;
}
private boolean isNaryTrait(IToken operatorToken) {
switch (operatorToken.getType()) {
case IGCCToken.tTT_is_trivially_constructible:
case IGCCToken.tTT_is_constructible:
return true;
}
return false;
}
private IASTBinaryTypeIdExpression.Operator getBinaryTypeTraitOperator(IToken first) {
switch (first.getType()) {
case IGCCToken.tTT_is_base_of:
return IASTBinaryTypeIdExpression.Operator.__is_base_of;
case IGCCToken.tTT_is_trivially_assignable:
return IASTBinaryTypeIdExpression.Operator.__is_trivially_assignable;
}
assert false;
return null;
}
private ICPPASTNaryTypeIdExpression.Operator getNaryTypeTraitOperator(IToken operatorToken) {
switch (operatorToken.getType()) {
case IGCCToken.tTT_is_trivially_constructible:
return ICPPASTNaryTypeIdExpression.Operator.__is_trivially_constructible;
case IGCCToken.tTT_is_constructible:
return ICPPASTNaryTypeIdExpression.Operator.__is_constructible;
}
assert false;
return null;
}
private int getUnaryTypeTraitOperator(IToken first) {
switch (first.getType()) {
case IGCCToken.tTT_has_nothrow_assign:
return IASTTypeIdExpression.op_has_nothrow_assign;
case IGCCToken.tTT_has_nothrow_constructor:
return IASTTypeIdExpression.op_has_nothrow_constructor;
case IGCCToken.tTT_has_nothrow_copy:
return IASTTypeIdExpression.op_has_nothrow_copy;
case IGCCToken.tTT_has_trivial_assign:
return IASTTypeIdExpression.op_has_trivial_assign;
case IGCCToken.tTT_has_trivial_constructor:
return IASTTypeIdExpression.op_has_trivial_constructor;
case IGCCToken.tTT_has_trivial_copy:
return IASTTypeIdExpression.op_has_trivial_copy;
case IGCCToken.tTT_has_trivial_destructor:
return IASTTypeIdExpression.op_has_trivial_destructor;
case IGCCToken.tTT_has_virtual_destructor:
return IASTTypeIdExpression.op_has_virtual_destructor;
case IGCCToken.tTT_is_abstract:
return IASTTypeIdExpression.op_is_abstract;
case IGCCToken.tTT_is_class:
return IASTTypeIdExpression.op_is_class;
case IGCCToken.tTT_is_empty:
return IASTTypeIdExpression.op_is_empty;
case IGCCToken.tTT_is_enum:
return IASTTypeIdExpression.op_is_enum;
case IGCCToken.tTT_is_final:
return IASTTypeIdExpression.op_is_final;
case IGCCToken.tTT_is_literal_type:
return IASTTypeIdExpression.op_is_literal_type;
case IGCCToken.tTT_is_pod:
return IASTTypeIdExpression.op_is_pod;
case IGCCToken.tTT_is_polymorphic:
return IASTTypeIdExpression.op_is_polymorphic;
case IGCCToken.tTT_is_standard_layout:
return IASTTypeIdExpression.op_is_standard_layout;
case IGCCToken.tTT_is_trivial:
return IASTTypeIdExpression.op_is_trivial;
case IGCCToken.tTT_is_union:
return IASTTypeIdExpression.op_is_union;
case IGCCToken.tTT_is_trivially_copyable:
return IASTTypeIdExpression.op_is_trivially_copyable;
}
assert false;
return 0;
}
/**
* postfix-expression:
* [gnu-extension, compound literals in c++]
* (type-name) { initializer-list }
* (type-name) { initializer-list , }
*
* primary-expression
* postfix-expression [ expression ]
* postfix-expression [ braced-init-list ]
* postfix-expression (expression-list_opt)
* simple-type-specifier (expression-list_opt)
* simple-type-specifier braced-init-list
* typename-specifier (expression-list_opt)
* typename-specifier braced-init-list
* postfix-expression . templateopt id-expression
* postfix-expression -> templateopt id-expression
* postfix-expression . pseudo-destructor-name
* postfix-expression -> pseudo-destructor-name
* postfix-expression ++
* postfix-expression --
* dynamic_cast < type-id > (expression)
* static_cast < type-id > (expression)
* reinterpret_cast < type-id > (expression)
* const_cast < type-id > (expression)
* typeid (expression)
* typeid (type-id)
*/
private IASTExpression postfixExpression(CastExprCtx ctx, ITemplateIdStrategy strat) throws EndOfFileException, BacktrackException {
IASTExpression firstExpression = null;
boolean isTemplate = false;
int offset;
switch (LT(1)) {
case IToken.t_dynamic_cast:
firstExpression = specialCastExpression(ICPPASTCastExpression.op_dynamic_cast);
break;
case IToken.t_static_cast:
firstExpression = specialCastExpression(ICPPASTCastExpression.op_static_cast);
break;
case IToken.t_reinterpret_cast:
firstExpression = specialCastExpression(ICPPASTCastExpression.op_reinterpret_cast);
break;
case IToken.t_const_cast:
firstExpression = specialCastExpression(ICPPASTCastExpression.op_const_cast);
break;
case IToken.t_typeid:
// 'typeid' (expression)
// 'typeid' (type-id)
firstExpression = parseTypeidInParenthesisOrUnaryExpression(true, consume().getOffset(),
ICPPASTTypeIdExpression.op_typeid, ICPPASTUnaryExpression.op_typeid, ctx, strat);
break;
case IToken.t_noexcept:
// 'noexcept' (expression)
offset= consume().getOffset(); // noexcept
consume(IToken.tLPAREN); // (
firstExpression= expression();
firstExpression= getNodeFactory().newUnaryExpression(IASTUnaryExpression.op_noexcept, firstExpression);
final int endOffset = consume(IToken.tRPAREN).getEndOffset(); //)
setRange(firstExpression, offset, endOffset);
break;
case IToken.tLPAREN:
// Gnu-extension: compound literals in c++
// (type-name) { initializer-list }
// (type-name) { initializer-list , }
IToken m = mark();
try {
if (canBeCompoundLiteral()) {
offset = consume().getOffset();
IASTTypeId t= typeId(DeclarationOptions.TYPEID);
consume(IToken.tRPAREN);
if (LT(1) == IToken.tLBRACE) {
IASTInitializer i = bracedInitList(false, false);
firstExpression= getNodeFactory().newTypeIdInitializerExpression(t, i);
setRange(firstExpression, offset, calculateEndOffset(i));
break;
}
}
} catch (BacktrackException bt) {
}
backup(m);
firstExpression= primaryExpression(ctx, strat);
break;
// typename-specifier (expression-list_opt)
// typename-specifier braced-init-list
// simple-type-specifier (expression-list_opt)
// simple-type-specifier braced-init-list
case IToken.t_typename:
case IToken.t_char:
case IToken.t_char16_t:
case IToken.t_char32_t:
case IToken.t_wchar_t:
case IToken.t_bool:
case IToken.t_short:
case IToken.t_int:
case IToken.t_long:
case IToken.t_signed:
case IToken.t_unsigned:
case IToken.t_float:
case IToken.t_double:
case IToken.t_decltype:
case IToken.t_void:
case IGCCToken.t_typeof:
if (LT(1) == IToken.t_decltype) {
// Might be an id-expression starting with a decltype-specifier.
IToken marked = mark();
try {
firstExpression = primaryExpression(ctx, strat);
break;
} catch (BacktrackException e) {
backup(marked);
}
}
firstExpression = simpleTypeConstructorExpression(simpleTypeSpecifier());
break;
default:
firstExpression = primaryExpression(ctx, strat);
if (firstExpression instanceof IASTIdExpression && LT(1) == IToken.tLBRACE) {
IASTName name = ((IASTIdExpression) firstExpression).getName();
ICPPASTDeclSpecifier declSpec= getNodeFactory().newTypedefNameSpecifier(name);
firstExpression = simpleTypeConstructorExpression(setRange(declSpec, name));
}
break;
}
for (;;) {
switch (LT(1)) {
case IToken.tLBRACKET:
// postfix-expression [ expression ]
// postfix-expression [ braced-init-list ]
consume(IToken.tLBRACKET);
IASTInitializerClause expression;
if (LT(1) == IToken.tLBRACE) {
expression= bracedInitList(false, false);
} else {
expression= expression();
}
int endOffset= consumeOrEOC(IToken.tRBRACKET).getEndOffset();
IASTArraySubscriptExpression s = getNodeFactory().newArraySubscriptExpression(firstExpression, expression);
firstExpression= setRange(s, firstExpression, endOffset);
break;
case IToken.tLPAREN:
// postfix-expression (expression-list_opt)
// simple-type-specifier (expression-list_opt) // cannot be distinguished
consume(IToken.tLPAREN);
IASTInitializerClause[] initArray;
if (LT(1) == IToken.tRPAREN) {
initArray= IASTExpression.EMPTY_EXPRESSION_ARRAY;
} else {
final List<ICPPASTInitializerClause> exprList = expressionList();
initArray = exprList.toArray(new IASTInitializerClause[exprList.size()]);
}
endOffset = consumeOrEOC(IToken.tRPAREN).getEndOffset();
IASTFunctionCallExpression fce = getNodeFactory().newFunctionCallExpression(firstExpression, initArray);
firstExpression= setRange(fce, firstExpression, endOffset);
break;
case IToken.tINCR:
endOffset = consume().getEndOffset();
firstExpression = buildUnaryExpression(IASTUnaryExpression.op_postFixIncr, firstExpression,
((ASTNode) firstExpression).getOffset(), endOffset);
break;
case IToken.tDECR:
endOffset = consume().getEndOffset();
firstExpression = buildUnaryExpression(IASTUnaryExpression.op_postFixDecr, firstExpression,
((ASTNode) firstExpression).getOffset(), endOffset);
break;
case IToken.tDOT:
// member access
IToken dot = consume();
if (LT(1) == IToken.t_template) {
consume();
isTemplate = true;
}
IASTName name = qualifiedName(ctx, strat);
if (name == null)
throwBacktrack(((ASTNode) firstExpression).getOffset(),
((ASTNode) firstExpression).getLength() + dot.getLength());
ICPPASTFieldReference fieldReference = getNodeFactory().newFieldReference(name, firstExpression);
fieldReference.setIsPointerDereference(false);
fieldReference.setIsTemplate(isTemplate);
((ASTNode) fieldReference).setOffsetAndLength(
((ASTNode) firstExpression).getOffset(),
calculateEndOffset(name) - ((ASTNode) firstExpression).getOffset());
firstExpression = fieldReference;
break;
case IToken.tARROW:
// member access
IToken arrow = consume();
if (LT(1) == IToken.t_template) {
consume();
isTemplate = true;
}
name = qualifiedName(ctx, strat);
if (name == null)
throwBacktrack(((ASTNode) firstExpression).getOffset(),
((ASTNode) firstExpression).getLength() + arrow.getLength());
fieldReference = getNodeFactory().newFieldReference(name, firstExpression);
fieldReference.setIsPointerDereference(true);
fieldReference.setIsTemplate(isTemplate);
((ASTNode) fieldReference).setOffsetAndLength(
((ASTNode) firstExpression).getOffset(),
calculateEndOffset(name) - ((ASTNode) firstExpression).getOffset());
firstExpression = fieldReference;
break;
default:
return firstExpression;
}
}
}
@Override
protected IASTAmbiguousExpression createAmbiguousExpression() {
return new CPPASTAmbiguousExpression();
}
@Override
protected IASTAmbiguousExpression createAmbiguousBinaryVsCastExpression(IASTBinaryExpression binary, IASTCastExpression castExpr) {
return new CPPASTAmbiguousBinaryVsCastExpression(binary, castExpr);
}
@Override
protected IASTAmbiguousExpression createAmbiguousCastVsFunctionCallExpression(IASTCastExpression castExpr, IASTFunctionCallExpression funcCall) {
return new CPPASTAmbiguousCastVsFunctionCallExpression(castExpr, funcCall);
}
protected ICPPASTAmbiguousTemplateArgument createAmbiguousTemplateArgument() {
return new CPPASTAmbiguousTemplateArgument();
}
private IASTExpression simpleTypeConstructorExpression(ICPPASTDeclSpecifier declSpec) throws EndOfFileException, BacktrackException {
IASTInitializer initializer = bracedOrCtorStyleInitializer();
ICPPASTSimpleTypeConstructorExpression result = getNodeFactory().newSimpleTypeConstructorExpression(
declSpec, initializer);
return setRange(result, declSpec, calculateEndOffset(initializer));
}
@Override
protected IASTExpression primaryExpression(CastExprCtx ctx, ITemplateIdStrategy strat) throws EndOfFileException, BacktrackException {
IToken t = null;
IASTLiteralExpression literalExpr = null;
IASTLiteralExpression literalExprWithRange = null;
switch (LT(1)) {
case IToken.tINTEGER:
t = consume();
literalExpr = getNodeFactory().newLiteralExpression(IASTLiteralExpression.lk_integer_constant, t.getImage(), additionalNumericalSuffixes);
literalExprWithRange = setRange(literalExpr, t.getOffset(), t.getEndOffset());
break;
case IToken.tFLOATINGPT:
t = consume();
literalExpr = getNodeFactory().newLiteralExpression(IASTLiteralExpression.lk_float_constant, t.getImage(), additionalNumericalSuffixes);
literalExprWithRange = setRange(literalExpr, t.getOffset(), t.getEndOffset());
break;
case IToken.tSTRING:
case IToken.tLSTRING:
case IToken.tUTF16STRING:
case IToken.tUTF32STRING:
case IToken.tUSER_DEFINED_STRING_LITERAL:
literalExprWithRange = stringLiteral();
break;
case IToken.tCHAR:
case IToken.tLCHAR:
case IToken.tUTF16CHAR:
case IToken.tUTF32CHAR:
case IToken.tUSER_DEFINED_CHAR_LITERAL:
t = consume();
literalExpr = getNodeFactory().newLiteralExpression(
IASTLiteralExpression.lk_char_constant, t.getImage());
literalExprWithRange = setRange(literalExpr, t.getOffset(), t.getEndOffset());
break;
case IToken.t_false:
t = consume();
literalExpr = getNodeFactory().newLiteralExpression(IASTLiteralExpression.lk_false, t.getImage());
return setRange(literalExpr, t.getOffset(), t.getEndOffset());
case IToken.t_true:
t = consume();
literalExpr = getNodeFactory().newLiteralExpression(IASTLiteralExpression.lk_true, t.getImage());
return setRange(literalExpr, t.getOffset(), t.getEndOffset());
case IToken.t_nullptr:
t= consume();
literalExpr = getNodeFactory().newLiteralExpression(IASTLiteralExpression.lk_nullptr, t.getImage());
return setRange(literalExpr, t.getOffset(), t.getEndOffset());
case IToken.t_this:
t = consume();
literalExpr = getNodeFactory().newLiteralExpression(IASTLiteralExpression.lk_this, t.getImage());
return setRange(literalExpr, t.getOffset(), t.getEndOffset());
case IToken.tLPAREN:
if (supportStatementsInExpressions && LT(2) == IToken.tLBRACE) {
return compoundStatementExpression();
}
t = consume();
int finalOffset= 0;
IASTExpression lhs= expression(ExprKind.eExpression, BinaryExprCtx.eNotInTemplateID, null, null); // instead of expression(), to keep the stack smaller
switch (LT(1)) {
case IToken.tRPAREN:
case IToken.tEOC:
finalOffset = consume().getEndOffset();
break;
default:
throwBacktrack(LA(1));
}
return buildUnaryExpression(IASTUnaryExpression.op_bracketedPrimary, lhs, t.getOffset(), finalOffset);
case IToken.tIDENTIFIER:
case IToken.tCOLONCOLON:
case IToken.t_operator:
case IToken.tCOMPLETION:
case IToken.tBITCOMPLEMENT:
case IToken.t_decltype: {
IASTName name = qualifiedName(ctx, strat);
// A qualified-name's last name can sometimes be empty in a declaration (e.g. in "int A::*x",
// "A::" is a valid qualified-name with an empty last name), but not in an expression
// (unless we are invoking code completion at the '::').
if (name.getLookupKey().length == 0 && LT(1) != IToken.tEOC)
throwBacktrack(LA(1));
IASTIdExpression idExpression = getNodeFactory().newIdExpression(name);
return setRange(idExpression, name);
}
case IToken.tLBRACKET:
return lambdaExpression();
default:
IToken la = LA(1);
int startingOffset = la.getOffset();
throwBacktrack(startingOffset, la.getLength());
return null;
}
if (supportUserDefinedLiterals) {
IToken la = LA(1);
int offset = ((ASTNode) literalExprWithRange).getOffset();
int length = ((ASTNode) literalExprWithRange).getLength();
if (isIdentifierOrKeyword(la)) {
if ((offset + length) != la.getOffset()) {
return literalExprWithRange;
}
consume();
((CPPASTLiteralExpression) literalExprWithRange).setSuffix(la.getCharImage());
setRange(literalExprWithRange, offset, la.getEndOffset());
}
}
return literalExprWithRange;
}
private ICPPASTLiteralExpression stringLiteral() throws EndOfFileException, BacktrackException {
switch (LT(1)) {
case IToken.tSTRING:
case IToken.tLSTRING:
case IToken.tUTF16STRING:
case IToken.tUTF32STRING:
case IToken.tUSER_DEFINED_STRING_LITERAL:
break;
default:
throwBacktrack(LA(1));
}
IToken t= consume();
ICPPASTLiteralExpression r= getNodeFactory().newLiteralExpression(IASTLiteralExpression.lk_string_literal, t.getImage());
return setRange(r, t.getOffset(), t.getEndOffset());
}
private IASTExpression lambdaExpression() throws EndOfFileException, BacktrackException {
final int offset= LA().getOffset();
ICPPASTLambdaExpression lambdaExpr= getNodeFactory().newLambdaExpression();
// Lambda introducer
consume(IToken.tLBRACKET);
boolean needComma= false;
switch (LT(1)) {
case IToken.tASSIGN:
lambdaExpr.setCaptureDefault(CaptureDefault.BY_COPY);
consume();
needComma= true;
break;
case IToken.tAMPER:
final int lt2 = LT(2);
if (lt2 == IToken.tCOMMA || lt2 == IToken.tRBRACKET) {
lambdaExpr.setCaptureDefault(CaptureDefault.BY_REFERENCE);
consume();
needComma= true;
}
break;
}
loop: while (true) {
switch (LT(1)) {
case IToken.tEOC:
return setRange(lambdaExpr, offset, LA().getEndOffset());
case IToken.tRBRACKET:
consume();
break loop;
}
if (needComma) {
consume(IToken.tCOMMA);
}
ICPPASTCapture cap= capture();
lambdaExpr.addCapture(cap);
needComma= true;
}
if (LT(1) == IToken.tLPAREN) {
ICPPASTFunctionDeclarator dtor = functionDeclarator(true);
lambdaExpr.setDeclarator(dtor);
if (LT(1) == IToken.tEOC)
return setRange(lambdaExpr, offset, calculateEndOffset(dtor));
}
IASTCompoundStatement body = functionBody();
lambdaExpr.setBody(body);
return setRange(lambdaExpr, offset, calculateEndOffset(body));
}
private ICPPASTInitCapture createInitCapture(IASTName identifier, IASTInitializer initializer, boolean isReference, int offset)
throws EndOfFileException, BacktrackException {
ICPPASTDeclarator declarator = getNodeFactory().newDeclarator(identifier);
declarator.setInitializer(initializer);
if (isReference) {
declarator.addPointerOperator(getNodeFactory().newReferenceOperator(false));
}
setRange(declarator, offset, calculateEndOffset(initializer));
ICPPASTInitCapture initCapture = getNodeFactory().newInitCapture(declarator);
return setRange(initCapture, offset, calculateEndOffset(initializer));
}
private ICPPASTCapture capture() throws EndOfFileException, BacktrackException {
final int offset = LA().getOffset();
ICPPASTCapture result = getNodeFactory().newCapture();
boolean referenceCapture = false;
switch (LT(1)) {
case IToken.t_this:
result.setIsByReference(true);
return setRange(result, offset, consume().getEndOffset());
case IToken.tAMPER:
consume();
referenceCapture = true;
break;
case IToken.tSTAR:
if (LT(2) == IToken.t_this) {
consume();
return setRange(result, offset, consume().getEndOffset());
}
break;
}
final IASTName identifier = identifier();
result.setIdentifier(identifier);
result.setIsByReference(referenceCapture);
setRange(result, offset, calculateEndOffset(identifier));
switch(LT(1)) {
case IToken.tASSIGN:
result = createInitCapture(identifier, equalsInitalizerClause(false), referenceCapture, offset);
break;
case IToken.tLBRACE:
case IToken.tLPAREN:
result = createInitCapture(identifier, bracedOrCtorStyleInitializer(), referenceCapture, offset);
break;
}
if (LT(1) == IToken.tELLIPSIS) {
// Note this will probably change with C++20 such that the
// pack expansion of a CPPASTInitCapture will be part of the IASTDeclarator
// and not the capture. [See: P0780R2]
result.setIsPackExpansion(true);
return setRange(result, offset, consume().getEndOffset());
}
return result;
}
protected IASTExpression specialCastExpression(int kind) throws EndOfFileException, BacktrackException {
final int offset = LA(1).getOffset();
final int optype= consume().getType();
consume(IToken.tLT);
final IASTTypeId typeID = typeId(DeclarationOptions.TYPEID);
final IToken gt = LA(1);
if (gt.getType() == IToken.tGT || gt.getType() == IToken.tGT_in_SHIFTR) {
consume();
} else if (gt.getType() != IToken.tEOC) {
throwBacktrack(gt);
}
consumeOrEOC(IToken.tLPAREN);
IASTExpression operand= null;
if (LT(1) != IToken.tEOC) {
operand= expression();
}
final int endOffset= consumeOrEOC(IToken.tRPAREN).getEndOffset();
int operator;
switch (optype) {
case IToken.t_dynamic_cast:
operator = ICPPASTCastExpression.op_dynamic_cast;
break;
case IToken.t_static_cast:
operator = ICPPASTCastExpression.op_static_cast;
break;
case IToken.t_reinterpret_cast:
operator = ICPPASTCastExpression.op_reinterpret_cast;
break;
case IToken.t_const_cast:
operator = ICPPASTCastExpression.op_const_cast;
break;
default:
operator = IASTCastExpression.op_cast;
break;
}
return buildCastExpression(operator, typeID, operand, offset, endOffset);
}
/**
* The merger of using-declaration and using-directive in ANSI C++ grammar.
* using-declaration: using typename? ::? nested-name-specifier
* unqualified-id ; using :: unqualified-id ; using-directive: using
* namespace ::? nested-name-specifier? namespace-name ;
*
* @throws BacktrackException
* request for a backtrack
*/
protected IASTDeclaration usingClause(List<IASTAttributeSpecifier> attributes)
throws EndOfFileException, BacktrackException {
final int offset= consume().getOffset();
if (LT(1) == IToken.t_namespace) {
// using-directive
int endOffset = consume().getEndOffset();
IASTName name = null;
switch (LT(1)) {
case IToken.tIDENTIFIER:
case IToken.tCOLONCOLON:
case IToken.tCOMPLETION:
name = qualifiedName();
break;
default:
throwBacktrack(offset, endOffset - offset);
}
attributes = CollectionUtils.merge(attributes, __attribute_decl_seq(supportAttributeSpecifiers, false));
switch (LT(1)) {
case IToken.tSEMI:
case IToken.tEOC:
endOffset = consume().getEndOffset();
break;
default:
throw backtrack;
}
ICPPASTUsingDirective astUD = getNodeFactory().newUsingDirective(name);
addAttributeSpecifiers(attributes, astUD);
((ASTNode) astUD).setOffsetAndLength(offset, endOffset - offset);
return astUD;
}
if (LT(1) == IToken.tIDENTIFIER
&& (LT(2) == IToken.tASSIGN || (LT(2) == IToken.tLBRACKET && LT(3) == IToken.tLBRACKET))) {
return aliasDeclaration(offset);
}
ICPPASTUsingDeclaration result = usingDeclaration(offset);
return result;
}
/**
* alias-declaration
* using identifier attribute-specifier-seq? = type-id ;
*
* @throws EndOfFileException
*/
private IASTDeclaration aliasDeclaration(final int offset) throws EndOfFileException,
BacktrackException {
IToken identifierToken = consume();
IASTName aliasName = buildName(-1, identifierToken);
List<IASTAttributeSpecifier> attributes = attributeSpecifierSeq();
consume();
ICPPASTTypeId aliasedType = typeId(DeclarationOptions.TYPEID);
final int nextToken = LT(1);
if (nextToken != IToken.tSEMI && nextToken != IToken.tEOC) {
throw backtrack;
}
int endOffset = consume().getEndOffset();
ICPPASTAliasDeclaration aliasDeclaration = getNodeFactory().newAliasDeclaration(aliasName, aliasedType);
addAttributeSpecifiers(attributes, aliasDeclaration);
setRange(aliasDeclaration, offset, endOffset);
return aliasDeclaration;
}
private ICPPASTUsingDeclaration usingDeclaration(final int offset) throws EndOfFileException, BacktrackException {
boolean typeName = false;
if (LT(1) == IToken.t_typename) {
typeName = true;
consume();
}
IASTName name = qualifiedName();
int end;
switch (LT(1)) {
case IToken.tSEMI:
case IToken.tEOC:
end = consume().getEndOffset();
break;
default:
throw backtrack;
}
ICPPASTUsingDeclaration result = getNodeFactory().newUsingDeclaration(name);
((ASTNode) result).setOffsetAndLength(offset, end - offset);
result.setIsTypename(typeName);
return result;
}
/**
* static_assert-declaration:
* static_assert (constant-expression);
* OR
* static_assert (constant-expression , string-literal);
*/
private ICPPASTStaticAssertDeclaration staticAssertDeclaration() throws EndOfFileException, BacktrackException {
int offset= consume(IToken.t_static_assert).getOffset();
consume(IToken.tLPAREN);
IASTExpression e= constantExpression();
int endOffset= calculateEndOffset(e);
ICPPASTLiteralExpression message = null;
if (LT(1) == IToken.tCOMMA) {
consume(IToken.tCOMMA);
message = stringLiteral();
}
ICPPASTStaticAssertDeclaration assertion = getNodeFactory().newStaticAssertion(e, message);
if (LT(1) != IToken.tEOC) {
consume(IToken.tRPAREN);
endOffset = consume(IToken.tSEMI).getEndOffset();
}
return setRange(assertion, offset, endOffset);
}
/**
* Implements Linkage specification in the ANSI C++ grammar.
* linkageSpecification : extern "string literal" declaration | extern
* "string literal" { declaration-seq }
*
* @throws BacktrackException
* request for a backtrack
*/
protected ICPPASTLinkageSpecification linkageSpecification() throws EndOfFileException, BacktrackException {
int offset= consume().getOffset(); // t_extern
String spec = consume().getImage(); // tString
ICPPASTLinkageSpecification linkage = getNodeFactory().newLinkageSpecification(spec);
if (LT(1) == IToken.tLBRACE) {
declarationListInBraces(linkage, offset, DeclarationOptions.GLOBAL);
return linkage;
}
// single declaration
IASTDeclaration d = declaration(DeclarationOptions.GLOBAL);
linkage.addDeclaration(d);
setRange(linkage, offset, calculateEndOffset(d));
return linkage;
}
/**
* Represents the amalgamation of template declarations, template
* instantiations and specializations in the ANSI C++ grammar.
* template-declaration: export? template < template-parameter-list >
* declaration explicit-instantiation: template declaration
* explicit-specialization: template <>declaration
* @param option
*
* @throws BacktrackException
* request for a backtrack
*/
protected IASTDeclaration templateDeclaration(DeclarationOptions option) throws EndOfFileException, BacktrackException {
final int offset= LA(1).getOffset();
boolean exported = false;
int explicitInstMod= 0;
switch (LT(1)) {
case IToken.t_export:
exported = true;
consume();
break;
case IToken.t_extern:
consume();
explicitInstMod= ICPPASTExplicitTemplateInstantiation.EXTERN;
break;
case IToken.t_static:
consume();
explicitInstMod= ICPPASTExplicitTemplateInstantiation.STATIC;
break;
case IToken.t_inline:
consume();
explicitInstMod= ICPPASTExplicitTemplateInstantiation.INLINE;
break;
}
consume(IToken.t_template);
if (LT(1) != IToken.tLT) {
// explicit-instantiation
IASTDeclaration d = declaration(option);
ICPPASTExplicitTemplateInstantiation ti= getNodeFactory().newExplicitTemplateInstantiation(d);
ti.setModifier(explicitInstMod);
setRange(ti, offset, calculateEndOffset(d));
return ti;
}
// Modifiers for explicit instantiations
if (explicitInstMod != 0) {
throwBacktrack(LA(1));
}
consume(IToken.tLT);
if (LT(1) == IToken.tGT) {
// explicit-specialization
consume();
IASTDeclaration d = declaration(option);
ICPPASTTemplateSpecialization templateSpecialization = getNodeFactory().newTemplateSpecialization(d);
setRange(templateSpecialization, offset, calculateEndOffset(d));
return templateSpecialization;
}
List<ICPPASTTemplateParameter> parms= outerTemplateParameterList();
if (LT(1) != IToken.tEOC) {
consume(IToken.tGT, IToken.tGT_in_SHIFTR);
}
IASTDeclaration d = declaration(option);
ICPPASTTemplateDeclaration templateDecl = getNodeFactory().newTemplateDeclaration(d);
setRange(templateDecl, offset, calculateEndOffset(d));
templateDecl.setExported(exported);
for (int i = 0; i < parms.size(); ++i) {
ICPPASTTemplateParameter parm = parms.get(i);
templateDecl.addTemplateParameter(parm);
}
return templateDecl;
}
/**
* template-parameter-list: template-parameter template-parameter-list ,
* template-parameter template-parameter: type-parameter
* parameter-declaration type-parameter: class identifier? class identifier? =
* type-id typename identifier? typename identifier? = type-id template <
* template-parameter-list > class identifier? template <
* template-parameter-list > class identifier? = id-expression template-id:
* template-name < template-argument-list?> template-name: identifier
* template-argument-list: template-argument template-argument-list ,
* template-argument template-argument: assignment-expression type-id
* id-expression
*
* @throws BacktrackException
* request for a backtrack
*/
protected List<ICPPASTTemplateParameter> outerTemplateParameterList() throws BacktrackException, EndOfFileException {
fTemplateParameterListStrategy= new TemplateIdStrategy();
try {
List<ICPPASTTemplateParameter> result = new ArrayList<>(DEFAULT_PARM_LIST_SIZE);
IToken m= mark();
while (true) {
try {
return templateParameterList(result);
} catch (BacktrackException e) {
if (!fTemplateParameterListStrategy.setNextAlternative(true /* previous alternative failed to parse */)) {
fTemplateParameterListStrategy= null;
throw e;
}
result.clear();
backup(m);
}
}
} finally {
fTemplateParameterListStrategy= null;
}
}
private List<ICPPASTTemplateParameter> templateParameterList(List<ICPPASTTemplateParameter> result)
throws EndOfFileException, BacktrackException {
boolean needComma= false;
for (;;) {
final int lt1= LT(1);
if (lt1 == IToken.tGT || lt1 == IToken.tEOC || lt1 == IToken.tGT_in_SHIFTR) {
return result;
}
if (needComma) {
consume(IToken.tCOMMA);
} else {
needComma= true;
}
result.add(templateParameter());
}
}
private ICPPASTTemplateParameter templateParameter() throws EndOfFileException, BacktrackException {
final int lt1= LT(1);
final IToken start= mark();
if (lt1 == IToken.t_class || lt1 == IToken.t_typename) {
try {
int type = (lt1 == IToken.t_class ? ICPPASTSimpleTypeTemplateParameter.st_class
: ICPPASTSimpleTypeTemplateParameter.st_typename);
boolean parameterPack= false;
IASTName identifierName = null;
IASTTypeId defaultValue = null;
int endOffset = consume().getEndOffset();
if (LT(1) == IToken.tELLIPSIS) {
parameterPack= true;
endOffset= consume().getOffset();
}
if (LT(1) == IToken.tIDENTIFIER) { // optional identifier
identifierName = identifier();
endOffset = calculateEndOffset(identifierName);
} else {
identifierName = getNodeFactory().newName();
setRange(identifierName, endOffset, endOffset);
}
if (LT(1) == IToken.tASSIGN) { // optional = type-id
if (parameterPack)
throw backtrack;
consume();
defaultValue = typeId(DeclarationOptions.TYPEID); // type-id
endOffset = calculateEndOffset(defaultValue);
}
// Check if followed by comma
switch (LT(1)) {
case IToken.tGT:
case IToken.tEOC:
case IToken.tGT_in_SHIFTR:
case IToken.tCOMMA:
ICPPASTSimpleTypeTemplateParameter tpar = getNodeFactory().newSimpleTypeTemplateParameter(type, identifierName, defaultValue);
tpar.setIsParameterPack(parameterPack);
setRange(tpar, start.getOffset(), endOffset);
return tpar;
}
} catch (BacktrackException bt) {
}
// Can be a non-type template parameter, see bug 333285
backup(start);
} else if (lt1 == IToken.t_template) {
boolean parameterPack= false;
IASTName identifierName = null;
IASTExpression defaultValue = null;
consume();
consume(IToken.tLT);
List<ICPPASTTemplateParameter> tparList = templateParameterList(new ArrayList<>());
consume(IToken.tGT, IToken.tGT_in_SHIFTR);
int endOffset = consume(IToken.t_class).getEndOffset();
if (LT(1) == IToken.tELLIPSIS) {
parameterPack= true;
endOffset= consume().getOffset();
}
if (LT(1) == IToken.tIDENTIFIER) { // optional identifier
identifierName = identifier();
endOffset = calculateEndOffset(identifierName);
if (LT(1) == IToken.tASSIGN) { // optional = type-id
if (parameterPack)
throw backtrack;
consume();
defaultValue = primaryExpression(CastExprCtx.eNotInBExpr, null);
endOffset = calculateEndOffset(defaultValue);
}
} else {
identifierName = getNodeFactory().newName();
}
ICPPASTTemplatedTypeTemplateParameter tpar = getNodeFactory().newTemplatedTypeTemplateParameter(identifierName, defaultValue);
tpar.setIsParameterPack(parameterPack);
setRange(tpar, start.getOffset(), endOffset);
for (int i = 0; i < tparList.size(); ++i) {
ICPPASTTemplateParameter p = tparList.get(i);
tpar.addTemplateParameter(p);
}
return tpar;
}
// Try non-type template parameter
return parameterDeclaration();
}
/**
* The most abstract construct within a translationUnit : a declaration.
* declaration : {"asm"} asmDefinition | {"namespace"} namespaceDefinition |
* {"using"} usingDeclaration | {"export"|"template"} templateDeclaration |
* {"extern"} linkageSpecification | simpleDeclaration Notes: - folded in
* blockDeclaration - merged alternatives that required same LA -
* functionDefinition into simpleDeclaration - namespaceAliasDefinition into
* namespaceDefinition - usingDirective into usingDeclaration -
* explicitInstantiation and explicitSpecialization into templateDeclaration
* - fetched attributes at the beginning to avoid arbitrary lookahead
*
* @throws BacktrackException
* request a backtrack
*/
@Override
protected IASTDeclaration declaration(DeclarationOptions option) throws EndOfFileException, BacktrackException {
List<IASTAttributeSpecifier> attributes = attributeSpecifierSeq();
switch (LT(1)) {
case IToken.t_asm:
return asmDeclaration();
case IToken.t_namespace:
return namespaceDefinitionOrAlias();
case IToken.t_using:
return usingClause(attributes);
case IToken.t_static_assert:
return staticAssertDeclaration();
case IToken.t_export:
case IToken.t_template:
return templateDeclaration(option);
case IToken.t_extern:
if (LT(2) == IToken.tSTRING)
return linkageSpecification();
if (LT(2) == IToken.t_template)
return templateDeclaration(option);
break;
case IToken.t_static:
case IToken.t_inline:
if (supportExtendedTemplateSyntax && LT(2) == IToken.t_template)
return templateDeclaration(option);
if (LT(2) == IToken.t_namespace) {
return namespaceDefinitionOrAlias();
}
break;
case IToken.tSEMI:
IToken t= consume();
IASTSimpleDeclSpecifier declspec= getNodeFactory().newSimpleDeclSpecifier();
IASTSimpleDeclaration decl= getNodeFactory().newSimpleDeclaration(declspec);
((ASTNode) declspec).setOffsetAndLength(t.getOffset(), 0);
((ASTNode) decl).setOffsetAndLength(t.getOffset(), t.getLength());
return decl;
case IToken.t_public:
case IToken.t_protected:
case IToken.t_private:
if (option == DeclarationOptions.CPP_MEMBER) {
t= consume();
int key= t.getType();
int endOffset= consume(IToken.tCOLON).getEndOffset();
ICPPASTVisibilityLabel label = getNodeFactory().newVisibilityLabel(token2Visibility(key));
setRange(label, t.getOffset(), endOffset);
return label;
}
break;
}
try {
return simpleDeclaration(option, attributes);
} catch (BacktrackException e) {
if (option != DeclarationOptions.CPP_MEMBER || declarationMark == null)
throw e;
BacktrackException orig= new BacktrackException(e); // copy the exception
IToken mark= mark();
backup(declarationMark);
try {
return usingDeclaration(declarationMark.getOffset());
} catch (BacktrackException e2) {
backup(mark);
throw orig; // throw original exception;
}
}
}
/**
* Serves as the namespace declaration portion of the ANSI C++ grammar.
* namespace-definition: namespace identifier { namespace-body } | namespace {
* namespace-body } namespace-body: declaration-seq?
*
* @throws BacktrackException
* request a backtrack
*/
protected IASTDeclaration namespaceDefinitionOrAlias() throws BacktrackException, EndOfFileException {
final int offset= LA().getOffset();
int endOffset;
boolean isInline= false;
if (LT(1) == IToken.t_inline) {
consume();
isInline= true;
}
consume(IToken.t_namespace);
// optional name
ICPPASTName name = null;
if (LT(1) == IToken.tIDENTIFIER) {
name = qualifiedName();
endOffset= calculateEndOffset(name);
} else {
name = getNodeFactory().newName();
}
// bug 195701, gcc 4.2 allows visibility attribute for namespaces.
List<IASTAttributeSpecifier> attributeSpecifiers = __attribute_decl_seq(true, false);
if (LT(1) == IToken.tLBRACE) {
ICPPASTNamespaceDefinition outer = null;
ICPPASTNamespaceDefinition inner = null;
if (name instanceof ICPPASTQualifiedName) {
// Handle C++17 nested namespace definition.
ICPPASTNameSpecifier[] qualifier = ((ICPPASTQualifiedName) name).getQualifier();
for (ICPPASTNameSpecifier specifier : qualifier) {
if (!(specifier instanceof ICPPASTName)) {
// No decltype-specifiers in nested namespace definition.
throwBacktrack(specifier);
return null;
}
ICPPASTName segment = (ICPPASTName) specifier;
ICPPASTNamespaceDefinition ns = getNodeFactory().newNamespaceDefinition(segment);
if (outer == null || inner == null) { // second half of condition is just to avoid warning
outer = ns;
} else {
inner.addDeclaration(ns);
}
inner = ns;
}
}
IASTName lastName = name.getLastName();
ICPPASTNamespaceDefinition ns = getNodeFactory().newNamespaceDefinition(lastName);
if (outer == null || inner == null) { // second half of condition is just to avoid warning
outer = ns;
} else {
inner.addDeclaration(ns);
}
ns.setIsInline(isInline);
declarationListInBraces(ns, offset, DeclarationOptions.GLOBAL);
endOffset = getEndOffset();
if (ns != outer) {
// For a C++17 nested namespace definition, we need to set the offset/length of
// the enclosing namespace declaration nodes (declarationListInBraces() does it
// for the inner one).
for (IASTNode parent = ns.getParent(); parent != null; parent = parent.getParent()) {
setRange(parent, offset, endOffset);
if (parent == outer) {
break;
}
}
}
addAttributeSpecifiers(attributeSpecifiers, ns);
return outer;
}
if (LT(1) == IToken.tASSIGN) {
endOffset= consume().getEndOffset();
if (name.toString() == null || name instanceof ICPPASTQualifiedName) {
throwBacktrack(offset, endOffset - offset);
return null;
}
IASTName qualifiedName= qualifiedName();
endOffset = consume(IToken.tSEMI).getEndOffset();
ICPPASTNamespaceAlias alias = getNodeFactory().newNamespaceAlias(name, qualifiedName);
((ASTNode) alias).setOffsetAndLength(offset, endOffset - offset);
return alias;
}
throwBacktrack(LA(1));
return null;
}
protected List<IASTAttributeSpecifier> attributeSpecifierSeq() throws EndOfFileException,
BacktrackException {
List<IASTAttributeSpecifier> specifiers = null;
while ((LTcatchEOF(1) == IToken.tLBRACKET && LTcatchEOF(2) == IToken.tLBRACKET) ||
LTcatchEOF(1) == IToken.t_alignas) {
if (specifiers == null)
specifiers = new ArrayList<>();
if (LTcatchEOF(1) == IToken.t_alignas) {
specifiers.add((ICPPASTAlignmentSpecifier) alignmentSpecifier());
} else {
int offset = consumeOrEOC(IToken.tLBRACKET).getOffset();
consumeOrEOC(IToken.tLBRACKET);
ICPPASTAttributeList attributeList = getNodeFactory().newAttributeList();
while (LT(1) != IToken.tRBRACKET) {
if (LT(1) == IToken.tCOMMA)
consume();
ICPPASTAttribute attribute = singleAttribute();
attributeList.addAttribute(attribute);
}
consumeOrEOC(IToken.tRBRACKET);
int endOffset = consumeOrEOC(IToken.tRBRACKET).getEndOffset();
setRange(attributeList, offset, endOffset);
specifiers.add(attributeList);
}
}
return specifiers;
}
@Override
protected ICPPASTAttribute singleAttribute() throws EndOfFileException, BacktrackException {
// Get an identifier including keywords
IToken nameToken = identifierOrKeyword();
IToken scopeToken = null;
IASTToken argumentClause = null;
boolean packExpansion = false;
// Check for scoped attribute
if (LT(1) == IToken.tCOLONCOLON) {
consume();
scopeToken = nameToken;
nameToken = identifierOrKeyword();
}
int endOffset = nameToken.getEndOffset();
// Check for arguments
if (LT(1) == IToken.tLPAREN) {
IToken t = consume();
argumentClause = balancedTokenSeq(t.getEndOffset(), IToken.tRPAREN);
//endOffset = calculateEndOffset(argumentClause);
endOffset = consume(IToken.tRPAREN).getEndOffset();
}
// Check for pack expansion
if (LT(1) == IToken.tELLIPSIS) {
packExpansion = true;
endOffset = consumeOrEOC(IToken.tELLIPSIS).getEndOffset();
}
char[] attributeName = nameToken.getCharImage();
char[] scopeName = scopeToken != null ? scopeToken.getCharImage() : null;
ICPPASTAttribute result = getNodeFactory().newAttribute(attributeName, scopeName,
argumentClause, packExpansion);
setRange(result, nameToken.getOffset(), endOffset);
return result;
}
@Override
protected boolean isLegalWithoutDtor(IASTDeclSpecifier declSpec) {
if (declSpec instanceof IASTElaboratedTypeSpecifier) {
return ((IASTElaboratedTypeSpecifier) declSpec).getKind() != IASTElaboratedTypeSpecifier.k_enum;
} else if (declSpec instanceof ICPPASTNamedTypeSpecifier &&
((ICPPASTNamedTypeSpecifier) declSpec).isFriend()) {
return true;
}
return super.isLegalWithoutDtor(declSpec);
}
/**
* Parses a declaration with the given options.
*/
protected IASTDeclaration simpleDeclaration(DeclarationOptions declOption, List<IASTAttributeSpecifier> attributes)
throws BacktrackException, EndOfFileException {
if (LT(1) == IToken.tLBRACE)
throwBacktrack(LA(1));
final int firstOffset= LA(1).getOffset();
int endOffset= firstOffset;
boolean insertSemi= false;
IASTDeclSpecifier declSpec= null;
IASTDeclarator dtor= null;
IASTDeclSpecifier altDeclSpec= null;
IASTDeclarator altDtor= null;
IToken markBeforDtor= null;
try {
Decl decl= declSpecifierSequence_initDeclarator(declOption, true);
markBeforDtor= decl.fDtorToken1;
declSpec= decl.fDeclSpec1;
dtor= decl.fDtor1;
altDeclSpec= decl.fDeclSpec2;
altDtor= decl.fDtor2;
} catch (FoundAggregateInitializer lie) {
declSpec= lie.fDeclSpec;
// scalability: don't keep references to tokens, initializer may be large
declarationMark= null;
dtor= addInitializer(lie, declOption);
} catch (BacktrackException e) {
IASTNode node= e.getNodeBeforeProblem();
if (node instanceof IASTDeclSpecifier && isLegalWithoutDtor((IASTDeclSpecifier) node)) {
IASTSimpleDeclaration d= getNodeFactory().newSimpleDeclaration((IASTDeclSpecifier) node);
setRange(d, node);
throwBacktrack(e.getProblem(), d);
}
throw e;
}
IASTDeclarator[] declarators= IASTDeclarator.EMPTY_DECLARATOR_ARRAY;
if (dtor != null) {
declarators= new IASTDeclarator[] { dtor };
if (!declOption.fSingleDtor) {
while (LTcatchEOF(1) == IToken.tCOMMA) {
consume();
try {
dtor= initDeclarator(declSpec, declOption);
} catch (FoundAggregateInitializer e) {
// scalability: don't keep references to tokens, initializer may be large
declarationMark= null;
markBeforDtor= null;
dtor= addInitializer(e, declOption);
}
declarators = ArrayUtil.append(IASTDeclarator.class, declarators, dtor);
}
declarators = ArrayUtil.removeNulls(IASTDeclarator.class, declarators);
}
}
final int lt1= LTcatchEOF(1);
switch (lt1) {
case IToken.tEOC:
endOffset= figureEndOffset(declSpec, declarators);
break;
case IToken.tSEMI:
endOffset= consume().getEndOffset();
break;
case IToken.tCOLON:
if (declOption == DeclarationOptions.RANGE_BASED_FOR) {
endOffset= figureEndOffset(declSpec, declarators);
break;
}
//$FALL-THROUGH$
case IToken.t_try:
case IToken.tLBRACE:
case IToken.tASSIGN: // defaulted or deleted function definition
if (declarators.length != 1 || !declOption.fAllowFunctionDefinition)
throwBacktrack(LA(1));
dtor= declarators[0];
if (altDeclSpec != null && altDtor != null && dtor != null &&
!(ASTQueries.findTypeRelevantDeclarator(dtor) instanceof IASTFunctionDeclarator)) {
declSpec= altDeclSpec;
dtor= altDtor;
}
ICPPASTFunctionDefinition functionDefinition = functionDefinition(firstOffset, declSpec, dtor);
addAttributeSpecifiers(attributes, functionDefinition);
return functionDefinition;
default:
insertSemi= true;
if (declOption == DeclarationOptions.LOCAL) {
endOffset= figureEndOffset(declSpec, declarators);
break;
} else {
if (isLegalWithoutDtor(declSpec) && markBeforDtor != null && !isOnSameLine(calculateEndOffset(declSpec), markBeforDtor.getOffset())) {
backup(markBeforDtor);
declarators= IASTDeclarator.EMPTY_DECLARATOR_ARRAY;
endOffset= calculateEndOffset(declSpec);
break;
}
endOffset= figureEndOffset(declSpec, declarators);
if (lt1 == 0 || !isOnSameLine(endOffset, LA(1).getOffset())) {
break;
}
if (declarators.length == 1 && declarators[0] instanceof IASTFunctionDeclarator) {
break;
}
}
throwBacktrack(LA(1));
}
// no function body
final boolean isAmbiguous= altDeclSpec != null && altDtor != null && declarators.length == 1;
IASTSimpleDeclaration simpleDeclaration;
if (isAmbiguous) {
// class C { C(T); }; // if T is a type this is a constructor, so
// prefer the empty declspec, it shall be used if both variants show no problems
simpleDeclaration= getNodeFactory().newSimpleDeclaration(altDeclSpec);
simpleDeclaration.addDeclarator(altDtor);
} else {
simpleDeclaration= getNodeFactory().newSimpleDeclaration(declSpec);
for (IASTDeclarator declarator : declarators) {
simpleDeclaration.addDeclarator(declarator);
}
}
setRange(simpleDeclaration, firstOffset, endOffset);
if (isAmbiguous) {
simpleDeclaration = new CPPASTAmbiguousSimpleDeclaration(simpleDeclaration, declSpec, dtor);
setRange(simpleDeclaration, firstOffset, endOffset);
}
if (insertSemi) {
IASTProblem problem= createProblem(IProblem.MISSING_SEMICOLON, endOffset-1, 1);
throwBacktrack(problem, simpleDeclaration);
}
addAttributeSpecifiers(attributes, simpleDeclaration);
return simpleDeclaration;
}
private ICPPASTFunctionDefinition functionDefinition(final int firstOffset, IASTDeclSpecifier declSpec,
IASTDeclarator outerDtor) throws EndOfFileException, BacktrackException {
final IASTDeclarator dtor= ASTQueries.findTypeRelevantDeclarator(outerDtor);
if (!(dtor instanceof ICPPASTFunctionDeclarator))
throwBacktrack(firstOffset, LA(1).getEndOffset() - firstOffset);
ICPPASTFunctionDefinition fdef;
if (LT(1) == IToken.t_try) {
consume();
fdef= getNodeFactory().newFunctionTryBlock(declSpec, (ICPPASTFunctionDeclarator) dtor, null);
} else {
fdef= getNodeFactory().newFunctionDefinition(declSpec, (ICPPASTFunctionDeclarator) dtor, null);
}
if (LT(1) == IToken.tASSIGN) {
consume();
IToken kind= consume();
switch (kind.getType()) {
case IToken.t_default:
fdef.setIsDefaulted(true);
break;
case IToken.t_delete:
fdef.setIsDeleted(true);
break;
default:
throwBacktrack(kind);
}
return setRange(fdef, firstOffset, consume(IToken.tSEMI).getEndOffset());
}
if (LT(1) == IToken.tCOLON) {
ctorInitializer(fdef);
}
try {
IASTStatement body= handleFunctionBody();
fdef.setBody(body);
setRange(fdef, firstOffset, calculateEndOffset(body));
} catch (BacktrackException bt) {
final IASTNode n= bt.getNodeBeforeProblem();
if (n instanceof IASTCompoundStatement && !(fdef instanceof ICPPASTFunctionWithTryBlock)) {
fdef.setBody((IASTCompoundStatement) n);
setRange(fdef, firstOffset, calculateEndOffset(n));
throwBacktrack(bt.getProblem(), fdef);
}
throw bt;
}
if (fdef instanceof ICPPASTFunctionWithTryBlock) {
ICPPASTFunctionWithTryBlock tryblock= (ICPPASTFunctionWithTryBlock) fdef;
List<ICPPASTCatchHandler> handlers = new ArrayList<>(DEFAULT_CATCH_HANDLER_LIST_SIZE);
catchHandlerSequence(handlers);
ICPPASTCatchHandler last= null;
for (ICPPASTCatchHandler catchHandler : handlers) {
tryblock.addCatchHandler(catchHandler);
last= catchHandler;
}
if (last != null) {
adjustLength(tryblock, last);
}
}
return fdef;
}
/**
* ctor-initializer:
* : mem-initializer-list
* mem-initializer-list:
* mem-initializer ...?
* mem-initializer ...?, mem-initializer-list
* mem-initializer:
* mem-initializer-id (expression-list?)
* mem-initializer-id braced-init-list
* mem-initializer-id:
* ::? nested-name-specifier? class-name
* identifier
*/
protected void ctorInitializer(ICPPASTFunctionDefinition fdef) throws EndOfFileException, BacktrackException {
consume(IToken.tCOLON);
loop: while (true) {
final int offset= LA(1).getOffset();
final IASTName name = qualifiedName();
final IASTInitializer init;
int endOffset;
if (LT(1) != IToken.tEOC) {
init = bracedOrCtorStyleInitializer();
endOffset= calculateEndOffset(init);
} else {
init= null;
endOffset= calculateEndOffset(name);
}
ICPPASTConstructorChainInitializer ctorInitializer = getNodeFactory().newConstructorChainInitializer(name, init);
if (LT(1) == IToken.tELLIPSIS) {
ctorInitializer.setIsPackExpansion(true);
endOffset= consume().getEndOffset();
}
fdef.addMemberInitializer(setRange(ctorInitializer, offset, endOffset));
if (LT(1) == IToken.tCOMMA) {
consume();
} else {
break loop;
}
}
}
/**
* This routine parses a parameter declaration
*
* @throws BacktrackException
* request a backtrack
*/
protected ICPPASTParameterDeclaration parameterDeclaration() throws BacktrackException, EndOfFileException {
final int startOffset= LA(1).getOffset();
List<IASTAttributeSpecifier> attributes = attributeSpecifierSeq();
if (LT(1) == IToken.tLBRACKET && supportParameterInfoBlock) {
skipBrackets(IToken.tLBRACKET, IToken.tRBRACKET, 0);
}
IASTDeclSpecifier declSpec= null;
IASTDeclarator declarator;
try {
Decl decl= declSpecifierSequence_initDeclarator(DeclarationOptions.PARAMETER, false);
declSpec= decl.fDeclSpec1;
declarator= decl.fDtor1;
} catch (FoundAggregateInitializer lie) {
declSpec= lie.fDeclSpec;
declarator= addInitializer(lie, DeclarationOptions.PARAMETER);
}
addAttributeSpecifiers(attributes, declSpec);
final ICPPASTParameterDeclaration parm = getNodeFactory().newParameterDeclaration(declSpec, declarator);
final int endOffset = figureEndOffset(declSpec, declarator);
setRange(parm, startOffset, endOffset);
return parm;
}
private final static int INLINE= 0x1, CONST= 0x2, CONSTEXPR= 0x4, RESTRICT= 0x8, VOLATILE= 0x10,
SHORT= 0x20, UNSIGNED= 0x40, SIGNED= 0x80, COMPLEX= 0x100, IMAGINARY= 0x200,
VIRTUAL= 0x400, EXPLICIT= 0x800, FRIEND= 0x1000, THREAD_LOCAL= 0x2000;
private static final int FORBID_IN_EMPTY_DECLSPEC =
CONST | RESTRICT | VOLATILE | SHORT | UNSIGNED | SIGNED | COMPLEX | IMAGINARY | THREAD_LOCAL;
/**
* This function parses a declaration specifier sequence, as according to
* the ANSI C++ specification.
* declSpecifier :
* "register" | "static" | "extern" | "mutable" |
* "inline" | "virtual" | "explicit" |
* "typedef" | "friend" | "constexpr" |
* "const" | "volatile" |
* "short" | "long" | "signed" | "unsigned" | "int" |
* "char" | "wchar_t" | "bool" | "float" | "double" | "void" |
* "auto" |
* ("typename")? name |
* { "class" | "struct" | "union" } classSpecifier |
* {"enum"} enumSpecifier
*/
@Override
protected Decl declSpecifierSeq(final DeclarationOptions option, ITemplateIdStrategy strat)
throws BacktrackException, EndOfFileException {
return declSpecifierSeq(option, false, strat);
}
private ICPPASTDeclSpecifier simpleTypeSpecifier() throws BacktrackException, EndOfFileException {
Decl d= declSpecifierSeq(null, true, null);
return (ICPPASTDeclSpecifier) d.fDeclSpec1;
}
private ICPPASTDeclSpecifier simpleTypeSpecifierSequence() throws BacktrackException, EndOfFileException {
Decl d= declSpecifierSeq(null, false, null);
return (ICPPASTDeclSpecifier) d.fDeclSpec1;
}
private Decl declSpecifierSeq(final DeclarationOptions option, final boolean single,
ITemplateIdStrategy strat) throws BacktrackException, EndOfFileException {
int storageClass = IASTDeclSpecifier.sc_unspecified;
int simpleType = IASTSimpleDeclSpecifier.t_unspecified;
int options= 0;
int isLong= 0;
IToken returnToken= null;
ICPPASTDeclSpecifier result= null;
ICPPASTDeclSpecifier altResult= null;
List<IASTAttributeSpecifier> attributes = null;
try {
IASTName identifier= null;
IASTExpression typeofExpression= null;
IASTProblem problem= null;
boolean isTypename = false;
boolean encounteredRawType= false;
boolean encounteredTypename= false;
final int offset = LA(1).getOffset();
int endOffset= offset;
declSpecifiers: for (;;) {
final int lt1= LTcatchEOF(1);
switch (lt1) {
case 0: // encountered eof
break declSpecifiers;
// storage class specifiers
case IToken.t_auto:
if (supportAutoTypeSpecifier) {
if (encounteredTypename)
break declSpecifiers;
simpleType = IASTSimpleDeclSpecifier.t_auto;
encounteredRawType= true;
endOffset= consume().getEndOffset();
break;
} else {
storageClass = IASTDeclSpecifier.sc_auto;
endOffset= consume().getEndOffset();
}
break;
case IToken.t_register:
storageClass = IASTDeclSpecifier.sc_register;
endOffset= consume().getEndOffset();
break;
case IToken.t_static:
storageClass = IASTDeclSpecifier.sc_static;
endOffset= consume().getEndOffset();
break;
case IToken.t_extern:
storageClass = IASTDeclSpecifier.sc_extern;
endOffset= consume().getEndOffset();
break;
case IToken.t_thread_local:
options |= THREAD_LOCAL; // thread_local may appear with static or extern
endOffset= consume().getEndOffset();
break;
case IToken.t_mutable:
storageClass = IASTDeclSpecifier.sc_mutable;
endOffset= consume().getEndOffset();
break;
case IToken.t_typedef:
storageClass = IASTDeclSpecifier.sc_typedef;
endOffset= consume().getEndOffset();
break;
// function specifiers
case IToken.t_inline:
options |= INLINE;
endOffset= consume().getEndOffset();
break;
case IToken.t_virtual:
options |= VIRTUAL;
endOffset= consume().getEndOffset();
break;
case IToken.t_explicit:
options |= EXPLICIT;
endOffset= consume().getEndOffset();
break;
case IToken.t_friend:
options |= FRIEND;
endOffset= consume().getEndOffset();
break;
case IToken.t_constexpr:
options |= CONSTEXPR;
endOffset= consume().getEndOffset();
break;
// type specifier
case IToken.t_const:
options |= CONST;
endOffset= consume().getEndOffset();
break;
case IToken.t_volatile:
options |= VOLATILE;
endOffset= consume().getEndOffset();
break;
case IToken.t_restrict:
options |= RESTRICT;
endOffset= consume().getEndOffset();
break;
case IToken.t_signed:
if (encounteredTypename)
break declSpecifiers;
options |= SIGNED;
encounteredRawType= true;
endOffset= consume().getEndOffset();
break;
case IToken.t_unsigned:
if (encounteredTypename)
break declSpecifiers;
options |= UNSIGNED;
encounteredRawType= true;
endOffset= consume().getEndOffset();
break;
case IToken.t_short:
if (encounteredTypename)
break declSpecifiers;
options |= SHORT;
encounteredRawType= true;
endOffset= consume().getEndOffset();
break;
case IToken.t_long:
if (encounteredTypename)
break declSpecifiers;
isLong++;
encounteredRawType= true;
endOffset= consume().getEndOffset();
break;
case IToken.t__Complex:
if (encounteredTypename)
break declSpecifiers;
options |= COMPLEX;
endOffset= consume().getEndOffset();
break;
case IToken.t__Imaginary:
if (encounteredTypename)
break declSpecifiers;
options |= IMAGINARY;
endOffset= consume().getEndOffset();
break;
case IToken.t_char:
if (encounteredTypename)
break declSpecifiers;
simpleType = IASTSimpleDeclSpecifier.t_char;
encounteredRawType= true;
endOffset= consume().getEndOffset();
break;
case IToken.t_wchar_t:
if (encounteredTypename)
break declSpecifiers;
simpleType = IASTSimpleDeclSpecifier.t_wchar_t;
encounteredRawType= true;
endOffset= consume().getEndOffset();
break;
case IToken.t_char16_t:
if (encounteredTypename)
break declSpecifiers;
simpleType = IASTSimpleDeclSpecifier.t_char16_t;
encounteredRawType= true;
endOffset= consume().getEndOffset();
break;
case IToken.t_char32_t:
if (encounteredTypename)
break declSpecifiers;
simpleType = IASTSimpleDeclSpecifier.t_char32_t;
encounteredRawType= true;
endOffset= consume().getEndOffset();
break;
case IToken.t_bool:
if (encounteredTypename)
break declSpecifiers;
simpleType = IASTSimpleDeclSpecifier.t_bool;
encounteredRawType= true;
endOffset= consume().getEndOffset();
break;
case IToken.t_int:
if (encounteredTypename)
break declSpecifiers;
simpleType = IASTSimpleDeclSpecifier.t_int;
encounteredRawType= true;
endOffset= consume().getEndOffset();
break;
case IGCCToken.t__int128:
if (encounteredTypename)
break declSpecifiers;
simpleType = IASTSimpleDeclSpecifier.t_int128;
encounteredRawType= true;
endOffset= consume().getEndOffset();
break;
case IToken.t_float:
if (encounteredTypename)
break declSpecifiers;
simpleType = IASTSimpleDeclSpecifier.t_float;
encounteredRawType= true;
endOffset= consume().getEndOffset();
break;
case IToken.t_double:
if (encounteredTypename)
break declSpecifiers;
simpleType = IASTSimpleDeclSpecifier.t_double;
encounteredRawType= true;
endOffset= consume().getEndOffset();
break;
case IGCCToken.t__float128:
if (encounteredTypename)
break declSpecifiers;
simpleType = IASTSimpleDeclSpecifier.t_float128;
encounteredRawType= true;
endOffset= consume().getEndOffset();
break;
case IGCCToken.t_decimal32:
if (encounteredTypename)
break declSpecifiers;
simpleType = IASTSimpleDeclSpecifier.t_decimal32;
encounteredRawType= true;
endOffset= consume().getEndOffset();
break;
case IGCCToken.t_decimal64:
if (encounteredTypename)
break declSpecifiers;
simpleType = IASTSimpleDeclSpecifier.t_decimal64;
encounteredRawType= true;
endOffset= consume().getEndOffset();
break;
case IGCCToken.t_decimal128:
if (encounteredTypename)
break declSpecifiers;
simpleType = IASTSimpleDeclSpecifier.t_decimal128;
encounteredRawType= true;
endOffset= consume().getEndOffset();
break;
case IToken.t_void:
if (encounteredTypename)
break declSpecifiers;
simpleType = IASTSimpleDeclSpecifier.t_void;
encounteredRawType= true;
endOffset= consume().getEndOffset();
break;
case IToken.t_typename:
if (encounteredTypename || encounteredRawType)
break declSpecifiers;
consume();
identifier= qualifiedName();
endOffset= calculateEndOffset(identifier);
isTypename = true;
encounteredTypename= true;
break;
case IToken.tBITCOMPLEMENT:
case IToken.tCOLONCOLON:
case IToken.tIDENTIFIER:
case IToken.tCOMPLETION:
if (encounteredRawType || encounteredTypename)
break declSpecifiers;
if (option != null && option.fAllowEmptySpecifier && LT(1) != IToken.tCOMPLETION) {
if ((options & FORBID_IN_EMPTY_DECLSPEC) == 0 && storageClass == IASTDeclSpecifier.sc_unspecified) {
altResult= buildSimpleDeclSpec(storageClass, simpleType, options, isLong, typeofExpression, offset, endOffset);
returnToken= mark();
}
}
identifier= qualifiedName(CastExprCtx.eNotInBExpr, strat);
if (identifier.getLookupKey().length == 0 && LT(1) != IToken.tEOC)
throwBacktrack(LA(1));
endOffset= calculateEndOffset(identifier);
encounteredTypename= true;
break;
case IToken.t_class:
case IToken.t_struct:
case IToken.t_union:
if (encounteredTypename || encounteredRawType)
break declSpecifiers;
try {
result= classSpecifier();
} catch (BacktrackException bt) {
result= elaboratedTypeSpecifier();
}
endOffset= calculateEndOffset(result);
encounteredTypename= true;
break;
case IToken.t_enum:
if (encounteredTypename || encounteredRawType)
break declSpecifiers;
try {
result= enumDeclaration(option != null && option.fAllowOpaqueEnum);
} catch (BacktrackException bt) {
if (bt.getNodeBeforeProblem() instanceof ICPPASTDeclSpecifier) {
result= (ICPPASTDeclSpecifier) bt.getNodeBeforeProblem();
problem= bt.getProblem();
break declSpecifiers;
}
throw bt;
}
endOffset= calculateEndOffset(result);
encounteredTypename= true;
break;
case IGCCToken.t__attribute__: // if __attribute__ is after the declSpec
if (!supportAttributeSpecifiers)
throwBacktrack(LA(1));
attributes = CollectionUtils.merge(attributes, __attribute_decl_seq(true, false));
break;
case IGCCToken.t__declspec: // __declspec precedes the identifier
if (identifier != null || !supportDeclspecSpecifiers)
throwBacktrack(LA(1));
__attribute_decl_seq(false, true);
break;
case IGCCToken.t_typeof:
if (encounteredRawType || encounteredTypename)
throwBacktrack(LA(1));
simpleType= IASTSimpleDeclSpecifier.t_typeof;
consume(IGCCToken.t_typeof);
typeofExpression= parseTypeidInParenthesisOrUnaryExpression(false, LA(1).getOffset(),
IASTTypeIdExpression.op_typeof, -1, CastExprCtx.eNotInBExpr, null);
encounteredTypename= true;
endOffset= calculateEndOffset(typeofExpression);
break;
case IToken.t_decltype:
if (encounteredRawType || encounteredTypename)
throwBacktrack(LA(1));
// A decltype-specifier could be the first element
// in a qualified name, in which case we'll have
// a named-type-specifier.
IToken marked = mark();
try {
identifier = qualifiedName();
endOffset = calculateEndOffset(identifier);
encounteredTypename = true;
break;
} catch (BacktrackException e) {
backup(marked);
}
// Otherwise we have a simple-decl-specifier.
consume(IToken.t_decltype);
consume(IToken.tLPAREN);
if (LT(1) == IToken.t_auto) {
simpleType= IASTSimpleDeclSpecifier.t_decltype_auto;
consume(IToken.t_auto);
} else {
simpleType= IASTSimpleDeclSpecifier.t_decltype;
typeofExpression= expression();
}
endOffset= consumeOrEOC(IToken.tRPAREN).getEndOffset();
encounteredTypename= true;
break;
case IGCCToken.tTT_underlying_type:
if (encounteredRawType || encounteredTypename)
throwBacktrack(LA(1));
result= typeTransformationSpecifier(DeclarationOptions.TYPEID);
endOffset= calculateEndOffset(result);
encounteredTypename= true;
break;
default:
if (lt1 >= IExtensionToken.t__otherDeclSpecModifierFirst && lt1 <= IExtensionToken.t__otherDeclSpecModifierLast) {
handleOtherDeclSpecModifier();
endOffset= LA(1).getOffset();
break;
}
break declSpecifiers;
}
if (encounteredRawType && encounteredTypename)
throwBacktrack(LA(1));
if (single)
break declSpecifiers;
}
// check for empty specification
if (!encounteredRawType && !encounteredTypename && LT(1) != IToken.tEOC
&& (option == null || !option.fAllowEmptySpecifier)) {
throwBacktrack(LA(1));
}
attributes = CollectionUtils.merge(attributes, attributeSpecifierSeq());
if (result != null) {
configureDeclSpec(result, storageClass, options);
// cannot store restrict in the cpp-nodes.
// if ((options & RESTRICT) != 0) {
// }
setRange(result, offset, endOffset);
if (problem != null) {
throwBacktrack(problem, result);
}
} else if (identifier != null) {
result= buildNamedTypeSpecifier(identifier, isTypename, storageClass, options, offset, endOffset);
} else {
result= buildSimpleDeclSpec(storageClass, simpleType, options, isLong, typeofExpression, offset, endOffset);
}
addAttributeSpecifiers(attributes, result);
} catch (BacktrackException e) {
if (returnToken != null) {
backup(returnToken);
result= altResult;
altResult= null;
returnToken= null;
} else {
throw e;
}
}
Decl target= new Decl();
target.fDeclSpec1= result;
target.fDeclSpec2= altResult;
target.fDtorToken1= returnToken;
return target;
}
private ICPPASTNamedTypeSpecifier buildNamedTypeSpecifier(IASTName name, boolean isTypename,
int storageClass, int options, int offset, int endOffset) {
ICPPASTNamedTypeSpecifier declSpec = getNodeFactory().newTypedefNameSpecifier(name);
declSpec.setIsTypename(isTypename);
configureDeclSpec(declSpec, storageClass, options);
((ASTNode) declSpec).setOffsetAndLength(offset, endOffset - offset);
return declSpec;
}
private ICPPASTSimpleDeclSpecifier buildSimpleDeclSpec(int storageClass, int simpleType,
int options, int isLong, IASTExpression typeofExpression, int offset, int endOffset) {
ICPPASTSimpleDeclSpecifier declSpec= getNodeFactory().newSimpleDeclSpecifier();
configureDeclSpec(declSpec, storageClass, options);
declSpec.setType(simpleType);
declSpec.setLong(isLong == 1);
declSpec.setLongLong(isLong > 1);
declSpec.setShort((options & SHORT) != 0);
declSpec.setUnsigned((options & UNSIGNED) != 0);
declSpec.setSigned((options & SIGNED) != 0);
declSpec.setComplex((options & COMPLEX) != 0);
declSpec.setImaginary((options & IMAGINARY) != 0);
declSpec.setDeclTypeExpression(typeofExpression);
((ASTNode) declSpec).setOffsetAndLength(offset, endOffset-offset);
return declSpec;
}
private void configureDeclSpec(ICPPASTDeclSpecifier declSpec, int storageClass, int options) {
declSpec.setStorageClass(storageClass);
declSpec.setConst((options & CONST) != 0);
declSpec.setConstexpr((options & CONSTEXPR) != 0);
declSpec.setVolatile((options & VOLATILE) != 0);
declSpec.setInline((options & INLINE) != 0);
declSpec.setFriend((options & FRIEND) != 0);
declSpec.setVirtual((options & VIRTUAL) != 0);
declSpec.setExplicit((options & EXPLICIT) != 0);
declSpec.setRestrict((options & RESTRICT) != 0);
declSpec.setThreadLocal((options & THREAD_LOCAL) != 0);
}
private ICPPASTDeclSpecifier enumDeclaration(boolean allowOpaque) throws BacktrackException, EndOfFileException {
IToken mark= mark();
final int offset= consume(IToken.t_enum).getOffset();
int endOffset= 0;
boolean isScoped= false;
IASTName name= null;
ICPPASTDeclSpecifier baseType= null;
List<IASTAttributeSpecifier> attributes = null;
try {
int lt1= LT(1);
if (lt1 == IToken.t_class || lt1 == IToken.t_struct) {
isScoped= true;
consume();
}
// if __attribute__ or __declspec occurs after struct/union/class and before the identifier
attributes = __attribute_decl_seq(supportAttributeSpecifiers, supportDeclspecSpecifiers);
attributes = CollectionUtils.merge(attributes, attributeSpecifierSeq());
if (isScoped || LT(1) == IToken.tIDENTIFIER) {
// A qualified-name can appear here if an enumeration declared at class scope is
// being defined out of line.
name= qualifiedName();
endOffset= calculateEndOffset(name);
}
if (LT(1) == IToken.tCOLON) {
consume();
baseType= simpleTypeSpecifierSequence();
endOffset= calculateEndOffset(baseType);
}
} catch (BacktrackException e) {
backup(mark);
return elaboratedTypeSpecifier();
}
final int lt1= LT(1);
final boolean isDef= lt1 == IToken.tLBRACE || (lt1 == IToken.tEOC && baseType != null);
final boolean isOpaque= !isDef && allowOpaque && lt1 == IToken.tSEMI;
if (!isDef && !isOpaque) {
backup(mark);
return elaboratedTypeSpecifier();
}
mark= null;
if (isOpaque && !isScoped && baseType == null)
throwBacktrack(LA(1));
if (name == null) {
if (isOpaque)
throwBacktrack(LA(1));
name= getNodeFactory().newName();
}
final ICPPASTEnumerationSpecifier result= getNodeFactory().newEnumerationSpecifier(isScoped, name, baseType);
result.setIsOpaque(isOpaque);
if (lt1 == IToken.tLBRACE) {
endOffset= enumBody(result);
}
assert endOffset != 0;
addAttributeSpecifiers(attributes, result);
return setRange(result, offset, endOffset);
}
/**
* Parse an elaborated type specifier.
*
* @throws BacktrackException
* request a backtrack
*/
protected ICPPASTElaboratedTypeSpecifier elaboratedTypeSpecifier() throws BacktrackException, EndOfFileException {
// this is an elaborated class specifier
final int lt1= LT(1);
int eck = 0;
switch (lt1) {
case IToken.t_class:
eck = ICPPASTElaboratedTypeSpecifier.k_class;
break;
case IToken.t_struct:
eck = IASTElaboratedTypeSpecifier.k_struct;
break;
case IToken.t_union:
eck = IASTElaboratedTypeSpecifier.k_union;
break;
case IToken.t_enum:
eck = IASTElaboratedTypeSpecifier.k_enum;
break;
default:
throwBacktrack(LA(1));
}
final int offset= consume().getOffset();
// if __attribute__ or __declspec occurs after struct/union/class and before the identifier
List<IASTAttributeSpecifier> attributes = __attribute_decl_seq(supportAttributeSpecifiers, supportDeclspecSpecifiers);
attributes = CollectionUtils.merge(attributes, attributeSpecifierSeq());
IASTName name = qualifiedName();
ICPPASTElaboratedTypeSpecifier elaboratedTypeSpecifier = getNodeFactory().newElaboratedTypeSpecifier(eck, name);
addAttributeSpecifiers(attributes, elaboratedTypeSpecifier);
return setRange(elaboratedTypeSpecifier, offset, calculateEndOffset(name));
}
/**
* Parse a type transformation specifier.
*/
protected ICPPASTTypeTransformationSpecifier typeTransformationSpecifier(DeclarationOptions options)
throws BacktrackException, EndOfFileException {
final int offset = consume(IGCCToken.tTT_underlying_type).getOffset();
consume(IToken.tLPAREN);
ICPPASTTypeId operand = typeId(options);
final int endOffset = consumeOrEOC(IToken.tRPAREN).getEndOffset();
return setRange(getNodeFactory().newTypeTransformationSpecifier(ICPPUnaryTypeTransformation.Operator.underlying_type, operand), offset, endOffset);
}
@Override
protected IASTDeclarator initDeclarator(IASTDeclSpecifier declspec, DeclarationOptions option)
throws EndOfFileException, BacktrackException, FoundAggregateInitializer {
final IToken mark= mark();
IASTDeclarator dtor1= null;
IToken end1= null;
IASTDeclarator dtor2= null;
BacktrackException bt= null;
try {
dtor1= initDeclarator(DtorStrategy.PREFER_FUNCTION, declspec, option);
verifyDtor(declspec, dtor1, option);
int lt1= LTcatchEOF(1);
switch (lt1) {
case 0:
return dtor1;
case IToken.tLBRACE:
if (option.fCanBeFollowedByBrace
|| ASTQueries.findTypeRelevantDeclarator(dtor1) instanceof IASTFunctionDeclarator)
return dtor1;
dtor1= null;
throwBacktrack(LA(1));
break;
case IToken.tCOLON:
// a colon can be used after a type-id in a conditional expression
if (option != DeclarationOptions.CPP_MEMBER && option != DeclarationOptions.GLOBAL)
break;
//$FALL-THROUGH$
case IToken.t_throw: case IToken.t_try:
case IToken.t_const: case IToken.t_volatile:
case IToken.tASSIGN: // defaulted or deleted function definition
if (option == DeclarationOptions.TYPEID_TRAILING_RETURN_TYPE ||
ASTQueries.findTypeRelevantDeclarator(dtor1) instanceof IASTFunctionDeclarator) {
return dtor1;
} else {
dtor1= null;
throwBacktrack(LA(1));
}
}
if (!(dtor1 instanceof IASTFunctionDeclarator))
return dtor1;
end1= LA(1);
} catch (BacktrackException e) {
bt= e;
}
if (!option.fAllowCtorStyleInitializer || !canHaveConstructorInitializer(declspec, dtor1)) {
if (bt != null)
throw bt;
return dtor1;
}
backup(mark);
try {
dtor2= initDeclarator(DtorStrategy.PREFER_NESTED, declspec, option);
if (dtor1 == null) {
return dtor2;
}
} catch (BacktrackException e) {
if (dtor1 != null) {
backup(end1);
return dtor1;
}
throw e;
}
// we have an ambiguity
if (end1 != null && LA(1).getEndOffset() != end1.getEndOffset()) {
backup(end1);
return dtor1;
}
if (functionBodyCount != 0) {
// prefer the variable prototype:
IASTDeclarator h= dtor1; dtor1= dtor2; dtor2= h;
}
CPPASTAmbiguousDeclarator dtor= new CPPASTAmbiguousDeclarator(dtor1, dtor2);
dtor.setOffsetAndLength((ASTNode) dtor1);
return dtor;
}
/**
* Tries to detect illegal versions of declarations
*/
private void verifyDtor(IASTDeclSpecifier declspec, IASTDeclarator dtor, DeclarationOptions opt) throws BacktrackException {
if (CPPVisitor.doesNotSpecifyType(declspec)) {
if (ASTQueries.findTypeRelevantDeclarator(dtor) instanceof IASTFunctionDeclarator) {
boolean isQualified= false;
IASTName name= ASTQueries.findInnermostDeclarator(dtor).getName();
if (name instanceof ICPPASTQualifiedName) {
isQualified= true;
name= name.getLastName();
}
if (name instanceof ICPPASTTemplateId)
name= ((ICPPASTTemplateId) name).getTemplateName();
// accept conversion operator
if (name instanceof ICPPASTConversionName)
return;
if (opt == DeclarationOptions.CPP_MEMBER) {
// Accept constructor and destructor within class body
final char[] nchars= name.getLookupKey();
if (nchars.length > 0 && currentClassName != null) {
final int start= nchars[0] == '~' ? 1 : 0;
if (CharArrayUtils.equals(nchars, start, nchars.length-start, currentClassName))
return;
}
// Accept constructors and destructors of other classes as friends
if (declspec instanceof ICPPASTDeclSpecifier && ((ICPPASTDeclSpecifier) declspec).isFriend())
return;
} else if (isQualified) {
// Accept qualified constructor or destructor outside of class body
return;
}
}
ASTNode node= (ASTNode) dtor;
throwBacktrack(node.getOffset(), node.getLength());
}
}
private boolean canHaveConstructorInitializer(IASTDeclSpecifier declspec, IASTDeclarator dtor) {
if (declspec instanceof ICPPASTDeclSpecifier) {
ICPPASTDeclSpecifier cppspec= (ICPPASTDeclSpecifier) declspec;
if (cppspec.isFriend()) {
return false;
}
if (cppspec.getStorageClass() == IASTDeclSpecifier.sc_typedef) {
return false;
}
}
if (declspec instanceof ICPPASTSimpleDeclSpecifier) {
ICPPASTSimpleDeclSpecifier sspec= (ICPPASTSimpleDeclSpecifier) declspec;
if (CPPVisitor.doesNotSpecifyType(declspec)) {
return false;
}
if (sspec.getType() == IASTSimpleDeclSpecifier.t_void && dtor != null &&
dtor.getPointerOperators().length == 0 && dtor.getNestedDeclarator() == null) {
return false;
}
}
if (dtor != null) {
IASTName name = ASTQueries.findInnermostDeclarator(dtor).getName().getLastName();
if (name instanceof ICPPASTTemplateId) {
name= ((ICPPASTTemplateId) name).getTemplateName();
}
if (name instanceof ICPPASTOperatorName || name instanceof ICPPASTConversionName)
return false;
}
return true;
}
/**
* Parses the initDeclarator construct of the ANSI C++ spec. initDeclarator :
* declarator ("=" initializerClause | "(" expressionList ")")?
*
* @return declarator that this parsing produced.
* @throws BacktrackException request a backtrack
* @throws FoundAggregateInitializer
*/
private IASTDeclarator initDeclarator(DtorStrategy strategy, IASTDeclSpecifier declspec, DeclarationOptions option)
throws EndOfFileException, BacktrackException, FoundAggregateInitializer {
final IASTDeclarator dtor= declarator(strategy, option);
if (option.fAllowInitializer) {
final IASTDeclarator typeRelevantDtor = ASTQueries.findTypeRelevantDeclarator(dtor);
if (option != DeclarationOptions.PARAMETER && typeRelevantDtor instanceof IASTFunctionDeclarator) {
// Function declarations don't have initializers.
// For member functions we need to consider virtual specifiers and pure-virtual syntax.
if (option == DeclarationOptions.CPP_MEMBER) {
optionalVirtSpecifierSeq((ICPPASTFunctionDeclarator) typeRelevantDtor);
List<IASTAttributeSpecifier> attributeSpecifiers = __attribute_decl_seq(supportAttributeSpecifiers, false);
addAttributeSpecifiers(attributeSpecifiers, dtor);
int lt1 = LTcatchEOF(1);
if (lt1 == IToken.tASSIGN && LTcatchEOF(2) == IToken.tINTEGER) {
consume();
IToken t = consume();
char[] image = t.getCharImage();
if (image.length != 1 || image[0] != '0') {
throwBacktrack(t);
}
((ICPPASTFunctionDeclarator) typeRelevantDtor).setPureVirtual(true);
adjustEndOffset(dtor, t.getEndOffset()); // We can only adjust the offset of the outermost dtor.
}
}
} else {
if (LTcatchEOF(1) == IToken.tASSIGN && LTcatchEOF(2) == IToken.tLBRACE)
throw new FoundAggregateInitializer(declspec, dtor);
IASTInitializer initializer= optionalInitializer(dtor, option);
if (initializer != null) {
if (initializer instanceof IASTInitializerList
&& ((IASTInitializerList) initializer).getSize() == 0) {
// Avoid ambiguity between constructor with body and variable with initializer
switch (LTcatchEOF(1)) {
case IToken.tCOMMA:
case IToken.tSEMI:
case IToken.tRPAREN:
break;
case 0:
throw backtrack;
default:
throwBacktrack(LA(1));
}
}
dtor.setInitializer(initializer);
adjustLength(dtor, initializer);
}
}
}
return dtor;
}
/**
* virt-specifier-seq
* virt-specifier
* virt-specifier-seq virt-specifier
*
* virt-specifier:
* override
* final
* @throws EndOfFileException
* @throws BacktrackException
*/
private void optionalVirtSpecifierSeq(ICPPASTFunctionDeclarator typeRelevantDtor)
throws EndOfFileException, BacktrackException {
while (true) {
IToken token = LAcatchEOF(1);
ContextSensitiveTokenType contextSensitiveType = getContextSensitiveType(token);
if (contextSensitiveType == null) {
break;
}
consume();
SpecifierKind specifierKind;
if (contextSensitiveType == ContextSensitiveTokenType.OVERRIDE) {
specifierKind = ICPPASTVirtSpecifier.SpecifierKind.Override;
} else if (contextSensitiveType == ContextSensitiveTokenType.FINAL) {
specifierKind = ICPPASTVirtSpecifier.SpecifierKind.Final;
} else {
break;
}
ICPPASTVirtSpecifier spec = getNodeFactory().newVirtSpecifier(specifierKind);
int endOffset = token.getOffset() + token.getLength();
setRange(spec, token.getOffset(), endOffset);
typeRelevantDtor.addVirtSpecifier(spec);
adjustEndOffset(typeRelevantDtor, endOffset);
}
}
private IASTEqualsInitializer equalsInitalizerClause(boolean allowSkipping)
throws EndOfFileException, BacktrackException {
// Check for deleted or defaulted function syntax.
final int lt2 = LTcatchEOF(2);
if (lt2 == IToken.t_delete || lt2 == IToken.t_default) {
return null;
}
int offset = consume(IToken.tASSIGN).getOffset();
IASTInitializerClause initClause = initClause(allowSkipping);
IASTEqualsInitializer initExpr = getNodeFactory().newEqualsInitializer(initClause);
return setRange(initExpr, offset, calculateEndOffset(initClause));
}
/**
* initializer:
* brace-or-equal-initializer
* (expression-list)
*
* brace-or-equal-initializer:
* = initializer-clause
* braced-init-list
*/
@Override
protected IASTInitializer optionalInitializer(IASTDeclarator dtor, DeclarationOptions option)
throws EndOfFileException, BacktrackException {
final int lt1= LTcatchEOF(1);
// = initializer-clause
if (lt1 == IToken.tASSIGN) {
return equalsInitalizerClause(LTcatchEOF(2) == IToken.tLBRACE && specifiesArray(dtor));
}
// braced-init-list
if (option.fAllowBracedInitializer && lt1 == IToken.tLBRACE) {
return bracedInitList(false, false);
}
// (expression-list)
if (option.fAllowCtorStyleInitializer && lt1 == IToken.tLPAREN) {
return ctorStyleInitializer(false);
}
return null;
}
private boolean specifiesArray(IASTDeclarator dtor) {
dtor = ASTQueries.findTypeRelevantDeclarator(dtor);
return dtor instanceof IASTArrayDeclarator;
}
private IASTInitializer bracedOrCtorStyleInitializer() throws EndOfFileException, BacktrackException {
final int lt1= LT(1);
if (lt1 == IToken.tLPAREN) {
return ctorStyleInitializer(true);
}
return bracedInitList(false, true);
}
/**
* (expression-list_opt)
*/
private ICPPASTConstructorInitializer ctorStyleInitializer(boolean optionalExpressionList)
throws EndOfFileException, BacktrackException {
IASTInitializerClause[] initArray;
int offset = consume(IToken.tLPAREN).getOffset();
// ()
if (optionalExpressionList && LT(1) == IToken.tRPAREN) {
initArray= IASTExpression.EMPTY_EXPRESSION_ARRAY;
} else {
final List<ICPPASTInitializerClause> exprList = expressionList();
initArray = exprList.toArray(new IASTInitializerClause[exprList.size()]);
}
int endOffset = consumeOrEOC(IToken.tRPAREN).getEndOffset();
return setRange(getNodeFactory().newConstructorInitializer(initArray), offset, endOffset);
}
private List<ICPPASTInitializerClause> expressionList() throws EndOfFileException, BacktrackException {
return initializerList(false, false);
}
/**
* initializer-clause:
* assignment-expression
* braced-init-list
*/
private ICPPASTInitializerClause initClause(boolean allowSkipping) throws EndOfFileException,
BacktrackException {
// braced-init-list
if (LT(1) == IToken.tLBRACE) {
return bracedInitList(allowSkipping, true);
}
// assignment expression
TemplateIdStrategy strat= fTemplateParameterListStrategy;
final BinaryExprCtx ctx= strat != null ? BinaryExprCtx.eInTemplateID : BinaryExprCtx.eNotInTemplateID;
return expression(ExprKind.eAssignment, ctx, null, strat);
}
/**
* braced-init-list:
* { initializer-list ,opt }
* { }
*/
private ICPPASTInitializerList bracedInitList(boolean allowSkipping, boolean allowDesignators)
throws EndOfFileException, BacktrackException {
int offset = consume(IToken.tLBRACE).getOffset();
// { }
if (LT(1) == IToken.tRBRACE) {
return setRange(getNodeFactory().newInitializerList(), offset, consume().getEndOffset());
}
// { initializer-list ,opt }
List<ICPPASTInitializerClause> initList= initializerList(allowSkipping, allowDesignators);
if (LT(1) == IToken.tCOMMA)
consume();
int endOffset= consumeOrEOC(IToken.tRBRACE).getEndOffset();
ICPPASTInitializerList result = getNodeFactory().newInitializerList();
for (IASTInitializerClause init : initList) {
result.addClause(init);
}
return setRange(result, offset, endOffset);
}
/**
* initializerList:
* initializer-clause ...opt
* initializer-list , initializer-clause ...opt
*/
private List<ICPPASTInitializerClause> initializerList(boolean allowSkipping, boolean allowDesignators)
throws EndOfFileException, BacktrackException {
List<ICPPASTInitializerClause> result= new ArrayList<>();
// List of initializer clauses
loop: while (true) {
List<ICPPASTDesignator> designators = null;
IToken mark = mark();
if (allowDesignators) {
designators= designatorList();
}
if (designators != null) {
try {
ICPPASTDesignatedInitializer desigInitializer = getNodeFactory().newDesignatedInitializer(null);
setRange(desigInitializer, designators.get(0));
for (ICPPASTDesignator d : designators) {
desigInitializer.addDesignator(d);
}
if (LT(1) != IToken.tEOC) {
// GNU extension: the assign operator is optional.
if (LT(1) == IToken.tASSIGN)
consume(IToken.tASSIGN);
ICPPASTInitializerClause clause= initClause(false);
desigInitializer.setOperand(clause);
adjustLength(desigInitializer, clause);
}
result.add(desigInitializer);
} catch (BacktrackException e) {
backup(mark);
designators = null; // Retry without designators.
}
}
if (designators == null) {
// Clause may be null, add to initializer anyways, so that the size can be computed.
ICPPASTInitializerClause clause = initClause(allowSkipping);
if (allowSkipping && result.size() >= maximumTrivialExpressionsInAggregateInitializers
&& !ASTQueries.canContainName(clause)) {
translationUnit.setHasNodesOmitted(true);
clause= null;
}
if (LT(1) == IToken.tELLIPSIS) {
final int endOffset = consume(IToken.tELLIPSIS).getEndOffset();
if (clause instanceof ICPPASTPackExpandable) {
// Mark initializer lists directly as pack expansions
((ICPPASTPackExpandable) clause).setIsPackExpansion(true);
adjustEndOffset(clause, endOffset);
} else if (clause instanceof IASTExpression) {
// Wrap pack expanded assignment expressions
ICPPASTExpression packExpansion= getNodeFactory().newPackExpansionExpression((IASTExpression) clause);
clause= setRange(packExpansion, clause, endOffset);
}
}
result.add(clause);
}
if (LT(1) != IToken.tCOMMA)
break;
switch (LT(2)) {
case IToken.tRBRACE:
case IToken.tRPAREN:
case IToken.tEOC:
break loop;
}
consume(IToken.tCOMMA);
}
return result;
}
private List<ICPPASTDesignator> designatorList() throws EndOfFileException, BacktrackException {
IToken mark= mark();
try {
final int lt1= LT(1);
if (lt1 == IToken.tDOT || lt1 == IToken.tLBRACKET) {
List<ICPPASTDesignator> designatorList= null;
while (true) {
switch (LT(1)) {
case IToken.tDOT:
int offset = consume().getOffset();
IASTName n = identifier();
ICPPASTFieldDesignator fieldDesignator = getNodeFactory().newFieldDesignator(n);
setRange(fieldDesignator, offset, calculateEndOffset(n));
if (designatorList == null)
designatorList = new ArrayList<>(DEFAULT_DESIGNATOR_LIST_SIZE);
designatorList.add(fieldDesignator);
break;
case IToken.tLBRACKET:
offset = consume().getOffset();
ICPPASTExpression constantExpression = expression();
if (supportGCCStyleDesignators && LT(1) == IToken.tELLIPSIS) {
consume(IToken.tELLIPSIS);
ICPPASTExpression constantExpression2 = expression();
int lastOffset = consume(IToken.tRBRACKET).getEndOffset();
IGPPASTArrayRangeDesignator designator = getNodeFactory().newArrayRangeDesignatorGPP(constantExpression, constantExpression2);
setRange(designator, offset, lastOffset);
if (designatorList == null)
designatorList = new ArrayList<>(DEFAULT_DESIGNATOR_LIST_SIZE);
designatorList.add(designator);
} else {
int lastOffset = consume(IToken.tRBRACKET).getEndOffset();
ICPPASTArrayDesignator designator = getNodeFactory().newArrayDesignator(constantExpression);
setRange(designator, offset, lastOffset);
if (designatorList == null)
designatorList = new ArrayList<>(DEFAULT_DESIGNATOR_LIST_SIZE);
designatorList.add(designator);
}
break;
default:
return designatorList;
}
}
}
// If reached identifier and it's not a designator then return empty designator list (bug 84176).
if (supportGCCStyleDesignators && lt1 == IToken.tIDENTIFIER && LT(2) == IToken.tCOLON) {
int offset= LA(1).getOffset();
IASTName n = identifier();
int lastOffset = consume(IToken.tCOLON).getEndOffset();
ICPPASTFieldDesignator designator = getNodeFactory().newFieldDesignator(n);
setRange(designator, offset, lastOffset);
return Collections.singletonList(designator);
}
} catch (BacktrackException bt) {
backup(mark);
}
return null;
}
@Override
protected ICPPASTTypeId typeId(DeclarationOptions option) throws EndOfFileException, BacktrackException {
return typeId(option, null);
}
protected ICPPASTTypeId typeId(DeclarationOptions option, ITemplateIdStrategy strat)
throws EndOfFileException, BacktrackException {
if (!canBeTypeSpecifier()) {
throwBacktrack(LA(1));
}
final int offset = LA().getOffset();
IASTDeclSpecifier declSpecifier = null;
IASTDeclarator declarator = null;
try {
Decl decl= declSpecifierSequence_initDeclarator(option, false, strat);
declSpecifier= decl.fDeclSpec1;
declarator= decl.fDtor1;
} catch (FoundAggregateInitializer lie) {
// type-ids have no initializers
throwBacktrack(lie.fDeclarator);
}
ICPPASTTypeId result = getNodeFactory().newTypeId(declSpecifier, declarator);
setRange(result, offset, figureEndOffset(declSpecifier, declarator));
return result;
}
/**
* Parse a declarator, as according to the ANSI C++ specification.
* declarator : (ptrOperator)* directDeclarator
* directDeclarator :
* declaratorId |
* directDeclarator "(" parameterDeclarationClause ")" (cvQualifier)* (exceptionSpecification)* |
* directDeclarator "[" (constantExpression)? "]" |
* "(" declarator")" |
* directDeclarator "(" parameterDeclarationClause ")" (oldKRParameterDeclaration)*
*
* declaratorId : name
* @return declarator that this parsing produced.
* @throws BacktrackException
* request a backtrack
*/
protected IASTDeclarator declarator(DtorStrategy strategy, DeclarationOptions option)
throws EndOfFileException, BacktrackException {
final int startingOffset = LA(1).getOffset();
int endOffset = startingOffset;
List<? extends IASTPointerOperator> pointerOps = consumePointerOperators();
if (pointerOps != null) {
endOffset = calculateEndOffset(pointerOps.get(pointerOps.size() - 1));
}
// Accept __attribute__ or __declspec between pointer operators and declarator.
List<IASTAttributeSpecifier> attributes = __attribute_decl_seq(supportAttributeSpecifiers,
supportDeclspecSpecifiers);
// Look for identifier or nested declarator
boolean hasEllipsis= false;
if (option.fAllowParameterPacks && LT(1) == IToken.tELLIPSIS) {
consume();
hasEllipsis= true;
}
final int lt1= LT(1);
switch (lt1) {
case IToken.tBITCOMPLEMENT:
case IToken.t_operator:
case IToken.tCOLONCOLON:
case IToken.tIDENTIFIER:
case IToken.tCOMPLETION:
if (option.fRequireAbstract) {
// We might have a virt-specifier following a type-id in a trailing-return-type.
ContextSensitiveTokenType contextSensitiveType = getContextSensitiveType(LA(1));
if (contextSensitiveType == ContextSensitiveTokenType.OVERRIDE ||
contextSensitiveType == ContextSensitiveTokenType.FINAL) {
// In that case, we're done parsing the declarator of the type-id.
break;
} else {
// Otherwise, we have what looks like a name, but we're not expecting one.
throwBacktrack(LA(1));
}
}
final IASTName declaratorName= !option.fRequireSimpleName ? qualifiedName() : identifier();
endOffset= calculateEndOffset(declaratorName);
return declarator(pointerOps, hasEllipsis, declaratorName, null, startingOffset,
endOffset, strategy, option, attributes);
}
if (lt1 == IToken.tLPAREN) {
IASTDeclarator cand1= null;
IToken cand1End= null;
// try an abstract function declarator
if (option.fAllowAbstract && option.fAllowFunctions) {
final IToken mark= mark();
try {
cand1= declarator(pointerOps, hasEllipsis, getNodeFactory().newName(), null,
startingOffset, endOffset, strategy, option, attributes);
if (option.fRequireAbstract || !option.fAllowNested || hasEllipsis)
return cand1;
cand1End= LA(1);
} catch (BacktrackException e) {
}
backup(mark);
}
// type-ids for new or operator-id:
if (!option.fAllowNested || hasEllipsis) {
if (option.fAllowAbstract) {
return declarator(pointerOps, hasEllipsis, getNodeFactory().newName(), null,
startingOffset, endOffset, strategy, option, attributes);
}
throwBacktrack(LA(1));
}
// try a nested declarator
try {
consume();
if (LT(1) == IToken.tRPAREN)
throwBacktrack(LA(1));
final IASTDeclarator nested= declarator(DtorStrategy.PREFER_FUNCTION, option);
endOffset= consume(IToken.tRPAREN).getEndOffset();
final IASTDeclarator cand2= declarator(pointerOps, hasEllipsis, getNodeFactory().newName(), nested,
startingOffset, endOffset, strategy, option, attributes);
if (cand1 == null || cand1End == null)
return cand2;
final IToken cand2End= LA(1);
if (cand1End == cand2End) {
CPPASTAmbiguousDeclarator result= new CPPASTAmbiguousDeclarator(cand1, cand2);
((ASTNode) result).setOffsetAndLength((ASTNode) cand1);
return result;
}
// use the longer variant
if (cand1End.getOffset() < cand2End.getOffset())
return cand2;
} catch (BacktrackException e) {
if (cand1 == null)
throw e;
}
backup(cand1End);
return cand1;
}
// try abstract declarator
if (!option.fAllowAbstract) {
// bit-fields may be abstract
if (!option.fAllowBitField || LT(1) != IToken.tCOLON)
throwBacktrack(LA(1));
}
return declarator(pointerOps, hasEllipsis, getNodeFactory().newName(), null, startingOffset,
endOffset, strategy, option, attributes);
}
/**
* Parse a Pointer Operator.
* ptrOperator : "*" attribute-specifier-seq? (cvQualifier)*
* | "&" attribute-specifier-seq?
* | "&&" attribute-specifier-seq?
* | ::? nestedNameSpecifier "*" attribute-specifier-seq? (cvQualifier)*
*
* @throws BacktrackException
* request a backtrack
*/
private List<? extends IASTPointerOperator> consumePointerOperators() throws EndOfFileException, BacktrackException {
List<IASTPointerOperator> result= null;
for (;;) {
IToken mark = mark();
final int startOffset = mark.getOffset();
// __attribute__ in-between pointers
List<IASTAttributeSpecifier> attributes = __attribute_decl_seq(supportAttributeSpecifiers, false);
final int lt1 = LT(1);
if (lt1 == IToken.tAMPER || lt1 == IToken.tAND) {
IToken endToken= consume();
final int offset= endToken.getOffset();
if (allowCPPRestrict && LT(1) == IToken.t_restrict) {
endToken= consume();
}
ICPPASTReferenceOperator refOp = getNodeFactory().newReferenceOperator(lt1 == IToken.tAND);
setRange(refOp, offset, endToken.getEndOffset());
attributes = CollectionUtils.merge(attributes, attributeSpecifierSeq());
addAttributeSpecifiers(attributes, refOp);
if (result != null) {
result.add(refOp);
return result;
}
return Collections.singletonList(refOp);
}
boolean isConst = false, isVolatile = false, isRestrict = false;
IASTName name= null;
int coloncolon= LT(1) == IToken.tCOLONCOLON ? 1 : 0;
loop: while (LTcatchEOF(coloncolon+1) == IToken.tIDENTIFIER) {
switch (LTcatchEOF(coloncolon+2)) {
case IToken.tCOLONCOLON:
coloncolon+= 2;
break;
case IToken.tLT:
coloncolon= 1;
break loop;
default:
coloncolon= 0;
break loop;
}
}
if (coloncolon != 0) {
try {
name= qualifiedName();
if (name.getLookupKey().length != 0) {
backup(mark);
return result;
}
} catch (BacktrackException bt) {
backup(mark);
return result;
}
}
if (LTcatchEOF(1) != IToken.tSTAR) {
backup(mark);
return result;
}
int endOffset= consume().getEndOffset();
loop: for (;;) {
switch (LTcatchEOF(1)) {
case IToken.t_const:
endOffset= consume().getEndOffset();
isConst = true;
break;
case IToken.t_volatile:
endOffset= consume().getEndOffset();
isVolatile = true;
break;
case IToken.t_restrict:
if (!allowCPPRestrict)
throwBacktrack(LA(1));
endOffset= consume().getEndOffset();
isRestrict = true;
break;
default:
break loop;
}
}
IASTPointer pointer;
if (name != null) {
pointer= getNodeFactory().newPointerToMember(name);
} else {
pointer = getNodeFactory().newPointer();
}
pointer.setConst(isConst);
pointer.setVolatile(isVolatile);
pointer.setRestrict(isRestrict);
setRange(pointer, startOffset, endOffset);
if (result == null) {
result= new ArrayList<>(4);
}
attributes = CollectionUtils.merge(attributes, attributeSpecifierSeq());
addAttributeSpecifiers(attributes, pointer);
result.add(pointer);
}
}
private IASTDeclarator declarator(List<? extends IASTPointerOperator> pointerOps, boolean hasEllipsis,
IASTName declaratorName, IASTDeclarator nestedDeclarator, int startingOffset, int endOffset,
DtorStrategy strategy, DeclarationOptions option, List<IASTAttributeSpecifier> attributes)
throws EndOfFileException, BacktrackException {
ICPPASTDeclarator result= null;
loop: while (true) {
final int lt1= LTcatchEOF(1);
switch (lt1) {
case IToken.tLPAREN:
if (option.fAllowFunctions && strategy == DtorStrategy.PREFER_FUNCTION) {
result= functionDeclarator(false);
setDeclaratorID(result, hasEllipsis, declaratorName, nestedDeclarator);
}
break loop;
case IToken.tLBRACKET:
if (LTcatchEOF(2) == IToken.tLBRACKET) {
attributes = CollectionUtils.merge(attributes, attributeSpecifierSeq());
break;
}
result= arrayDeclarator(option);
setDeclaratorID(result, hasEllipsis, declaratorName, nestedDeclarator);
break loop;
case IToken.tCOLON:
if (!option.fAllowBitField || nestedDeclarator != null)
break loop; // no backtrack because typeid can be followed by colon
result= bitFieldDeclarator();
setDeclaratorID(result, hasEllipsis, declaratorName, nestedDeclarator);
break loop;
case IGCCToken.t__attribute__: // if __attribute__ is after a declarator
if (!supportAttributeSpecifiers)
throwBacktrack(LA(1));
attributes = CollectionUtils.merge(attributes,
__attribute_decl_seq(true, supportDeclspecSpecifiers));
break;
case IGCCToken.t__declspec:
if (!supportDeclspecSpecifiers)
throwBacktrack(LA(1));
attributes = CollectionUtils.merge(attributes,
__attribute_decl_seq(supportAttributeSpecifiers, true));
break;
default:
break loop;
}
}
attributes = CollectionUtils.merge(attributes,
__attribute_decl_seq(supportAttributeSpecifiers, supportDeclspecSpecifiers));
if (result == null) {
result= getNodeFactory().newDeclarator(null);
setDeclaratorID(result, hasEllipsis, declaratorName, nestedDeclarator);
} else {
endOffset= calculateEndOffset(result);
}
if (LTcatchEOF(1) == IToken.t_asm) { // asm labels bug 226121
consume();
endOffset= asmExpression(null).getEndOffset();
attributes = CollectionUtils.merge(attributes,
__attribute_decl_seq(supportAttributeSpecifiers, supportDeclspecSpecifiers));
}
if (pointerOps != null) {
for (IASTPointerOperator po : pointerOps) {
result.addPointerOperator(po);
}
}
addAttributeSpecifiers(attributes, result);
((ASTNode) result).setOffsetAndLength(startingOffset, endOffset - startingOffset);
return result;
}
private void setDeclaratorID(ICPPASTDeclarator declarator, boolean hasEllipsis, IASTName declaratorName, IASTDeclarator nestedDeclarator) {
if (nestedDeclarator != null) {
declarator.setNestedDeclarator(nestedDeclarator);
declarator.setName(getNodeFactory().newName());
} else {
declarator.setName(declaratorName);
}
declarator.setDeclaresParameterPack(hasEllipsis);
}
/**
* Parse a function declarator starting with the left parenthesis.
*/
private ICPPASTFunctionDeclarator functionDeclarator(boolean isLambdaDeclarator) throws EndOfFileException, BacktrackException {
IToken last = consume(IToken.tLPAREN);
final int startOffset= last.getOffset();
int endOffset= last.getEndOffset();
final ICPPASTFunctionDeclarator fc = getNodeFactory().newFunctionDeclarator(null);
ICPPASTParameterDeclaration pd= null;
paramLoop: while (true) {
switch (LT(1)) {
case IToken.tRPAREN:
case IToken.tEOC:
endOffset= consume().getEndOffset();
break paramLoop;
case IToken.tELLIPSIS:
consume();
endOffset= consume(IToken.tRPAREN).getEndOffset();
fc.setVarArgs(true);
break paramLoop;
case IToken.tCOMMA:
if (pd == null)
throwBacktrack(LA(1));
endOffset= consume().getEndOffset();
pd= null;
break;
default:
if (pd != null)
throwBacktrack(startOffset, endOffset - startOffset);
pd = parameterDeclaration();
fc.addParameterDeclaration(pd);
endOffset = calculateEndOffset(pd);
break;
}
}
// Handle ambiguity between parameter pack and varargs.
if (pd != null) {
ICPPASTDeclarator dtor = pd.getDeclarator();
if (dtor != null && !(dtor instanceof IASTAmbiguousDeclarator)) {
if (dtor.declaresParameterPack() && dtor.getNestedDeclarator() == null
&& dtor.getInitializer() == null && dtor.getName().getSimpleID().length == 0) {
((IASTAmbiguityParent) fc).replace(pd, new CPPASTAmbiguousParameterDeclaration(pd));
}
}
}
// Consume any number of __attribute__ tokens after the parameters
List<IASTAttributeSpecifier> attributes = __attribute_decl_seq(supportAttributeSpecifiers, false);
// cv-qualifiers
if (isLambdaDeclarator) {
if (LT(1) == IToken.t_mutable) {
fc.setMutable(true);
endOffset= consume().getEndOffset();
}
} else {
cvloop: while (true) {
switch (LT(1)) {
case IToken.t_const:
fc.setConst(true);
endOffset= consume().getEndOffset();
break;
case IToken.t_volatile:
fc.setVolatile(true);
endOffset= consume().getEndOffset();
break;
default:
break cvloop;
}
}
}
// ref-qualifiers
switch (LT(1)) {
case IToken.tAMPER:
fc.setRefQualifier(RefQualifier.LVALUE);
endOffset= consume().getEndOffset();
break;
case IToken.tAND:
fc.setRefQualifier(RefQualifier.RVALUE);
endOffset= consume().getEndOffset();
break;
default:
break;
}
// throws clause
if (LT(1) == IToken.t_throw) {
fc.setEmptyExceptionSpecification();
consume(); // throw
consume(IToken.tLPAREN);
thloop: while (true) {
switch (LT(1)) {
case IToken.tRPAREN:
case IToken.tEOC:
endOffset = consume().getEndOffset();
break thloop;
case IToken.tCOMMA:
consume();
break;
default:
int thoffset = LA(1).getOffset();
try {
ICPPASTTypeId typeId = typeId(DeclarationOptions.TYPEID);
if (LT(1) == IToken.tELLIPSIS) {
typeId.setIsPackExpansion(true);
adjustEndOffset(typeId, consume().getEndOffset());
}
fc.addExceptionSpecificationTypeId(typeId);
} catch (BacktrackException e) {
int thendoffset = LA(1).getOffset();
if (thoffset == thendoffset) {
thendoffset = consume().getEndOffset();
}
IASTProblem p = createProblem(IProblem.SYNTAX_ERROR, thoffset, thendoffset - thoffset);
IASTProblemTypeId typeIdProblem = getNodeFactory().newProblemTypeId(p);
((ASTNode) typeIdProblem).setOffsetAndLength(((ASTNode) p));
fc.addExceptionSpecificationTypeId(typeIdProblem);
}
break;
}
}
// more __attribute__ after throws
attributes = CollectionUtils.merge(attributes,
__attribute_decl_seq(supportAttributeSpecifiers, false));
}
// noexcept specification
if (LT(1) == IToken.t_noexcept) {
consume(); // noexcept
IASTExpression expression = ICPPASTFunctionDeclarator.NOEXCEPT_DEFAULT;
endOffset = getEndOffset();
if (LT(1) == IToken.tLPAREN) {
consume(); // (
expression = expression();
consume(IToken.tRPAREN); //)
endOffset = getEndOffset();
}
fc.setNoexceptExpression((ICPPASTExpression) expression);
}
attributes = CollectionUtils.merge(attributes, attributeSpecifierSeq());
addAttributeSpecifiers(attributes, fc);
if (attributes != null && !attributes.isEmpty()) {
endOffset = getEndOffset();
}
if (LT(1) == IToken.tARROW) {
consume();
IASTTypeId typeId= typeId(DeclarationOptions.TYPEID_TRAILING_RETURN_TYPE);
fc.setTrailingReturnType(typeId);
endOffset= calculateEndOffset(typeId);
}
return setRange(fc, startOffset, endOffset);
}
/**
* Parse an array declarator starting at the square bracket.
*/
private ICPPASTArrayDeclarator arrayDeclarator(DeclarationOptions option) throws EndOfFileException, BacktrackException {
ArrayList<IASTArrayModifier> arrayMods = new ArrayList<>(4);
int start= LA(1).getOffset();
consumeArrayModifiers(option, arrayMods);
if (arrayMods.isEmpty())
throwBacktrack(LA(1));
final int endOffset = calculateEndOffset(arrayMods.get(arrayMods.size() - 1));
final ICPPASTArrayDeclarator d = getNodeFactory().newArrayDeclarator(null);
for (IASTArrayModifier m : arrayMods) {
d.addArrayModifier(m);
}
((ASTNode) d).setOffsetAndLength(start, endOffset-start);
return d;
}
/**
* Parses for a bit field declarator starting with the colon
*/
private ICPPASTFieldDeclarator bitFieldDeclarator() throws EndOfFileException, BacktrackException {
int start= consume(IToken.tCOLON).getOffset();
final IASTExpression bitField = constantExpression();
final int endOffset = calculateEndOffset(bitField);
ICPPASTFieldDeclarator d = getNodeFactory().newFieldDeclarator(null, bitField);
((ASTNode) d).setOffsetAndLength(start, endOffset-start);
return d;
}
/**
* Parse a class/struct/union definition. classSpecifier : classKey attribute-specifier-seq? name
* (baseClause)? "{" (memberSpecification)* "}"
*
* @throws BacktrackException
* request a backtrack
*/
protected ICPPASTCompositeTypeSpecifier classSpecifier() throws BacktrackException, EndOfFileException {
int classKind = 0;
IToken mark = mark();
final int offset= mark.getOffset();
// class key
switch (LT(1)) {
case IToken.t_class:
consume();
classKind = ICPPASTCompositeTypeSpecifier.k_class;
break;
case IToken.t_struct:
consume();
classKind = IASTCompositeTypeSpecifier.k_struct;
break;
case IToken.t_union:
consume();
classKind = IASTCompositeTypeSpecifier.k_union;
break;
default:
throwBacktrack(mark);
return null; // line is never reached, hint for the parser
}
// if __attribute__ or __declspec occurs after struct/union/class and before the identifier
List<IASTAttributeSpecifier> attributes = __attribute_decl_seq(supportAttributeSpecifiers, supportDeclspecSpecifiers);
attributes = CollectionUtils.merge(attributes, attributeSpecifierSeq());
// class name
IASTName name = null;
if (LT(1) == IToken.tIDENTIFIER) {
name = qualifiedName();
} else {
name = getNodeFactory().newName();
}
// if __attribute__ or __declspec occurs after struct/union/class identifier and before the { or ;
attributes = CollectionUtils.merge(attributes, __attribute_decl_seq(supportAttributeSpecifiers, supportDeclspecSpecifiers));
ICPPASTCompositeTypeSpecifier astClassSpecifier = getNodeFactory().newCompositeTypeSpecifier(classKind, name);
addAttributeSpecifiers(attributes, astClassSpecifier);
// class virt specifier
if (LT(1) == IToken.tIDENTIFIER) {
classVirtSpecifier(astClassSpecifier);
}
// base clause
if (LT(1) == IToken.tCOLON) {
try {
baseClause(astClassSpecifier);
} catch (BacktrackException e) {
// Couldn't parse a base-clause.
// Backtrack and try an elaborated-type-specifier instead.
backup(mark);
throw e;
}
// content assist within the base-clause
if (LT(1) == IToken.tEOC) {
return astClassSpecifier;
}
}
if (LT(1) != IToken.tLBRACE) {
IToken errorPoint = LA(1);
backup(mark);
throwBacktrack(errorPoint);
}
mark= null; // don't hold on to tokens while parsing the members.
final char[] outerName= currentClassName;
currentClassName= name.getLookupKey();
try {
declarationListInBraces(astClassSpecifier, offset, DeclarationOptions.CPP_MEMBER);
} finally {
currentClassName= outerName;
}
return astClassSpecifier;
}
protected int token2Visibility(int type) {
switch (type) {
case IToken.t_public:
return ICPPASTVisibilityLabel.v_public;
case IToken.t_protected:
return ICPPASTVisibilityLabel.v_protected;
case IToken.t_private:
return ICPPASTVisibilityLabel.v_private;
}
return 0;
}
/**
* Parse a base clause for a class specification.
* base-clause:
* : base-specifier-list
* base-specifier-list:
* base-specifier
* base-specifier-list, base-specifier
*/
private void baseClause(ICPPASTCompositeTypeSpecifier astClassSpec) throws EndOfFileException, BacktrackException {
consume(IToken.tCOLON);
for (;;) {
ICPPASTCompositeTypeSpecifier.ICPPASTBaseSpecifier baseSpec = baseSpecifier();
astClassSpec.addBaseSpecifier(baseSpec);
if (LT(1) == IToken.tELLIPSIS) {
baseSpec.setIsPackExpansion(true);
adjustEndOffset(baseSpec, consume().getEndOffset());
}
if (LT(1) != IToken.tCOMMA) {
return;
}
consume();
}
}
/**
* Parse a class virtual specifier for a class specification.
* class-virt-specifier:
* final
* @param astClassSpecifier
*/
private void classVirtSpecifier(ICPPASTCompositeTypeSpecifier astClassSpecifier) throws EndOfFileException, BacktrackException {
IToken token = LA();
ContextSensitiveTokenType contextSensitiveType = getContextSensitiveType(token);
if (contextSensitiveType == ContextSensitiveTokenType.FINAL) {
consume();
ICPPASTClassVirtSpecifier spec = getNodeFactory().newClassVirtSpecifier(
ICPPASTClassVirtSpecifier.SpecifierKind.Final);
setRange(spec, token.getOffset(), token.getOffset() + token.getLength());
astClassSpecifier.setVirtSpecifier(spec);
}
}
/**
* base-specifier:
* ::? nested-name-specifier? class-name
* virtual access-specifier? ::? nested-name-specifier? class-name
* access-specifier virtual? ::? nested-name-specifier? class-name
*
* access-specifier: private | protected | public
* @return
*/
private ICPPASTBaseSpecifier baseSpecifier() throws EndOfFileException, BacktrackException {
int startOffset= LA(1).getOffset();
boolean isVirtual = false;
int visibility = 0;
ICPPASTNameSpecifier nameSpec = null;
loop: for (;;) {
switch (LT(1)) {
case IToken.t_virtual:
isVirtual = true;
consume();
break;
case IToken.t_public:
visibility = ICPPASTCompositeTypeSpecifier.ICPPASTBaseSpecifier.v_public;
consume();
break;
case IToken.t_protected:
visibility = ICPPASTCompositeTypeSpecifier.ICPPASTBaseSpecifier.v_protected;
consume();
break;
case IToken.t_private:
visibility = ICPPASTCompositeTypeSpecifier.ICPPASTBaseSpecifier.v_private;
consume();
break;
default:
break loop;
}
}
nameSpec = nameSpecifier();
ICPPASTCompositeTypeSpecifier.ICPPASTBaseSpecifier baseSpec = getNodeFactory().newBaseSpecifier(nameSpec, visibility, isVirtual);
setRange(baseSpec, startOffset, calculateEndOffset(nameSpec));
return baseSpec;
}
protected void catchHandlerSequence(List<ICPPASTCatchHandler> collection) throws EndOfFileException, BacktrackException {
if (LT(1) == IToken.tEOC)
return;
if (LT(1) != IToken.t_catch)
throwBacktrack(LA(1)); // error, need at least one
int lt1 = LT(1);
while (lt1 == IToken.t_catch) {
int startOffset = consume().getOffset();
consume(IToken.tLPAREN);
boolean isEllipsis = false;
IASTDeclaration decl = null;
try {
if (LT(1) == IToken.tELLIPSIS) {
consume(IToken.tELLIPSIS);
isEllipsis = true;
} else {
decl= simpleSingleDeclaration(DeclarationOptions.EXCEPTION);
}
if (LT(1) != IToken.tEOC)
consume(IToken.tRPAREN);
} catch (BacktrackException bte) {
failParse();
IASTProblem p = createProblem(bte);
IASTProblemDeclaration pd = getNodeFactory().newProblemDeclaration(p);
((ASTNode) pd).setOffsetAndLength(((ASTNode) p));
decl = pd;
}
ICPPASTCatchHandler handler = getNodeFactory().newCatchHandler(decl, null);
if (LT(1) != IToken.tEOC) {
IASTStatement compoundStatement = catchBlockCompoundStatement();
((ASTNode) handler).setOffsetAndLength(startOffset, calculateEndOffset(compoundStatement) - startOffset);
handler.setIsCatchAll(isEllipsis);
if (compoundStatement != null) {
handler.setCatchBody(compoundStatement);
}
}
collection.add(handler);
lt1 = LTcatchEOF(1);
}
}
private IASTSimpleDeclaration simpleSingleDeclaration(DeclarationOptions options) throws BacktrackException, EndOfFileException {
final int startOffset= LA(1).getOffset();
IASTDeclSpecifier declSpec;
IASTDeclarator declarator;
List<IASTAttributeSpecifier> attributes = attributeSpecifierSeq();
try {
Decl decl= declSpecifierSequence_initDeclarator(options, true);
declSpec= decl.fDeclSpec1;
declarator= decl.fDtor1;
} catch (FoundAggregateInitializer lie) {
declSpec= lie.fDeclSpec;
declarator= addInitializer(lie, options);
}
final int endOffset = figureEndOffset(declSpec, declarator);
final IASTSimpleDeclaration decl= getNodeFactory().newSimpleDeclaration(declSpec);
if (declarator != null)
decl.addDeclarator(declarator);
((ASTNode) decl).setOffsetAndLength(startOffset, endOffset - startOffset);
addAttributeSpecifiers(attributes, decl);
return decl;
}
protected IASTStatement catchBlockCompoundStatement() throws BacktrackException, EndOfFileException {
if (mode == ParserMode.QUICK_PARSE || mode == ParserMode.STRUCTURAL_PARSE || !isActiveCode()) {
int offset = LA(1).getOffset();
IToken last = skipOverCompoundStatement(true);
IASTCompoundStatement cs = getNodeFactory().newCompoundStatement();
setRange(cs, offset, last.getEndOffset());
return cs;
} else if (mode == ParserMode.COMPLETION_PARSE || mode == ParserMode.SELECTION_PARSE) {
if (scanner.isOnTopContext())
return compoundStatement();
int offset = LA(1).getOffset();
IToken last = skipOverCompoundStatement(true);
IASTCompoundStatement cs = getNodeFactory().newCompoundStatement();
setRange(cs, offset, last.getEndOffset());
return cs;
}
return compoundStatement();
}
@Override
protected void setupTranslationUnit() throws DOMException {
translationUnit = getNodeFactory().newTranslationUnit(scanner);
translationUnit.setIndex(index);
// Add built-in names to the scope.
if (builtinBindingsProvider != null) {
if (translationUnit instanceof ASTTranslationUnit) {
((ASTTranslationUnit) translationUnit).setupBuiltinBindings(builtinBindingsProvider);
}
}
}
private void consumeArrayModifiers(DeclarationOptions option, List<IASTArrayModifier> collection)
throws EndOfFileException, BacktrackException {
boolean allowExpression= option == DeclarationOptions.TYPEID_NEW;
while (LT(1) == IToken.tLBRACKET) {
int o = consume().getOffset(); // eat the '['
IASTExpression exp = null;
if (LT(1) != IToken.tRBRACKET && LT(1) != IToken.tEOC) {
exp = allowExpression ? expression() : constantExpression();
allowExpression= false;
}
int l;
switch (LT(1)) {
case IToken.tRBRACKET:
case IToken.tEOC:
l = consume().getEndOffset();
break;
default:
throw backtrack;
}
IASTArrayModifier arrayMod = getNodeFactory().newArrayModifier(exp);
((ASTNode) arrayMod).setOffsetAndLength(o, l - o);
List<IASTAttributeSpecifier> attributes = attributeSpecifierSeq();
addAttributeSpecifiers(attributes, arrayMod);
collection.add(arrayMod);
}
return;
}
@Override
protected IASTTranslationUnit getTranslationUnit() {
return translationUnit;
}
@Override
protected IASTStatement statement() throws EndOfFileException, BacktrackException {
List<IASTAttributeSpecifier> attributes = attributeSpecifierSeq();
IASTStatement statement = null;
switch (LT(1)) {
// labeled statements
case IToken.t_case:
statement = parseCaseStatement();
break;
case IToken.t_default:
statement = parseDefaultStatement();
break;
// compound statement
case IToken.tLBRACE:
statement = parseCompoundStatement();
break;
// selection statement
case IToken.t_if:
statement = parseIfStatement();
break;
case IToken.t_switch:
statement = parseSwitchStatement();
break;
// iteration statements
case IToken.t_while:
statement = parseWhileStatement();
break;
case IToken.t_do:
statement = parseDoStatement();
break;
case IToken.t_for:
statement = parseForStatement();
break;
// jump statement
case IToken.t_break:
statement = parseBreakStatement();
break;
case IToken.t_continue:
statement = parseContinueStatement();
break;
case IToken.t_return:
statement = parseReturnStatement();
break;
case IToken.t_goto:
statement = parseGotoStatement();
break;
case IToken.tSEMI:
statement = parseNullStatement();
break;
case IToken.t_try:
statement = parseTryStatement();
break;
default:
// can be many things:
// label
if (LT(1) == IToken.tIDENTIFIER && LT(2) == IToken.tCOLON) {
statement = parseLabelStatement();
break;
}
return parseDeclarationOrExpressionStatement(attributes);
}
addAttributeSpecifiers(attributes, statement);
return statement;
}
protected IASTStatement parseTryStatement() throws EndOfFileException, BacktrackException {
int startO = consume().getOffset();
IASTStatement tryBlock = compoundStatement();
List<ICPPASTCatchHandler> catchHandlers = new ArrayList<>(DEFAULT_CATCH_HANDLER_LIST_SIZE);
catchHandlerSequence(catchHandlers);
ICPPASTTryBlockStatement tryStatement = getNodeFactory().newTryBlockStatement(tryBlock);
((ASTNode) tryStatement).setOffset(startO);
for (int i = 0; i < catchHandlers.size(); ++i) {
ICPPASTCatchHandler handler = catchHandlers.get(i);
tryStatement.addCatchHandler(handler);
((ASTNode) tryStatement).setLength(calculateEndOffset(handler) - startO);
}
return tryStatement;
}
@Override
protected void nullifyTranslationUnit() {
translationUnit = null;
}
@Override
protected IASTStatement parseWhileStatement() throws EndOfFileException, BacktrackException {
int startOffset = consume().getOffset();
consume(IToken.tLPAREN);
IASTNode while_condition = cppStyleCondition(IToken.tRPAREN);
switch (LT(1)) {
case IToken.tRPAREN:
consume();
break;
case IToken.tEOC:
break;
default:
throwBacktrack(LA(1));
}
IASTStatement while_body = null;
if (LT(1) != IToken.tEOC)
while_body = statement();
IASTWhileStatement while_statement;
if (while_condition instanceof IASTExpression)
while_statement = getNodeFactory().newWhileStatement((IASTExpression) while_condition, while_body);
else
while_statement = getNodeFactory().newWhileStatement((IASTDeclaration) while_condition, while_body);
((ASTNode) while_statement).setOffsetAndLength(startOffset,
(while_body != null ? calculateEndOffset(while_body) : LA(1).getEndOffset()) - startOffset);
return while_statement;
}
protected IASTNode cppStyleCondition(int expectToken) throws BacktrackException, EndOfFileException {
IASTExpression e= null;
IASTSimpleDeclaration decl= null;
IToken end= null;
IToken mark = mark();
try {
decl= simpleSingleDeclaration(DeclarationOptions.CONDITION);
end= LA(1);
final int la= end.getType();
if (la != expectToken && la != IToken.tEOC) {
end= null;
decl= null;
}
} catch (BacktrackException b) {
}
backup(mark);
try {
e= expression();
final IToken end2= LA(1);
final int la= end2.getType();
if (la != expectToken && la != IToken.tEOC) {
throwBacktrack(end2);
}
if (end == null)
return e;
final int endOffset = end.getOffset();
final int endOffset2 = end2.getOffset();
if (endOffset == endOffset2) {
CPPASTAmbiguousCondition ambig= new CPPASTAmbiguousCondition(e, decl);
setRange(ambig, e);
return ambig;
}
if (endOffset < endOffset2)
return e;
} catch (BacktrackException bt) {
if (end == null) {
if (expectToken == IToken.tRPAREN) {
backup(mark);
return skipProblemConditionInParenthesis(mark.getOffset());
}
throw bt;
}
}
backup(end);
return decl;
}
@Override
protected ASTVisitor createAmbiguityNodeVisitor() {
return new CPPASTAmbiguityResolver();
}
@Override
protected IASTAmbiguousStatement createAmbiguousStatement() {
return new CPPASTAmbiguousStatement();
}
protected IASTStatement parseIfStatement() throws EndOfFileException, BacktrackException {
ICPPASTIfStatement result = null;
ICPPASTIfStatement if_statement = null;
int start = LA(1).getOffset();
if_loop: while (true) {
int so = consume(IToken.t_if).getOffset();
ICPPASTIfStatement new_if_statement = getNodeFactory().newIfStatement();
// constexpr if
if (LT(1) == IToken.t_constexpr) {
consume();
new_if_statement.setIsConstexpr(true);
}
consume(IToken.tLPAREN);
// init-statement
IToken mark= mark();
try {
IASTStatement statement = initStatement();
new_if_statement.setInitializerStatement(statement);
} catch (BacktrackException e) {
backup(mark);
}
// condition
IASTNode condition= cppStyleCondition(IToken.tRPAREN);
if (LT(1) == IToken.tEOC) {
// Completing in the condition
if (condition instanceof IASTExpression)
new_if_statement.setConditionExpression((IASTExpression) condition);
else if (condition instanceof IASTDeclaration)
new_if_statement.setConditionDeclaration((IASTDeclaration) condition);
if (if_statement != null) {
if_statement.setElseClause(new_if_statement);
}
return result != null ? result : new_if_statement;
}
consume(IToken.tRPAREN);
IASTStatement thenClause = statement();
((ASTNode) new_if_statement).setOffset(so);
if (condition != null && (condition instanceof IASTExpression || condition instanceof IASTDeclaration))
// shouldn't be possible but failure in condition() makes it so
{
if (condition instanceof IASTExpression)
new_if_statement.setConditionExpression((IASTExpression) condition);
else if (condition instanceof IASTDeclaration)
new_if_statement.setConditionDeclaration((IASTDeclaration) condition);
}
if (thenClause != null) {
new_if_statement.setThenClause(thenClause);
((ASTNode) new_if_statement).setLength(calculateEndOffset(thenClause) - ((ASTNode) new_if_statement).getOffset());
}
if (LT(1) == IToken.t_else) {
consume();
if (LT(1) == IToken.t_if) {
// an else if, don't recurse, just loop and do another if
if (if_statement != null) {
if_statement.setElseClause(new_if_statement);
((ASTNode) if_statement).setLength(calculateEndOffset(new_if_statement) - ((ASTNode) if_statement).getOffset());
}
if (result == null && if_statement != null)
result = if_statement;
if (result == null)
result = new_if_statement;
if_statement = new_if_statement;
continue if_loop;
}
IASTStatement elseStatement = statement();
new_if_statement.setElseClause(elseStatement);
if (if_statement != null) {
if_statement.setElseClause(new_if_statement);
((ASTNode) if_statement).setLength(calculateEndOffset(new_if_statement) - ((ASTNode) if_statement).getOffset());
} else {
if (result == null)
result = new_if_statement;
if_statement = new_if_statement;
}
} else {
if (thenClause != null)
((ASTNode) new_if_statement).setLength(calculateEndOffset(thenClause) - start);
if (if_statement != null) {
if_statement.setElseClause(new_if_statement);
((ASTNode) new_if_statement).setLength(calculateEndOffset(new_if_statement) - start);
}
if (result == null && if_statement != null)
result = if_statement;
if (result == null)
result = new_if_statement;
if_statement = new_if_statement;
}
break if_loop;
}
reconcileLengths(result);
return result;
}
@Override
protected IASTCompoundStatement functionBody() throws EndOfFileException, BacktrackException {
++functionBodyCount;
try {
return super.functionBody();
} finally {
--functionBodyCount;
}
}
protected IASTStatement parseSwitchStatement() throws EndOfFileException, BacktrackException {
int startOffset;
startOffset = consume().getOffset();
consume(IToken.tLPAREN);
ICPPASTSwitchStatement switch_statement = getNodeFactory().newSwitchStatement();
// init-statement
IToken mark= mark();
try {
IASTStatement statement = initStatement();
switch_statement.setInitializerStatement(statement);
} catch (BacktrackException e) {
backup(mark);
}
IASTNode switch_condition = cppStyleCondition(IToken.tRPAREN);
switch (LT(1)) {
case IToken.tRPAREN:
consume();
break;
case IToken.tEOC:
break;
default:
throwBacktrack(LA(1));
}
IASTStatement switch_body = parseSwitchBody();
((ASTNode) switch_statement).setOffsetAndLength(startOffset,
(switch_body != null ? calculateEndOffset(switch_body) : LA(1).getEndOffset()) - startOffset);
if (switch_condition instanceof IASTExpression) {
switch_statement.setControllerExpression((IASTExpression) switch_condition);
} else if (switch_condition instanceof IASTDeclaration) {
switch_statement.setControllerDeclaration((IASTDeclaration) switch_condition);
}
if (switch_body != null) {
switch_statement.setBody(switch_body);
}
return switch_statement;
}
protected IASTStatement parseForStatement() throws EndOfFileException, BacktrackException {
final int offset= consume(IToken.t_for).getOffset();
consume(IToken.tLPAREN);
IToken mark= mark();
IASTStatement forStmt;
try {
forStmt= startRangeBasedForLoop();
} catch (BacktrackException e) {
backup(mark);
forStmt= startTraditionalForLoop();
}
mark= null;
int endOffset= consumeOrEOC(IToken.tRPAREN).getEndOffset();
if (LT(1) != IToken.tEOC) {
IASTStatement body = statement();
if (forStmt instanceof ICPPASTRangeBasedForStatement) {
((ICPPASTRangeBasedForStatement) forStmt).setBody(body);
} else {
((IASTForStatement) forStmt).setBody(body);
}
endOffset= calculateEndOffset(body);
}
return setRange(forStmt, offset, endOffset);
}
// Look for "for-range-declaration : for-range-initializer"
// for-range-declaration:
// attribute-specifier-seq? type-specifier-seq declarator
// for-range-initializer:
// expression
// braced-init-list
private ICPPASTRangeBasedForStatement startRangeBasedForLoop() throws EndOfFileException, BacktrackException {
List<IASTAttributeSpecifier> attributes = attributeSpecifierSeq();
IASTDeclaration decl= simpleDeclaration(DeclarationOptions.RANGE_BASED_FOR, attributes);
consume(IToken.tCOLON);
IASTInitializerClause init= null;
switch (LT(1)) {
case IToken.tEOC:
break;
case IToken.tLBRACE:
init= bracedInitList(false, false);
break;
default:
init= expression();
}
ICPPASTRangeBasedForStatement result = getNodeFactory().newRangeBasedForStatement();
result.setDeclaration(decl);
result.setInitializerClause(init);
return result;
}
private IASTForStatement startTraditionalForLoop() throws BacktrackException, EndOfFileException {
final IASTStatement initStmt = initStatement();
IASTNode condition= null;
IASTExpression iterExpr= null;
int lt1 = LT(1);
if (lt1 != IToken.tSEMI && lt1 != IToken.tEOC) {
condition = cppStyleCondition(IToken.tSEMI);
}
consumeOrEOC(IToken.tSEMI);
lt1 = LT(1);
if (lt1 != IToken.tRPAREN && lt1 != IToken.tEOC) {
iterExpr = expression();
}
ICPPASTForStatement result = getNodeFactory().newForStatement();
result.setInitializerStatement(initStmt);
if (condition instanceof IASTExpression) {
result.setConditionExpression((IASTExpression) condition);
} else if (condition instanceof IASTDeclaration) {
result.setConditionDeclaration((IASTDeclaration) condition);
}
result.setIterationExpression(iterExpr);
return result;
}
@Override
protected IASTStatement parseReturnStatement() throws EndOfFileException, BacktrackException {
final int offset= consume(IToken.t_return).getOffset(); // t_return
// Optional expression
IASTInitializerClause expr = null;
final int lt1 = LT(1);
if (lt1 == IToken.tLBRACE) {
expr= bracedInitList(true, false);
} else if (lt1 != IToken.tSEMI) {
expr = expression();
}
// Semicolon
final int endOffset= consumeOrEOC(IToken.tSEMI).getEndOffset();
return setRange(getNodeFactory().newReturnStatement(expr), offset, endOffset);
}
@Override
protected IASTExpression expressionWithOptionalTrailingEllipsis() throws BacktrackException,
EndOfFileException {
IASTExpression result = expression();
if (LT(1) == IToken.tELLIPSIS) {
result = addPackExpansion(result, consume());
}
return result;
}
@Override
protected IASTTypeId typeIdWithOptionalTrailingEllipsis(DeclarationOptions option)
throws EndOfFileException, BacktrackException {
ICPPASTTypeId result = typeId(option);
if (LT(1) == IToken.tELLIPSIS) {
addPackExpansion(result, consume());
}
return result;
}
@Override
protected IASTAlignmentSpecifier createAmbiguousAlignmentSpecifier(IASTAlignmentSpecifier expression,
IASTAlignmentSpecifier typeId) {
return new CPPASTAmbiguousAlignmentSpecifier(expression, typeId);
}
}