/*******************************************************************************
* Copyright (c) 2006, 2010 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:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.cdt.core.dom.lrparser.action.cpp;
import static org.eclipse.cdt.core.dom.lrparser.action.ParserUtil.*;
import static org.eclipse.cdt.core.parser.util.CollectionUtils.findFirstAndRemove;
import static org.eclipse.cdt.core.parser.util.CollectionUtils.reverseIterable;
import static org.eclipse.cdt.internal.core.dom.lrparser.cpp.CPPParsersym.*;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import lpg.lpgjavaruntime.IToken;
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.IASTExpressionList;
import org.eclipse.cdt.core.dom.ast.IASTForStatement;
import org.eclipse.cdt.core.dom.ast.IASTFunctionDeclarator;
import org.eclipse.cdt.core.dom.ast.IASTIdExpression;
import org.eclipse.cdt.core.dom.ast.IASTIfStatement;
import org.eclipse.cdt.core.dom.ast.IASTInitializerClause;
import org.eclipse.cdt.core.dom.ast.IASTInitializerExpression;
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.IASTParameterDeclaration;
import org.eclipse.cdt.core.dom.ast.IASTPointer;
import org.eclipse.cdt.core.dom.ast.IASTPointerOperator;
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.IASTSwitchStatement;
import org.eclipse.cdt.core.dom.ast.IASTTypeId;
import org.eclipse.cdt.core.dom.ast.IASTUnaryExpression;
import org.eclipse.cdt.core.dom.ast.IASTWhileStatement;
import org.eclipse.cdt.core.dom.ast.IBasicType.Kind;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTAmbiguousTemplateArgument;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTCatchHandler;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTCompositeTypeSpecifier;
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.ICPPASTDeleteExpression;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTElaboratedTypeSpecifier;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTExplicitTemplateInstantiation;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTFieldReference;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTFunctionDeclarator;
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.ICPPASTLinkageSpecification;
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.ICPPASTNewExpression;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTOperatorName;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTParameterDeclaration;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTPointerToMember;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTQualifiedName;
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.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.ICPPASTTryBlockStatement;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTTypenameExpression;
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.ICPPASTVisibilityLabel;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPNodeFactory;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTCompositeTypeSpecifier.ICPPASTBaseSpecifier;
import org.eclipse.cdt.core.dom.lrparser.ISecondaryParser;
import org.eclipse.cdt.core.dom.lrparser.LPGTokenAdapter;
import org.eclipse.cdt.core.dom.lrparser.action.BuildASTParserAction;
import org.eclipse.cdt.core.dom.lrparser.action.ITokenMap;
import org.eclipse.cdt.core.dom.lrparser.action.ITokenStream;
import org.eclipse.cdt.core.dom.lrparser.action.ParserUtil;
import org.eclipse.cdt.core.dom.lrparser.action.ScopedStack;
import org.eclipse.cdt.core.dom.lrparser.action.TokenMap;
import org.eclipse.cdt.internal.core.dom.lrparser.cpp.CPPParsersym;
import org.eclipse.cdt.internal.core.dom.parser.ASTNode;
import org.eclipse.cdt.internal.core.dom.parser.IASTAmbiguityParent;
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.CPPASTAmbiguousDeclarator;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPASTAmbiguousExpression;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPASTAmbiguousStatement;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPASTAmbiguousTemplateArgument;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPASTConstructorInitializer;
import org.eclipse.cdt.internal.core.dom.parser.cpp.OverloadableOperator;
/**
* Semantic actions that build the AST during the parse.
* These are the actions that are specific to the C++ parser, the superclass
* contains actions that can be shared with the C99 parser.
*
* @author Mike Kucera
*/
@SuppressWarnings("restriction")
public class CPPBuildASTParserAction extends BuildASTParserAction {
/** Allows code in this class to refer to the token kinds in CPPParsersym */
private final ITokenMap tokenMap;
/** Used to create the AST node objects */
protected final ICPPNodeFactory nodeFactory;
protected final ICPPSecondaryParserFactory parserFactory;
/** Stack that provides easy access to the current class name, used to disambiguate declarators. */
protected final LinkedList<IASTName> classNames = new LinkedList<IASTName>();
/**
* @param parser
* @param orderedTerminalSymbols When an instance of this class is created for a parser
* that parsers token kinds will be mapped back to the base C99 parser's token kinds.
*/
public CPPBuildASTParserAction(ITokenStream parser, ScopedStack<Object> astStack, ICPPNodeFactory nodeFactory, ICPPSecondaryParserFactory parserFactory) {
super(parser, astStack, nodeFactory, parserFactory);
this.nodeFactory = nodeFactory;
this.parserFactory = parserFactory;
this.tokenMap = new TokenMap(CPPParsersym.orderedTerminalSymbols, parser.getOrderedTerminalSymbols());
}
private int baseKind(IToken token) {
return tokenMap.mapKind(token.getKind());
}
@Override
protected boolean isCompletionToken(IToken token) {
return baseKind(token) == TK_Completion;
}
@Override
protected boolean isIdentifierToken(IToken token) {
return baseKind(token) == TK_identifier;
}
@Override
protected IASTName createName(char[] image) {
return nodeFactory.newName(image);
}
public void consumeNewInitializer() {
if(astStack.peek() == null) { // if there is an empty set of parens
astStack.pop();
IASTExpression initializer = nodeFactory.newExpressionList();
setOffsetAndLength(initializer);
astStack.push(initializer);
}
}
// TODO can the new_array_expressions be removed? it looks like they parse as part of the type id
/**
* new_expression
* ::= dcolon_opt 'new' new_placement_opt new_type_id <openscope-ast> new_array_expressions_op new_initializer_opt
* | dcolon_opt 'new' new_placement_opt '(' type_id ')' <openscope-ast> new_array_expressions_op new_initializer_opt
*/
public void consumeExpressionNew(boolean isNewTypeId) {
IASTExpression initializer = (IASTExpression) astStack.pop(); // may be null
List<Object> arrayExpressions = astStack.closeScope();
IASTTypeId typeId = (IASTTypeId) astStack.pop();
IASTExpression placement = (IASTExpression) astStack.pop(); // may be null
boolean hasDoubleColon = astStack.pop() != null;
ICPPASTNewExpression newExpression = nodeFactory.newNewExpression(placement, initializer, typeId);
newExpression.setIsGlobal(hasDoubleColon);
newExpression.setIsNewTypeId(isNewTypeId);
setOffsetAndLength(newExpression);
for(Object expr : arrayExpressions)
newExpression.addNewTypeIdArrayExpression((IASTExpression)expr);
// handle ambiguities of the form: (A)(B)
if(!isNewTypeId && initializer == null &&
placement instanceof IASTIdExpression &&
typeId != null && typeId.getDeclSpecifier() instanceof IASTNamedTypeSpecifier) {
IASTName firstName = ((IASTIdExpression)placement).getName();
IASTName secondName = ((IASTNamedTypeSpecifier)typeId.getDeclSpecifier()).getName();
IASTNamedTypeSpecifier newTypeSpecifier = nodeFactory.newTypedefNameSpecifier(firstName.copy());
ParserUtil.setOffsetAndLength(newTypeSpecifier, firstName);
IASTDeclarator newDeclarator = nodeFactory.newDeclarator(nodeFactory.newName());
ParserUtil.setOffsetAndLength(newDeclarator, endOffset(firstName), 0);
IASTTypeId newTypeId = nodeFactory.newTypeId(newTypeSpecifier, newDeclarator);
ParserUtil.setOffsetAndLength(newTypeId, firstName);
IASTIdExpression newInitializer = nodeFactory.newIdExpression(secondName.copy());
ParserUtil.setOffsetAndLength(newInitializer, secondName);
ICPPASTNewExpression alternate = nodeFactory.newNewExpression(null, newInitializer, newTypeId);
ParserUtil.setOffsetAndLength(alternate, newExpression);
newExpression.setIsGlobal(hasDoubleColon);
newExpression.setIsNewTypeId(isNewTypeId);
IASTAmbiguousExpression ambiguity = createAmbiguousExpression(newExpression, alternate);
astStack.push(ambiguity);
}
else {
astStack.push(newExpression);
}
}
/**
* new_declarator -- pointer operators are part of the type id, held in an empty declarator
* ::= <openscope-ast> new_pointer_operators
*/
public void consumeNewDeclarator() {
IASTName name = nodeFactory.newName();
IASTDeclarator declarator = nodeFactory.newDeclarator(name);
for(Object pointer : astStack.closeScope())
declarator.addPointerOperator((IASTPointerOperator)pointer);
setOffsetAndLength(declarator);
astStack.push(declarator);
}
/**
* throw_expression
* ::= 'throw'
* | 'throw' assignment_expression
*/
public void consumeExpressionThrow(boolean hasExpr) {
IASTExpression operand = hasExpr ? (IASTExpression) astStack.pop() : null;
IASTUnaryExpression expr = nodeFactory.newUnaryExpression(ICPPASTUnaryExpression.op_throw, operand);
setOffsetAndLength(expr);
astStack.push(expr);
}
/**
* delete_expression
* ::= dcolon_opt 'delete' cast_expression
* | dcolon_opt 'delete' '[' ']' cast_expression
* @param isVectorized
*/
public void consumeExpressionDelete(boolean isVectorized) {
IASTExpression operand = (IASTExpression) astStack.pop();
boolean hasDoubleColon = astStack.pop() != null;
ICPPASTDeleteExpression deleteExpr = nodeFactory.newDeleteExpression(operand);
deleteExpr.setIsGlobal(hasDoubleColon);
deleteExpr.setIsVectored(isVectorized);
setOffsetAndLength(deleteExpr);
astStack.push(deleteExpr);
}
/**
*
*/
public void consumeExpressionFieldReference(boolean isPointerDereference, boolean hasTemplateKeyword) {
IASTName name = (IASTName) astStack.pop();
IASTExpression owner = (IASTExpression) astStack.pop();
ICPPASTFieldReference expr = nodeFactory.newFieldReference(name, owner);
expr.setIsPointerDereference(isPointerDereference);
expr.setIsTemplate(hasTemplateKeyword);
setOffsetAndLength(expr);
astStack.push(expr);
}
/**
* postfix_expression
* ::= simple_type_specifier '(' expression_list_opt ')'
*/
public void consumeExpressionSimpleTypeConstructor() {
IASTExpression expression = (IASTExpression) astStack.pop();
IToken token = (IToken) astStack.pop();
////CDT_70_FIX_FROM_50-#3
//int type = asICPPASTSimpleTypeConstructorExpressionType(token);
ICPPASTConstructorInitializer init=null;
if(expression!=null){
init = new CPPASTConstructorInitializer();
init.setExpression(expression);
((ASTNode)init).setOffsetAndLength(((ASTNode)expression).getOffset(),((ASTNode)expression).getLength());
}
ICPPASTDeclSpecifier declspec = transformIntoSimpleTypeSpecifier(token);
ICPPASTSimpleTypeConstructorExpression typeConstructor = nodeFactory.newSimpleTypeConstructorExpression(declspec, init);
setOffsetAndLength(typeConstructor);
astStack.push(typeConstructor);
}
private int asICPPASTSimpleTypeConstructorExpressionType(IToken token) {
assert token != null;
switch(baseKind(token)) {
case TK_char : return ICPPASTSimpleTypeConstructorExpression.t_char;
case TK_wchar_t : return ICPPASTSimpleTypeConstructorExpression.t_wchar_t;
case TK_bool : return ICPPASTSimpleTypeConstructorExpression.t_bool;
case TK_short : return ICPPASTSimpleTypeConstructorExpression.t_short;
case TK_int : return ICPPASTSimpleTypeConstructorExpression.t_int;
case TK_long : return ICPPASTSimpleTypeConstructorExpression.t_long;
case TK_signed : return ICPPASTSimpleTypeConstructorExpression.t_signed;
case TK_unsigned : return ICPPASTSimpleTypeConstructorExpression.t_unsigned;
case TK_float : return ICPPASTSimpleTypeConstructorExpression.t_float;
case TK_double : return ICPPASTSimpleTypeConstructorExpression.t_double;
case TK_void : return ICPPASTSimpleTypeConstructorExpression.t_void;
default:
assert false : "type parsed wrong"; //$NON-NLS-1$
return ICPPASTSimpleTypeConstructorExpression.t_unspecified;
}
}
private ICPPASTDeclSpecifier transformIntoSimpleTypeSpecifier(IToken token){
ICPPASTSimpleDeclSpecifier declspec= nodeFactory.newSimpleDeclSpecifier();
switch(baseKind(token)) {
case TK_char : declspec.setType(Kind.eChar); break;
case TK_wchar_t : declspec.setType(Kind.eWChar); break;
case TK_bool : declspec.setType(Kind.eBoolean);break;
case TK_short : declspec.setShort(true); break;
case TK_int : declspec.setType(Kind.eInt); break;
case TK_long : declspec.setLong(true); break;
case TK_signed : declspec.setSigned(true); break;
case TK_unsigned : declspec.setUnsigned(true); break;
case TK_float : declspec.setType(Kind.eFloat); break;
case TK_double : declspec.setType(Kind.eDouble); break;
case TK_void : declspec.setType(Kind.eVoid); break;
default:
assert false : "type parsed wrong"; //$NON-NLS-1$
declspec.setType(Kind.eUnspecified);
break;
}
((ASTNode) declspec).setOffset(token.getStartOffset());
int ruleLength = token.getEndOffset() - token.getStartOffset();
((ASTNode) declspec).setLength(ruleLength < 0 ? 0 : ruleLength);
return declspec;
}
/**
* postfix_expression
* ::= 'typename' dcolon_opt nested_name_specifier <empty> identifier_name '(' expression_list_opt ')'
* | 'typename' dcolon_opt nested_name_specifier template_opt template_id '(' expression_list_opt ')'
*/
@SuppressWarnings("unchecked")
public void consumeExpressionTypeName() {
IASTExpression expr = (IASTExpression) astStack.pop();
IASTName name = (IASTName) astStack.pop();
boolean isTemplate = astStack.pop() == PLACE_HOLDER;
LinkedList<IASTName> nestedNames = (LinkedList<IASTName>) astStack.pop();
IToken dColon = (IToken) astStack.pop();
nestedNames.addFirst(name);
int startOffset = dColon == null ? offset(nestedNames.getLast()) : offset(dColon);
int endOffset = endOffset(name);
IASTName qualifiedName = createQualifiedName(nestedNames, startOffset, endOffset, dColon != null);
ICPPASTTypenameExpression typenameExpr = nodeFactory.newTypenameExpression(qualifiedName, expr, isTemplate);
setOffsetAndLength(typenameExpr);
astStack.push(typenameExpr);
}
/**
* condition
* ::= type_specifier_seq declarator '=' assignment_expression
*/
public void consumeConditionDeclaration() {
IASTExpression expr = (IASTExpression) astStack.pop();
IASTDeclarator declarator = (IASTDeclarator) astStack.pop();
IASTDeclSpecifier declSpec = (IASTDeclSpecifier) astStack.pop();
//CDT_70_FIX_FROM_50-#2
//IASTInitializerExpression initializer = nodeFactory.newInitializerExpression(expr);
IASTEqualsInitializer initializer = nodeFactory.newEqualsInitializer(expr);
ParserUtil.setOffsetAndLength(initializer, offset(expr), length(expr));
declarator.setInitializer(initializer);
IASTSimpleDeclaration declaration = nodeFactory.newSimpleDeclaration(declSpec);
declaration.addDeclarator(declarator);
setOffsetAndLength(declaration);
astStack.push(declaration);
}
/**
* template_id
* ::= identifier_name '<' <openscope-ast> template_argument_list_opt '>'
*
* operator_function_id
* ::= operator_id '<' <openscope-ast> template_argument_list_opt '>'
*/
public void consumeTemplateId() {
List<Object> templateArguments = astStack.closeScope();
IASTName name = (IASTName) astStack.pop();
ICPPASTTemplateId templateId = nodeFactory.newTemplateId(name);
for(Object arg : templateArguments) {
if(arg instanceof IASTExpression)
templateId.addTemplateArgument((IASTExpression)arg);
else if(arg instanceof IASTTypeId)
templateId.addTemplateArgument((IASTTypeId)arg);
else if(arg instanceof ICPPASTAmbiguousTemplateArgument)
templateId.addTemplateArgument((ICPPASTAmbiguousTemplateArgument)arg);
}
setOffsetAndLength(templateId);
astStack.push(templateId);
}
/**
* Disambiguates template arguments.
*/
public void consumeTemplateArgumentTypeId() {
// TODO is this necessary? It should be able to tell if it looks like an id expression
ISecondaryParser<IASTExpression> secondaryParser = parserFactory.getExpressionParser(stream, properties);
IASTExpression result = runSecondaryParser(secondaryParser);
// The grammar rule allows assignment_expression, but the ambiguity
// only arises with id_expressions.
if(!(result instanceof IASTIdExpression))
return;
IASTTypeId typeId = (IASTTypeId) astStack.pop();
IASTIdExpression expr = (IASTIdExpression) result;
ICPPASTAmbiguousTemplateArgument ambiguityNode = new CPPASTAmbiguousTemplateArgument(typeId, expr);
//setOffsetAndLength(ambiguityNode);
astStack.push(ambiguityNode);
}
/**
* Disambiguates template arguments.
* Qualified names parse as an expression, so generate the corresponding
* typeId and create an ambiguity node.
*/
public void consumeTemplateArgumentExpression() {
IASTExpression expr = (IASTExpression) astStack.peek();
if(expr instanceof IASTIdExpression) {
IASTName name = ((IASTIdExpression)expr).getName().copy();
IASTNamedTypeSpecifier declSpec = nodeFactory.newTypedefNameSpecifier(name);
ParserUtil.setOffsetAndLength(declSpec, name);
IASTDeclarator declarator = nodeFactory.newDeclarator(nodeFactory.newName());
ParserUtil.setOffsetAndLength(declarator, endOffset(declSpec), 0);
IASTTypeId typeId = nodeFactory.newTypeId(declSpec, declarator);
setOffsetAndLength(typeId);
ICPPASTAmbiguousTemplateArgument ambiguityNode = new CPPASTAmbiguousTemplateArgument(typeId, expr);
astStack.pop();
astStack.push(ambiguityNode);
}
}
/**
* operator_id
* ::= 'operator' overloadable_operator
*/
public void consumeOperatorName() {
List<IToken> tokens = stream.getRuleTokens();
tokens = tokens.subList(1, tokens.size());
OverloadableOperator operator = getOverloadableOperator(tokens);
ICPPASTOperatorName name = nodeFactory.newOperatorName(operator.toCharArray());
setOffsetAndLength(name);
astStack.push(name);
}
private OverloadableOperator getOverloadableOperator(List<IToken> tokens) {
if(tokens.size() == 1) {
// TODO this is a hack that I did to save time
LPGTokenAdapter coreToken = (LPGTokenAdapter) tokens.get(0);
return OverloadableOperator.valueOf(coreToken.getWrappedToken());
}
else if(matchTokens(tokens, tokenMap, TK_new, TK_LeftBracket, TK_RightBracket)) {
return OverloadableOperator.NEW_ARRAY;
}
else if(matchTokens(tokens, tokenMap, TK_delete, TK_LeftBracket, TK_RightBracket)) {
return OverloadableOperator.DELETE_ARRAY;
}
else if(matchTokens(tokens, tokenMap, TK_LeftBracket, TK_RightBracket)) {
return OverloadableOperator.BRACKET;
}
else if(matchTokens(tokens, tokenMap, TK_LeftParen, TK_RightParen)) {
return OverloadableOperator.PAREN;
}
return null;
}
/**
* conversion_function_id
* ::= 'operator' conversion_type_id
*/
public void consumeConversionName() {
// Representation is computed by the conversion name itself, see bug 258054
// String rep = createStringRepresentation(parser.getRuleTokens());
// char[] chars = rep.toCharArray();
IASTTypeId typeId = (IASTTypeId) astStack.pop();
ICPPASTConversionName name = nodeFactory.newConversionName(typeId);
setOffsetAndLength(name);
astStack.push(name);
}
/**
* unqualified_id
* ::= '~' identifier_token
*/
public void consumeDestructorName() {
char[] chars = ("~" + stream.getRightIToken()).toCharArray(); //$NON-NLS-1$
IASTName name = nodeFactory.newName(chars);
setOffsetAndLength(name);
astStack.push(name);
}
/**
* destructor_type_name
* ::= '~' template_id_name
*/
public void consumeDestructorNameTemplateId() {
ICPPASTTemplateId templateId = (ICPPASTTemplateId) astStack.peek();
IASTName oldName = templateId.getTemplateName();
char[] newChars = ("~" + oldName).toCharArray(); //$NON-NLS-1$
IASTName newName = nodeFactory.newName(newChars);
int offset = offset(stream.getLeftIToken());
int length = offset - endOffset(oldName);
ParserUtil.setOffsetAndLength(newName, offset, length);
templateId.setTemplateName(newName);
}
/**
* qualified_id
* ::= '::' identifier_name
* | '::' operator_function_id
* | '::' template_id
*/
public void consumeGlobalQualifiedId() {
IASTName name = (IASTName) astStack.pop();
ICPPASTQualifiedName qualifiedName = nodeFactory.newQualifiedName();
qualifiedName.addName(name);
qualifiedName.setFullyQualified(true);
setOffsetAndLength(qualifiedName);
astStack.push(qualifiedName);
}
/**
* selection_statement ::= switch '(' condition ')' statement
*/
public void consumeStatementSwitch() {
IASTStatement body = (IASTStatement) astStack.pop();
Object condition = astStack.pop();
IASTSwitchStatement stat;
if(condition instanceof IASTExpression)
stat = nodeFactory.newSwitchStatement((IASTExpression)condition, body);
else
stat = nodeFactory.newSwitchStatement((IASTDeclaration)condition, body);
setOffsetAndLength(stat);
astStack.push(stat);
}
public void consumeStatementIf(boolean hasElse) {
IASTStatement elseClause = hasElse ? (IASTStatement)astStack.pop() : null;
IASTStatement thenClause = (IASTStatement) astStack.pop();
Object condition = astStack.pop();
IASTIfStatement ifStatement;
if(condition instanceof IASTExpression)
ifStatement = nodeFactory.newIfStatement((IASTExpression)condition, thenClause, elseClause);
else
ifStatement = nodeFactory.newIfStatement((IASTDeclaration)condition, thenClause, elseClause);
setOffsetAndLength(ifStatement);
astStack.push(ifStatement);
}
/**
* iteration_statement ::= 'while' '(' condition ')' statement
*/
public void consumeStatementWhileLoop() {
IASTStatement body = (IASTStatement) astStack.pop();
Object condition = astStack.pop();
IASTWhileStatement whileStatement;
if(condition instanceof IASTExpression)
whileStatement = nodeFactory.newWhileStatement((IASTExpression)condition, body);
else
whileStatement = nodeFactory.newWhileStatement((IASTDeclaration)condition, body);
setOffsetAndLength(whileStatement);
astStack.push(whileStatement);
}
/**
*/
public void consumeStatementForLoop() {
IASTStatement body = (IASTStatement) astStack.pop();
IASTExpression expr = (IASTExpression) astStack.pop();
Object condition = astStack.pop(); // can be an expression or a declaration
IASTStatement initializer = (IASTStatement) astStack.pop();
// bug 234463, fix for content assist to work in this case
int TK_EOC = TK_EndOfCompletion; // TODO: change this in the grammar file
List<IToken> tokens = stream.getRuleTokens();
if(matchTokens(tokens, tokenMap,
TK_for, TK_LeftParen, TK_Completion, TK_EOC, TK_EOC, TK_EOC, TK_EOC)) {
IASTName name = createName(tokens.get(2));
IASTIdExpression idExpression = nodeFactory.newIdExpression(name);
ParserUtil.setOffsetAndLength(idExpression, offset(name), length(name));
initializer = nodeFactory.newExpressionStatement(idExpression);
ParserUtil.setOffsetAndLength(initializer, offset(name), length(name));
}
IASTForStatement forStat;
if(condition instanceof IASTExpression)
forStat = nodeFactory.newForStatement(initializer, (IASTExpression)condition, expr, body);
else // its a declaration or its null
forStat = nodeFactory.newForStatement(initializer, (IASTDeclaration)condition, expr, body);
setOffsetAndLength(forStat);
astStack.push(forStat);
}
/**
* try_block
* ::= 'try' compound_statement <openscope-ast> handler_seq
*/
public void consumeStatementTryBlock(boolean hasCatchBlock) {
List<Object> handlerSeq = hasCatchBlock ? astStack.closeScope() : Collections.emptyList();
IASTStatement body = (IASTStatement) astStack.pop();
ICPPASTTryBlockStatement tryStatement = nodeFactory.newTryBlockStatement(body);
for(Object handler : handlerSeq)
tryStatement.addCatchHandler((ICPPASTCatchHandler)handler);
setOffsetAndLength(tryStatement);
astStack.push(tryStatement);
}
/**
* handler
* ::= 'catch' '(' exception_declaration ')' compound_statement
* | 'catch' '(' '...' ')' compound_statement
*/
public void consumeStatementCatchHandler(boolean hasEllipsis) {
IASTStatement body = (IASTStatement) astStack.pop();
IASTDeclaration decl = hasEllipsis ? null : (IASTDeclaration) astStack.pop();
ICPPASTCatchHandler catchHandler = nodeFactory.newCatchHandler(decl, body);
catchHandler.setIsCatchAll(hasEllipsis);
setOffsetAndLength(catchHandler);
astStack.push(catchHandler);
}
/**
* nested_name_specifier
* ::= class_or_namespace_name '::' nested_name_specifier_with_template
* | class_or_namespace_name '::'
*
* nested_name_specifier_with_template
* ::= class_or_namespace_name_with_template '::' nested_name_specifier_with_template
* | class_or_namespace_name_with_template '::'
*
*
* Creates and updates a list of the nested names on the stack.
* Important: the names in the list are in *reverse* order,
* this is because the actions fire in reverse order.
*/
@SuppressWarnings("unchecked")
public void consumeNestedNameSpecifier(final boolean hasNested) {
LinkedList<IASTName> names;
if(hasNested)
names = (LinkedList<IASTName>) astStack.pop();
else
names = new LinkedList<IASTName>();
IASTName name = (IASTName) astStack.pop();
names.add(name);
astStack.push(names);
}
public void consumeNestedNameSpecifierEmpty() {
// can't use Collections.EMPTY_LIST because we need a list thats mutable
astStack.push(new LinkedList<IASTName>());
}
/**
* The template keyword is optional but must be the leftmost token.
*
* This just throws away the template keyword.
*/
public void consumeNameWithTemplateKeyword() {
IASTName name = (IASTName) astStack.pop();
astStack.pop(); // pop the template keyword
astStack.push(name);
}
/**
* qualified_id
* ::= dcolon_opt nested_name_specifier any_name
*/
public void consumeQualifiedId(boolean hasTemplateKeyword) {
IASTName qualifiedName = subRuleQualifiedName(hasTemplateKeyword);
astStack.push(qualifiedName);
}
private IASTName createQualifiedName(LinkedList<IASTName> nestedNames, int startOffset, int endOffset, boolean startsWithColonColon) {
return createQualifiedName(nestedNames, startOffset, endOffset, startsWithColonColon, false);
}
/**
* Creates a qualified name from a list of names (that must be in reverse order).
*
* @param names List of name nodes in reverse order
*/
private IASTName createQualifiedName(LinkedList<IASTName> names, int startOffset, int endOffset, boolean startsWithColonColon, boolean endsWithColonColon) {
if(!endsWithColonColon && !startsWithColonColon && names.size() == 1)
return names.getFirst(); // its actually an unqualified name
ICPPASTQualifiedName qualifiedName = nodeFactory.newQualifiedName();
qualifiedName.setFullyQualified(startsWithColonColon);
ParserUtil.setOffsetAndLength(qualifiedName, startOffset, endOffset - startOffset);
for(IASTName name : reverseIterable(names))
qualifiedName.addName(name);
// there must be a dummy name in the AST after the last double colon, this happens with pointer to member names
if(endsWithColonColon) {
IASTName dummyName = nodeFactory.newName();
ParserUtil.setOffsetAndLength(dummyName, endOffset, 0);
qualifiedName.addName(dummyName);
}
return qualifiedName;
}
/**
* Consumes grammar sub-rules of the following form:
*
* dcolon_opt nested_name_specifier_opt keyword_opt name
*
* Where name is any rule that produces an IASTName node on the stack.
* Does not place the resulting node on the stack, returns it instead.
*/
@SuppressWarnings("unchecked")
private IASTName subRuleQualifiedName(boolean hasOptionalKeyword) {
IASTName lastName = (IASTName) astStack.pop();
if(hasOptionalKeyword) // this is usually a template keyword and can be ignored
astStack.pop();
LinkedList<IASTName> nestedNames = (LinkedList<IASTName>) astStack.pop();
IToken dColon = (IToken) astStack.pop();
if(nestedNames.isEmpty() && dColon == null) { // then its not a qualified name
return lastName;
}
nestedNames.addFirst(lastName); // the list of names is in reverse order
int startOffset = dColon == null ? offset(nestedNames.getLast()) : offset(dColon);
int endOffset = endOffset(lastName);
return createQualifiedName(nestedNames, startOffset, endOffset, dColon != null);
}
/**
* pseudo_destructor_name
* ::= dcolon_opt nested_name_specifier_opt type_name '::' destructor_type_name
* | dcolon_opt nested_name_specifier 'template' template_id '::' destructor_type_name
* | dcolon_opt nested_name_specifier_opt destructor_type_name
*/
@SuppressWarnings("unchecked")
public void consumePsudoDestructorName(boolean hasExtraTypeName) {
IASTName destructorTypeName = (IASTName) astStack.pop();
IASTName extraName = hasExtraTypeName ? (IASTName) astStack.pop() : null;
LinkedList<IASTName> nestedNames = (LinkedList<IASTName>) astStack.pop();
IToken dColon = (IToken) astStack.pop();
if(hasExtraTypeName)
nestedNames.addFirst(extraName);
nestedNames.addFirst(destructorTypeName);
int startOffset = dColon == null ? offset(nestedNames.getLast()) : offset(dColon);
int endOffset = endOffset(destructorTypeName);
IASTName qualifiedName = createQualifiedName(nestedNames, startOffset, endOffset, dColon != null);
setOffsetAndLength(qualifiedName);
astStack.push(qualifiedName);
}
/**
* namespace_alias_definition
* ::= 'namespace' 'identifier' '=' dcolon_opt nested_name_specifier_opt namespace_name ';'
*/
public void consumeNamespaceAliasDefinition() {
IASTName qualifiedName = subRuleQualifiedName(false);
IASTName alias = createName(stream.getRuleTokens().get(1));
ICPPASTNamespaceAlias namespaceAlias = nodeFactory.newNamespaceAlias(alias, qualifiedName);
setOffsetAndLength(namespaceAlias);
astStack.push(namespaceAlias);
}
/**
* using_declaration
* ::= 'using' typename_opt dcolon_opt nested_name_specifier_opt unqualified_id ';'
*/
public void consumeUsingDeclaration() {
IASTName qualifiedName = subRuleQualifiedName(false);
boolean hasTypenameKeyword = astStack.pop() == PLACE_HOLDER;
ICPPASTUsingDeclaration usingDeclaration = nodeFactory.newUsingDeclaration(qualifiedName);
usingDeclaration.setIsTypename(hasTypenameKeyword);
setOffsetAndLength(usingDeclaration);
astStack.push(usingDeclaration);
}
/**
* using_directive
* ::= 'using' 'namespace' dcolon_opt nested_name_specifier_opt namespace_name ';'
*/
public void consumeUsingDirective() {
IASTName qualifiedName = subRuleQualifiedName(false);
ICPPASTUsingDirective usingDirective = nodeFactory.newUsingDirective(qualifiedName);
setOffsetAndLength(usingDirective);
astStack.push(usingDirective);
}
/**
* linkage_specification
* ::= 'extern' 'stringlit' '{' <openscope-ast> declaration_seq_opt '}'
* | 'extern' 'stringlit' <openscope-ast> declaration
*/
public void consumeLinkageSpecification() {
String name = stream.getRuleTokens().get(1).toString();
ICPPASTLinkageSpecification linkageSpec = nodeFactory.newLinkageSpecification(name);
for(Object declaration : astStack.closeScope())
linkageSpec.addDeclaration((IASTDeclaration)declaration);
setOffsetAndLength(linkageSpec);
astStack.push(linkageSpec);
}
/**
* original_namespace_definition
* ::= 'namespace' identifier_name '{' <openscope-ast> declaration_seq_opt '}'
*
* extension_namespace_definition
* ::= 'namespace' original_namespace_name '{' <openscope-ast> declaration_seq_opt '}'
*
* unnamed_namespace_definition
* ::= 'namespace' '{' <openscope-ast> declaration_seq_opt '}'
*/
public void consumeNamespaceDefinition(boolean hasName) {
List<Object> declarations = astStack.closeScope();
IASTName namespaceName = hasName ? (IASTName)astStack.pop() : nodeFactory.newName();
ICPPASTNamespaceDefinition definition = nodeFactory.newNamespaceDefinition(namespaceName);
for(Object declaration : declarations)
definition.addDeclaration((IASTDeclaration)declaration);
setOffsetAndLength(definition);
astStack.push(definition);
}
/**
* template_declaration
* ::= export_opt 'template' '<' <openscope-ast> template_parameter_list '>' declaration
*/
public void consumeTemplateDeclaration() {
IASTDeclaration declaration = (IASTDeclaration) astStack.pop();
// For some reason ambiguous declarators cause bugs when they are a part of a template declaration.
// But it shouldn't be ambiguous anyway, so just throw away the ambiguity node.
resolveAmbiguousDeclaratorsToFunction(declaration);
ICPPASTTemplateDeclaration templateDeclaration = nodeFactory.newTemplateDeclaration(declaration);
for(Object param : astStack.closeScope())
templateDeclaration.addTemplateParamter((ICPPASTTemplateParameter)param);
boolean hasExportKeyword = astStack.pop() == PLACE_HOLDER;
templateDeclaration.setExported(hasExportKeyword);
setOffsetAndLength(templateDeclaration);
astStack.push(templateDeclaration);
}
/**
* If we know that a declarator must be a function declarator then we can resolve
* the ambiguity without resorting to binding resolution.
*/
private static void resolveAmbiguousDeclaratorsToFunction(IASTDeclaration declaration) {
if(declaration instanceof IASTSimpleDeclaration) {
for(IASTDeclarator declarator : ((IASTSimpleDeclaration)declaration).getDeclarators()) {
if(declarator instanceof CPPASTAmbiguousDeclarator) {
IASTAmbiguityParent owner = (IASTAmbiguityParent) declaration;
CPPASTAmbiguousDeclarator ambiguity = (CPPASTAmbiguousDeclarator)declarator;
owner.replace(ambiguity, ambiguity.getDeclarators()[0]);
}
}
}
}
/**
* explicit_instantiation
* ::= 'template' declaration
*/
public void consumeTemplateExplicitInstantiation() {
IASTDeclaration declaration = (IASTDeclaration) astStack.pop();
ICPPASTExplicitTemplateInstantiation instantiation = nodeFactory.newExplicitTemplateInstantiation(declaration);
setOffsetAndLength(instantiation);
astStack.push(instantiation);
}
/**
* explicit_specialization
* ::= 'template' '<' '>' declaration
*/
public void consumeTemplateExplicitSpecialization() {
IASTDeclaration declaration = (IASTDeclaration) astStack.pop();
ICPPASTTemplateSpecialization specialization = nodeFactory.newTemplateSpecialization(declaration);
setOffsetAndLength(specialization);
astStack.push(specialization);
}
/**
* Sets a token specifier.
* Needs to be overrideable for new decl spec keywords.
*
* @param token Allows subclasses to override this method and use any
* object to determine how to set a specifier.
*/
public void setSpecifier(ICPPASTDeclSpecifier node, Object specifier) {
if(!(specifier instanceof IToken))
return;
IToken token = (IToken)specifier;
int kind = baseKind(token);
switch(kind){
case TK_typedef: node.setStorageClass(IASTDeclSpecifier.sc_typedef); return;
case TK_extern: node.setStorageClass(IASTDeclSpecifier.sc_extern); return;
case TK_static: node.setStorageClass(IASTDeclSpecifier.sc_static); return;
case TK_auto: node.setStorageClass(IASTDeclSpecifier.sc_auto); return;
case TK_register: node.setStorageClass(IASTDeclSpecifier.sc_register); return;
case TK_mutable: node.setStorageClass(ICPPASTDeclSpecifier.sc_mutable); return;
case TK_inline: node.setInline(true); return;
case TK_const: node.setConst(true); return;
case TK_friend: node.setFriend(true); return;
case TK_virtual: node.setVirtual(true); return;
case TK_volatile: node.setVolatile(true); return;
case TK_explicit: node.setExplicit(true); return;
}
if(node instanceof ICPPASTSimpleDeclSpecifier) {
ICPPASTSimpleDeclSpecifier n = (ICPPASTSimpleDeclSpecifier) node;
switch(kind) {
case TK_void: n.setType(IASTSimpleDeclSpecifier.t_void); return;
case TK_char: n.setType(IASTSimpleDeclSpecifier.t_char); return;
case TK_int: n.setType(IASTSimpleDeclSpecifier.t_int); return;
case TK_float: n.setType(IASTSimpleDeclSpecifier.t_float); return;
case TK_double: n.setType(IASTSimpleDeclSpecifier.t_double); return;
case TK_bool: n.setType(ICPPASTSimpleDeclSpecifier.t_bool); return;
case TK_wchar_t: n.setType(ICPPASTSimpleDeclSpecifier.t_wchar_t); return;
case TK_signed: n.setSigned(true); return;
case TK_unsigned: n.setUnsigned(true); return;
//if it is a longlong, donot set long, CDT_70_FIX_FROM_50-#8
case TK_long: if(!n.isLongLong()) n.setLong(true); return;
case TK_short: n.setShort(true); return;
}
}
}
public void consumeDeclarationSpecifiersSimple() {
ICPPASTDeclSpecifier declSpec = nodeFactory.newSimpleDeclSpecifier();
for(Object token : astStack.closeScope())
setSpecifier(declSpec, token);
setOffsetAndLength(declSpec);
astStack.push(declSpec);
}
/**
* TODO: maybe move this into the superclass
*/
public void consumeDeclarationSpecifiersComposite() {
List<Object> topScope = astStack.closeScope();
// There's already a composite or elaborated or enum type specifier somewhere on the stack, find it.
ICPPASTDeclSpecifier declSpec = findFirstAndRemove(topScope, ICPPASTDeclSpecifier.class);
// now apply the rest of the specifiers
for(Object token : topScope)
setSpecifier(declSpec, token);
setOffsetAndLength(declSpec);
astStack.push(declSpec);
}
// /**
// * declaration_specifiers ::= <openscope> type_name_declaration_specifiers
// */
public void consumeDeclarationSpecifiersTypeName() {
List<Object> topScope = astStack.closeScope();
// There's a name somewhere on the stack, find it
IASTName typeName = findFirstAndRemove(topScope, IASTName.class);
// TODO what does the second argument mean?
ICPPASTNamedTypeSpecifier declSpec = nodeFactory.newTypedefNameSpecifier(typeName);
// now apply the rest of the specifiers
for(Object token : topScope) {
setSpecifier(declSpec, token);
}
// the only way there could be a typename token
for(IToken token : stream.getRuleTokens()) {
if(baseKind(token) == TK_typename) {
declSpec.setIsTypename(true);
break;
}
}
setOffsetAndLength(declSpec);
astStack.push(declSpec);
}
/**
* elaborated_type_specifier
* ::= class_keyword dcolon_opt nested_name_specifier_opt identifier_name
* | class_keyword dcolon_opt nested_name_specifier_opt template_opt template_id_name
* | 'enum' dcolon_opt nested_name_specifier_opt identifier_name
*/
public void consumeTypeSpecifierElaborated(boolean hasOptionalTemplateKeyword) {
IASTName name = subRuleQualifiedName(hasOptionalTemplateKeyword);
int kind = getElaboratedTypeSpecifier(stream.getLeftIToken());
IASTElaboratedTypeSpecifier typeSpecifier = nodeFactory.newElaboratedTypeSpecifier(kind, name);
setOffsetAndLength(typeSpecifier);
astStack.push(typeSpecifier);
}
private int getElaboratedTypeSpecifier(IToken token) {
int kind = baseKind(token);
switch(kind) {
default: assert false : "wrong token kind: " + kind; //$NON-NLS-1$
case TK_struct: return IASTElaboratedTypeSpecifier.k_struct;
case TK_union: return IASTElaboratedTypeSpecifier.k_union;
case TK_enum: return IASTElaboratedTypeSpecifier.k_enum;
case TK_class: return ICPPASTElaboratedTypeSpecifier.k_class;
}
}
/**
* simple_declaration
* ::= declaration_specifiers_opt <openscope-ast> init_declarator_list_opt ';'
*/
public void consumeDeclarationSimple(boolean hasDeclaratorList) {
List<Object> declarators = hasDeclaratorList ? astStack.closeScope() : new ArrayList<Object>();
ICPPASTDeclSpecifier declSpec = (ICPPASTDeclSpecifier) astStack.pop(); // may be null
List<IToken> ruleTokens = stream.getRuleTokens();
IToken nameToken = null;
// do not generate nodes for extra EOC tokens
if(matchTokens(ruleTokens, tokenMap, TK_EndOfCompletion)) {
return;
}
// In the case that a single completion token is parsed then it needs
// to be interpreted as a named type specifier for content assist to work.
else if(matchTokens(ruleTokens, tokenMap, TK_Completion, TK_EndOfCompletion)) {
IASTName name = createName(stream.getLeftIToken());
declSpec = nodeFactory.newTypedefNameSpecifier(name);
ParserUtil.setOffsetAndLength(declSpec, offset(name), length(name));
declarators = new ArrayList<Object>(); // throw away the bogus declarator
}
// can happen if implicit int is used
else if(declSpec == null) {
declSpec = nodeFactory.newSimpleDeclSpecifier();
ParserUtil.setOffsetAndLength(declSpec, stream.getLeftIToken().getStartOffset(), 0);
}
else if(declarators.size() == 1 && disambiguateToConstructor(declSpec, (IASTDeclarator)declarators.get(0))) { // puts results of disambiguation onto stack
declSpec = (ICPPASTDeclSpecifier) astStack.pop();
declarators = Arrays.asList(astStack.pop());
}
// bug 80171, check for situation similar to: static var;
// this will get parsed wrong, the following is a hack to rebuild the AST as it should have been parsed
// exclude syntax "friend xxx"
else if(declarators.isEmpty() &&
declSpec instanceof ICPPASTNamedTypeSpecifier && ! declSpec.isFriend() &&
ruleTokens.size() >= 2 &&
baseKind(nameToken = ruleTokens.get(ruleTokens.size() - 2)) == TK_identifier) {
declSpec = nodeFactory.newSimpleDeclSpecifier();
for(IToken t : ruleTokens.subList(0, ruleTokens.size()-1))
setSpecifier(declSpec, t);
int offset = offset(stream.getLeftIToken());
int length = endOffset(ruleTokens.get(ruleTokens.size()-2)) - offset;
ParserUtil.setOffsetAndLength(declSpec, offset, length);
IASTName name = createName(nameToken);
IASTDeclarator declarator = nodeFactory.newDeclarator(name);
ParserUtil.setOffsetAndLength(declarator, nameToken);
declarators.add(declarator);
}
IASTSimpleDeclaration declaration = nodeFactory.newSimpleDeclaration(declSpec);
setOffsetAndLength(declaration);
for(Object declarator : declarators)
declaration.addDeclarator((IASTDeclarator)declarator);
// simple ambiguity resolutions
// if(declSpecifier.isFriend())
// resolveAmbiguousDeclaratorsToFunction(declaration);
//
// if(declSpecifier instanceof IASTSimpleDeclSpecifier) {
// IASTSimpleDeclSpecifier simple = (IASTSimpleDeclSpecifier) declSpecifier;
// if(simple.getType() == IASTSimpleDeclSpecifier.t_void && declaration.getDeclarators()[0].getPointerOperators().length == 0)
// resolveAmbiguousDeclaratorsToFunction(declaration);
//
// }
astStack.push(declaration);
}
private boolean disambiguateToConstructor(IASTDeclSpecifier declSpec, IASTDeclarator declarator) {
if(!(declSpec instanceof IASTNamedTypeSpecifier))
return false;
IASTNamedTypeSpecifier namedTypeSpecifier = (IASTNamedTypeSpecifier) declSpec;
IASTName name = namedTypeSpecifier.getName();
IASTDeclarator nested = declarator.getNestedDeclarator();
ICPPASTSimpleDeclSpecifier simpleDeclSpec = nodeFactory.newSimpleDeclSpecifier(); // empty
ParserUtil.setOffsetAndLength(simpleDeclSpec, stream.getLeftIToken().getStartOffset(), 0);
if(!classNames.isEmpty() && nested != null && ParserUtil.isSameName(name, classNames.getLast())) {
IASTName paramTypeName = nested.getName(); // reuse the parameter name node
IASTNamedTypeSpecifier paramName = nodeFactory.newTypedefNameSpecifier(paramTypeName);
ParserUtil.setOffsetAndLength(paramName, paramTypeName);
IASTDeclarator paramDeclarator = nodeFactory.newDeclarator(nodeFactory.newName());
ParserUtil.setOffsetAndLength(paramDeclarator, offset(paramName) + length(paramName), 0);
ICPPASTParameterDeclaration parameter = nodeFactory.newParameterDeclaration(paramName, paramDeclarator);
ParserUtil.setOffsetAndLength(parameter, paramName);
ICPPASTFunctionDeclarator constructorDeclarator = nodeFactory.newFunctionDeclarator(name); // reuse the name node
constructorDeclarator.addParameterDeclaration(parameter);
ParserUtil.setOffsetAndLength(constructorDeclarator, offset(simpleDeclSpec), endOffset(paramDeclarator) - offset(simpleDeclSpec) + 1);
astStack.push(constructorDeclarator);
astStack.push(simpleDeclSpec);
return true;
}
if(declarator instanceof IASTFunctionDeclarator && declarator.getName() instanceof ICPPASTQualifiedName) {
ICPPASTQualifiedName qualifiedName = (ICPPASTQualifiedName) declarator.getName();
//IASTName lastName = qualifiedName.getLastName();
if(qualifiedName.isFullyQualified()) {
ICPPASTQualifiedName newQualifiedName = nodeFactory.newQualifiedName();
newQualifiedName.addName(name);
for(IASTName n : qualifiedName.getNames())
newQualifiedName.addName(n);
ParserUtil.setOffsetAndLength(newQualifiedName, offset(name), endOffset(qualifiedName.getLastName()) - offset(name));
declarator.setName(newQualifiedName);
ParserUtil.setOffsetAndLength(declarator, offset(name), length(declarator) + offset(declarator) - offset(name));
astStack.push(declarator);
astStack.push(simpleDeclSpec);
return true;
}
}
return false;
}
public void consumeInitDeclaratorComplete() {
// Don't do disambiguation when parsing for content assist,
// trust me this makes things work out a lot better.
if(completionNode != null)
return;
IASTDeclarator declarator = (IASTDeclarator) astStack.peek();
if(!(declarator instanceof IASTFunctionDeclarator))
return;
ISecondaryParser<IASTDeclarator> secondaryParser = parserFactory.getNoFunctionDeclaratorParser(stream, properties);
IASTDeclarator notFunctionDeclarator = runSecondaryParser(secondaryParser);
if(notFunctionDeclarator == null)
return;
astStack.pop();
IASTNode ambiguityNode = new CPPASTAmbiguousDeclarator(declarator, notFunctionDeclarator);
setOffsetAndLength(ambiguityNode);
astStack.push(ambiguityNode);
}
/**
* visibility_label
* ::= access_specifier_keyword ':'
*/
public void consumeVisibilityLabel() {
IToken specifier = (IToken)astStack.pop();
int visibility = getAccessSpecifier(specifier);
ICPPASTVisibilityLabel visibilityLabel = nodeFactory.newVisibilityLabel(visibility);
setOffsetAndLength(visibilityLabel);
astStack.push(visibilityLabel);
}
private int getAccessSpecifier(IToken token) {
int kind = baseKind(token);
switch(kind) {
default: assert false : "wrong token kind: " + kind; //$NON-NLS-1$
case TK_private: return ICPPASTVisibilityLabel.v_private;
case TK_public: return ICPPASTVisibilityLabel.v_public;
case TK_protected: return ICPPASTVisibilityLabel.v_protected;
}
}
/**
* base_specifier
* ::= dcolon_opt nested_name_specifier_opt class_name
* | 'virtual' access_specifier_keyword_opt dcolon_opt nested_name_specifier_opt class_name
* | access_specifier_keyword 'virtual' dcolon_opt nested_name_specifier_opt class_name
* | access_specifier_keyword dcolon_opt nested_name_specifier_opt class_name
*/
public void consumeBaseSpecifier(boolean hasAccessSpecifier, boolean isVirtual) {
IASTName name = subRuleQualifiedName(false);
int visibility = 0; // this is the default value that the DOM parser uses
if(hasAccessSpecifier) {
IToken accessSpecifierToken = (IToken) astStack.pop();
if(accessSpecifierToken != null)
visibility = getAccessSpecifier(accessSpecifierToken);
}
ICPPASTBaseSpecifier baseSpecifier = nodeFactory.newBaseSpecifier(name, visibility, isVirtual);
setOffsetAndLength(baseSpecifier);
astStack.push(baseSpecifier);
}
/**
* class_specifier
* ::= class_head '{' <openscope-ast> member_declaration_list_opt '}'
*/
public void consumeClassSpecifier() {
List<Object> declarations = astStack.closeScope();
// the class specifier is created by the rule for class_head
IASTCompositeTypeSpecifier classSpecifier = (IASTCompositeTypeSpecifier) astStack.peek();
for(Object declaration : declarations)
classSpecifier.addMemberDeclaration((IASTDeclaration)declaration);
setOffsetAndLength(classSpecifier);
classNames.removeLast(); // pop the stack of class names
}
/**
* class_head
* ::= class_keyword identifier_name_opt <openscope-ast> base_clause_opt
* | class_keyword template_id <openscope-ast> base_clause_opt
* | class_keyword nested_name_specifier identifier_name <openscope-ast> base_clause_opt
* | class_keyword nested_name_specifier template_id <openscope-ast> base_clause_opt
*/
@SuppressWarnings("unchecked")
public void consumeClassHead(boolean hasNestedNameSpecifier) {
int key = getCompositeTypeSpecifier(stream.getLeftIToken());
List<Object> baseSpecifiers = astStack.closeScope();
// may be null, but if it is then hasNestedNameSpecifier == false
IASTName className = (IASTName) astStack.pop();
if(hasNestedNameSpecifier) {
LinkedList<IASTName> nestedNames = (LinkedList<IASTName>) astStack.pop();
nestedNames.addFirst(className);
int startOffset = offset(nestedNames.getLast());
int endOffset = endOffset(className);
className = createQualifiedName(nestedNames, startOffset, endOffset, false);
}
if(className == null)
className = nodeFactory.newName();
ICPPASTCompositeTypeSpecifier classSpecifier = nodeFactory.newCompositeTypeSpecifier(key, className);
for(Object base : baseSpecifiers)
classSpecifier.addBaseSpecifier((ICPPASTBaseSpecifier)base);
// the offset and length are set in consumeClassSpecifier()
astStack.push(classSpecifier);
classNames.add(className); // push
}
private int getCompositeTypeSpecifier(IToken token) {
final int kind = baseKind(token);
switch(kind) {
default: assert false : "wrong token kind: " + kind; //$NON-NLS-1$
case TK_struct: return IASTCompositeTypeSpecifier.k_struct;
case TK_union: return IASTCompositeTypeSpecifier.k_union;
case TK_class: return ICPPASTCompositeTypeSpecifier.k_class;
}
}
/**
* ptr_operator
* ::= '*' <openscope-ast> cv_qualifier_seq_opt
*/
public void consumePointer() {
IASTPointer pointer = nodeFactory.newPointer();
List<Object> tokens = astStack.closeScope();
addCVQualifiersToPointer(pointer, tokens);
setOffsetAndLength(pointer);
astStack.push(pointer);
}
protected void addCVQualifiersToPointer(IASTPointer pointer, List<Object> tokens) {
for(Object t : tokens) {
switch(baseKind((IToken) t)) {
case TK_const: pointer.setConst(true); break;
case TK_volatile: pointer.setVolatile(true); break;
}
}
}
/**
* ptr_operator
* ::= '&'
*/
public void consumeReferenceOperator() {
ICPPASTReferenceOperator referenceOperator = nodeFactory.newReferenceOperator();
setOffsetAndLength(referenceOperator);
astStack.push(referenceOperator);
}
/**
* ptr_operator
* ::= dcolon_opt nested_name_specifier '*' <openscope-ast> cv_qualifier_seq_opt
*/
@SuppressWarnings("unchecked")
public void consumePointerToMember() {
List<Object> qualifiers = astStack.closeScope();
LinkedList<IASTName> nestedNames = (LinkedList<IASTName>) astStack.pop();
IToken dColon = (IToken) astStack.pop();
int startOffset = dColon == null ? offset(nestedNames.getLast()) : offset(dColon);
int endOffset = endOffset(nestedNames.getFirst()); // temporary
// find the last double colon by searching for it
for(IToken t : reverseIterable(stream.getRuleTokens())) {
if(baseKind(t) == TK_ColonColon) {
endOffset = endOffset(t);
break;
}
}
IASTName name = createQualifiedName(nestedNames, startOffset, endOffset, dColon != null, true);
ICPPASTPointerToMember pointer = nodeFactory.newPointerToMember(name);
addCVQualifiersToPointer(pointer, qualifiers);
setOffsetAndLength(pointer);
astStack.push(pointer);
}
/**
* initializer
* ::= '(' expression_list ')'
*/
public void consumeInitializerConstructor() {
//CDT_70_FIX_FROM_50-#5
Object o = astStack.pop();
IASTInitializerClause[] initClauseList =null;
if(o instanceof IASTExpressionList){
initClauseList = ((IASTExpressionList) o).getExpressions();
}else if(o instanceof IASTInitializerClause){
initClauseList = new IASTInitializerClause[]{(IASTInitializerClause)o};
}
ICPPASTConstructorInitializer initializer = nodeFactory.newConstructorInitializer(initClauseList);
setOffsetAndLength(initializer);
astStack.push(initializer);
}
/**
* function_direct_declarator
* ::= basic_direct_declarator '(' <openscope-ast> parameter_declaration_clause ')'
* <openscope-ast> cv_qualifier_seq_opt <openscope-ast> exception_specification_opt
*/
public void consumeDirectDeclaratorFunctionDeclarator(boolean hasDeclarator) {
IASTName name = nodeFactory.newName();
ICPPASTFunctionDeclarator declarator = nodeFactory.newFunctionDeclarator(name);
List<Object> typeIds = astStack.closeScope();
if(typeIds.size() == 1 && typeIds.get(0) == PLACE_HOLDER) { // fix for bug 86943
declarator.setEmptyExceptionSpecification();
}
else {
for(Object typeId : typeIds) {
declarator.addExceptionSpecificationTypeId((IASTTypeId) typeId);
}
}
for(Object token : astStack.closeScope()) {
int kind = baseKind((IToken)token);
switch(kind) {
default: assert false : "wrong token kind: " + kind; //$NON-NLS-1$
case TK_const: declarator.setConst(true); break;
case TK_volatile: declarator.setVolatile(true); break;
}
}
boolean isVarArgs = astStack.pop() == PLACE_HOLDER;
declarator.setVarArgs(isVarArgs);
for(Object o : astStack.closeScope()) {
declarator.addParameterDeclaration((IASTParameterDeclaration)o);
}
if(hasDeclarator) {
int endOffset = endOffset(stream.getRightIToken());
addFunctionModifier(declarator, endOffset);
}
else {
setOffsetAndLength(declarator);
astStack.push(declarator);
}
}
/**
* Consume an empty bracketed abstract declarator.
*/
public void consumeAbstractDeclaratorEmpty() {
IASTName name = nodeFactory.newName();
ParserUtil.setOffsetAndLength(name, offset(stream.getLeftIToken())+1, 0);
IASTDeclarator declarator = nodeFactory.newDeclarator(name);
setOffsetAndLength(declarator);
astStack.push(declarator);
}
/**
* mem_initializer
* ::= mem_initializer_id '(' expression_list_opt ')'
*/
public void consumeConstructorChainInitializer() {
IASTExpression expr = (IASTExpression) astStack.pop();
IASTName name = (IASTName) astStack.pop();
ICPPASTConstructorChainInitializer initializer = nodeFactory.newConstructorChainInitializer(name, expr);
setOffsetAndLength(initializer);
astStack.push(initializer);
}
/**
* function_definition
* ::= declaration_specifiers_opt function_direct_declarator
* <openscope-ast> ctor_initializer_list_opt function_body
*
* | declaration_specifiers_opt function_direct_declarator
* 'try' <openscope-ast> ctor_initializer_list_opt function_body <openscope-ast> handler_seq
*
*/
public void consumeFunctionDefinition(boolean isTryBlockDeclarator) {
List<Object> handlers = isTryBlockDeclarator ? astStack.closeScope() : Collections.emptyList();
IASTCompoundStatement body = (IASTCompoundStatement) astStack.pop();
List<Object> initializers = astStack.closeScope();
Object o = astStack.pop();
IASTFunctionDeclarator declarator = (IASTFunctionDeclarator) o;
Object o2 = astStack.pop();
IASTDeclSpecifier declSpec = (IASTDeclSpecifier) o2; // may be null
if(declSpec == null) { // can happen if implicit int is used
declSpec = nodeFactory.newSimpleDeclSpecifier();
ParserUtil.setOffsetAndLength(declSpec, stream.getLeftIToken().getStartOffset(), 0);
}
else if(disambiguateToConstructor(declSpec, declarator)) {
declSpec = (IASTDeclSpecifier) astStack.pop();
declarator = (IASTFunctionDeclarator) astStack.pop();
}
ICPPASTFunctionDefinition definition;
if (isTryBlockDeclarator) {
ICPPASTFunctionWithTryBlock tryblock= nodeFactory.newFunctionTryBlock(declSpec, declarator, body);
for(Object handler : handlers)
tryblock.addCatchHandler((ICPPASTCatchHandler)handler);
definition = tryblock;
} else {
definition = nodeFactory.newFunctionDefinition(declSpec, declarator, body);
}
if(initializers != null && !initializers.isEmpty()) {
for(Object initializer : initializers)
definition.addMemberInitializer((ICPPASTConstructorChainInitializer)initializer);
}
setOffsetAndLength(definition);
astStack.push(definition);
}
/**
* member_declaration
* ::= dcolon_opt nested_name_specifier template_opt unqualified_id_name ';'
*/
public void consumeMemberDeclarationQualifiedId() {
IASTName qualifiedId = subRuleQualifiedName(true);
// https://bugs.eclipse.org/bugs/show_bug.cgi?id=92793
ICPPASTUsingDeclaration declaration = nodeFactory.newUsingDeclaration(qualifiedId);
setOffsetAndLength(declaration);
astStack.push(declaration);
}
/**
* member_declarator
* ::= declarator constant_initializer
*/
public void consumeMemberDeclaratorWithInitializer() {
//CDT_70_FIX_FROM_50-#2
//IASTInitializerExpression initializer = (IASTInitializerExpression) astStack.pop();
IASTEqualsInitializer initializer = (IASTEqualsInitializer) astStack.pop();
IASTDeclarator declarator = (IASTDeclarator) astStack.peek();
setOffsetAndLength(declarator);
if(declarator instanceof ICPPASTFunctionDeclarator) {
IASTExpression expr = (IASTExpression)initializer.getInitializerClause();
if(expr instanceof IASTLiteralExpression && "0".equals(expr.toString())) { //$NON-NLS-1$
((ICPPASTFunctionDeclarator)declarator).setPureVirtual(true);
return;
}
}
declarator.setInitializer(initializer);
}
/**
* type_parameter
* ::= 'class' identifier_name_opt -- simple type template parameter
* | 'class' identifier_name_opt '=' type_id
* | 'typename' identifier_name_opt
* | 'typename' identifier_name_opt '=' type_id
*/
public void consumeSimpleTypeTemplateParameter(boolean hasTypeId) {
IASTTypeId typeId = hasTypeId ? (IASTTypeId)astStack.pop() : null;
IASTName name = (IASTName)astStack.pop();
if(name == null)
name = nodeFactory.newName();
int type = getTemplateParameterType(stream.getLeftIToken());
ICPPASTSimpleTypeTemplateParameter templateParameter = nodeFactory.newSimpleTypeTemplateParameter(type, name, typeId);
setOffsetAndLength(templateParameter);
astStack.push(templateParameter);
}
private int getTemplateParameterType(IToken token) {
int kind = baseKind(token);
switch(kind) {
default: assert false : "wrong token kind: " + kind; //$NON-NLS-1$
case TK_class: return ICPPASTSimpleTypeTemplateParameter.st_class;
case TK_typename: return ICPPASTSimpleTypeTemplateParameter.st_typename;
}
}
/**
* Simple type template parameters using the 'class' keyword are being parsed
* wrong due to an ambiguity between type_parameter and parameter_declaration.
*
* eg) template <class T>
*
* The 'class T' part is being parsed as an elaborated type specifier instead
* of a simple type template parameter.
*
* This method detects the incorrect parse, throws away the incorrect AST fragment,
* and replaces it with the correct AST fragment.
*
* Yes its a hack.
*/
public void consumeTemplateParamterDeclaration() {
ISecondaryParser<ICPPASTTemplateParameter> typeParameterParser = parserFactory.getTemplateTypeParameterParser(stream, properties);
IASTNode alternate = runSecondaryParser(typeParameterParser);
if(alternate == null)
return;
astStack.pop(); // throw away the incorrect AST
astStack.push(alternate); // replace it with the correct AST
}
/**
* type_parameter
* ::= 'template' '<' <openscope-ast> template_parameter_list '>' 'class' identifier_name_opt
* | 'template' '<' <openscope-ast> template_parameter_list '>' 'class' identifier_name_opt '=' id_expression
* @param hasIdExpr
*/
public void consumeTemplatedTypeTemplateParameter(boolean hasIdExpr) {
IASTExpression idExpression = hasIdExpr ? (IASTExpression)astStack.pop() : null;
IASTName name = (IASTName) astStack.pop();
ICPPASTTemplatedTypeTemplateParameter templateParameter = nodeFactory.newTemplatedTypeTemplateParameter(name, idExpression);
for(Object param : astStack.closeScope())
templateParameter.addTemplateParamter((ICPPASTTemplateParameter)param);
setOffsetAndLength(templateParameter);
astStack.push(templateParameter);
}
@Override
protected IASTAmbiguousExpression createAmbiguousExpression(IASTExpression... expressions) {
return new CPPASTAmbiguousExpression(expressions);
}
@Override
protected IASTAmbiguousStatement createAmbiguousStatement(IASTStatement... statements) {
return new CPPASTAmbiguousStatement(statements);
}
}