blob: a2408001604b9ce26147a5ad9c231091ca321f79 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2006, 2013 IBM Corporation and others.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* 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.endOffset;
import static org.eclipse.cdt.core.dom.lrparser.action.ParserUtil.length;
import static org.eclipse.cdt.core.dom.lrparser.action.ParserUtil.matchTokens;
import static org.eclipse.cdt.core.dom.lrparser.action.ParserUtil.offset;
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.TK_ColonColon;
import static org.eclipse.cdt.internal.core.dom.lrparser.cpp.CPPParsersym.TK_Completion;
import static org.eclipse.cdt.internal.core.dom.lrparser.cpp.CPPParsersym.TK_EndOfCompletion;
import static org.eclipse.cdt.internal.core.dom.lrparser.cpp.CPPParsersym.TK_LeftBracket;
import static org.eclipse.cdt.internal.core.dom.lrparser.cpp.CPPParsersym.TK_LeftParen;
import static org.eclipse.cdt.internal.core.dom.lrparser.cpp.CPPParsersym.TK_RightBracket;
import static org.eclipse.cdt.internal.core.dom.lrparser.cpp.CPPParsersym.TK_RightParen;
import static org.eclipse.cdt.internal.core.dom.lrparser.cpp.CPPParsersym.TK_SemiColon;
import static org.eclipse.cdt.internal.core.dom.lrparser.cpp.CPPParsersym.TK_auto;
import static org.eclipse.cdt.internal.core.dom.lrparser.cpp.CPPParsersym.TK_bool;
import static org.eclipse.cdt.internal.core.dom.lrparser.cpp.CPPParsersym.TK_char;
import static org.eclipse.cdt.internal.core.dom.lrparser.cpp.CPPParsersym.TK_class;
import static org.eclipse.cdt.internal.core.dom.lrparser.cpp.CPPParsersym.TK_const;
import static org.eclipse.cdt.internal.core.dom.lrparser.cpp.CPPParsersym.TK_delete;
import static org.eclipse.cdt.internal.core.dom.lrparser.cpp.CPPParsersym.TK_double;
import static org.eclipse.cdt.internal.core.dom.lrparser.cpp.CPPParsersym.TK_enum;
import static org.eclipse.cdt.internal.core.dom.lrparser.cpp.CPPParsersym.TK_explicit;
import static org.eclipse.cdt.internal.core.dom.lrparser.cpp.CPPParsersym.TK_extern;
import static org.eclipse.cdt.internal.core.dom.lrparser.cpp.CPPParsersym.TK_float;
import static org.eclipse.cdt.internal.core.dom.lrparser.cpp.CPPParsersym.TK_for;
import static org.eclipse.cdt.internal.core.dom.lrparser.cpp.CPPParsersym.TK_friend;
import static org.eclipse.cdt.internal.core.dom.lrparser.cpp.CPPParsersym.TK_identifier;
import static org.eclipse.cdt.internal.core.dom.lrparser.cpp.CPPParsersym.TK_inline;
import static org.eclipse.cdt.internal.core.dom.lrparser.cpp.CPPParsersym.TK_int;
import static org.eclipse.cdt.internal.core.dom.lrparser.cpp.CPPParsersym.TK_long;
import static org.eclipse.cdt.internal.core.dom.lrparser.cpp.CPPParsersym.TK_mutable;
import static org.eclipse.cdt.internal.core.dom.lrparser.cpp.CPPParsersym.TK_new;
import static org.eclipse.cdt.internal.core.dom.lrparser.cpp.CPPParsersym.TK_private;
import static org.eclipse.cdt.internal.core.dom.lrparser.cpp.CPPParsersym.TK_protected;
import static org.eclipse.cdt.internal.core.dom.lrparser.cpp.CPPParsersym.TK_public;
import static org.eclipse.cdt.internal.core.dom.lrparser.cpp.CPPParsersym.TK_register;
import static org.eclipse.cdt.internal.core.dom.lrparser.cpp.CPPParsersym.TK_short;
import static org.eclipse.cdt.internal.core.dom.lrparser.cpp.CPPParsersym.TK_signed;
import static org.eclipse.cdt.internal.core.dom.lrparser.cpp.CPPParsersym.TK_static;
import static org.eclipse.cdt.internal.core.dom.lrparser.cpp.CPPParsersym.TK_struct;
import static org.eclipse.cdt.internal.core.dom.lrparser.cpp.CPPParsersym.TK_typedef;
import static org.eclipse.cdt.internal.core.dom.lrparser.cpp.CPPParsersym.TK_typename;
import static org.eclipse.cdt.internal.core.dom.lrparser.cpp.CPPParsersym.TK_union;
import static org.eclipse.cdt.internal.core.dom.lrparser.cpp.CPPParsersym.TK_unsigned;
import static org.eclipse.cdt.internal.core.dom.lrparser.cpp.CPPParsersym.TK_virtual;
import static org.eclipse.cdt.internal.core.dom.lrparser.cpp.CPPParsersym.TK_void;
import static org.eclipse.cdt.internal.core.dom.lrparser.cpp.CPPParsersym.TK_volatile;
import static org.eclipse.cdt.internal.core.dom.lrparser.cpp.CPPParsersym.TK_wchar_t;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
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.IASTDeclarationStatement;
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.IASTExpressionStatement;
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.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.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.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.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.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.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;
import lpg.lpgjavaruntime.IToken;
/**
* 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<>();
/**
* @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() {
IASTExpression expr;
if (astStack.peek() == null) { // if there is an empty set of parens
astStack.pop();
expr = nodeFactory.newExpressionList();
setOffsetAndLength(expr);
} else {
expr = (IASTExpression) astStack.pop(); // may be null
}
ICPPASTConstructorInitializer initializer = nodeFactory.newConstructorInitializer(expr);
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) {
ICPPASTConstructorInitializer initializer = (ICPPASTConstructorInitializer) 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(new IASTExpression[] { 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));
}
int TK_SC = TK_SemiColon;
IASTExpressionStatement expressionStatement = null;
if (initializer instanceof IASTDeclarationStatement) {
IASTDeclarationStatement declarationStatement = (IASTDeclarationStatement) initializer;
List<IToken> expressionTokens = stream.getRuleTokens();
//find the first semicolon
int end_pos = -1;
for (int i = 0, n = expressionTokens.size(); i < n; i++) {
if (tokenMap.mapKind(expressionTokens.get(i).getKind()) == TK_SC) {
end_pos = i;
break;
}
}
if (end_pos != -1) {
expressionTokens = expressionTokens.subList(2, end_pos);
ISecondaryParser<IASTExpression> expressionParser = parserFactory.getExpressionParser(stream,
properties);
IASTExpression expr1 = runSecondaryParser(expressionParser, expressionTokens);
if (expr1 != null) { // the parse may fail
expressionStatement = nodeFactory.newExpressionStatement(expr1);
setOffsetAndLength(expressionStatement);
}
}
if (expressionStatement == null)
initializer = declarationStatement;
else {
initializer = createAmbiguousStatement(declarationStatement, expressionStatement);
setOffsetAndLength(initializer);
}
}
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 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<>();
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<>(); // 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 (ICPPASTNameSpecifier n : qualifiedName.getQualifier())
newQualifiedName.addNameSpecifier(n);
newQualifiedName.addName(qualifiedName.getLastName());
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() {
Object o = astStack.pop();
IASTName name = (IASTName) astStack.pop();
IASTInitializerClause[] initClauseList = null;
if (o instanceof IASTExpressionList) {
initClauseList = ((IASTExpressionList) o).getExpressions();
} else if (o instanceof IASTInitializerClause) {
initClauseList = new IASTInitializerClause[] { (IASTInitializerClause) o };
}
ICPPASTConstructorInitializer init = nodeFactory.newConstructorInitializer(initClauseList);
int rule_start_offset = stream.getLeftIToken().getStartOffset();
int initClauseList_offset = ParserUtil.offset(initClauseList[0]);
List<IToken> ruleTokens = stream.getRuleTokens();
int start_offset = -1;
for (int i = initClauseList_offset, n = rule_start_offset; i >= n; i--) {
if (tokenMap.mapKind(ruleTokens.get(i).getKind()) == TK_LeftParen) {
start_offset = ruleTokens.get(i).getStartOffset();
break;
}
}
int ruleLength = stream.getRightIToken().getEndOffset() - start_offset;
ParserUtil.setOffsetAndLength(init, start_offset, ruleLength < 0 ? 0 : ruleLength);
ICPPASTConstructorChainInitializer initializer = nodeFactory.newConstructorChainInitializer(name, init);
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);
}
}