| /******************************************************************************* |
| * 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); |
| } |
| } |