| /******************************************************************************* |
| * Copyright (c) 2003, 2004 IBM Corporation and others. |
| * All rights reserved. This program and the accompanying materials |
| * are made available under the terms of the Common Public License v1.0 |
| * which accompanies this distribution, and is available at |
| * http://www.eclipse.org/legal/cpl-v10.html |
| * |
| * Contributors: |
| * IBM Corporation - initial API and implementation |
| *******************************************************************************/ |
| package org.eclipse.cdt.internal.core.parser; |
| |
| import java.util.ArrayList; |
| import java.util.LinkedList; |
| import java.util.List; |
| import java.util.Stack; |
| |
| import org.eclipse.cdt.core.parser.BacktrackException; |
| import org.eclipse.cdt.core.parser.EndOfFileException; |
| import org.eclipse.cdt.core.parser.IParserLogService; |
| import org.eclipse.cdt.core.parser.IProblem; |
| import org.eclipse.cdt.core.parser.IScanner; |
| import org.eclipse.cdt.core.parser.IToken; |
| import org.eclipse.cdt.core.parser.ITokenDuple; |
| import org.eclipse.cdt.core.parser.KeywordSetKey; |
| import org.eclipse.cdt.core.parser.OffsetLimitReachedException; |
| import org.eclipse.cdt.core.parser.ParseError; |
| import org.eclipse.cdt.core.parser.ParserFactory; |
| import org.eclipse.cdt.core.parser.ParserLanguage; |
| import org.eclipse.cdt.core.parser.ParserMode; |
| import org.eclipse.cdt.core.parser.ScannerException; |
| import org.eclipse.cdt.core.parser.ast.ASTPointerOperator; |
| import org.eclipse.cdt.core.parser.ast.ASTSemanticException; |
| import org.eclipse.cdt.core.parser.ast.IASTArrayModifier; |
| import org.eclipse.cdt.core.parser.ast.IASTCompletionNode; |
| import org.eclipse.cdt.core.parser.ast.IASTExpression; |
| import org.eclipse.cdt.core.parser.ast.IASTFactory; |
| import org.eclipse.cdt.core.parser.ast.IASTNode; |
| import org.eclipse.cdt.core.parser.ast.IASTScope; |
| import org.eclipse.cdt.core.parser.ast.IASTSimpleTypeSpecifier; |
| import org.eclipse.cdt.core.parser.ast.IASTTypeId; |
| import org.eclipse.cdt.core.parser.ast.IASTCompletionNode.CompletionKind; |
| import org.eclipse.cdt.core.parser.ast.IASTExpression.Kind; |
| import org.eclipse.cdt.core.parser.extension.IParserExtension; |
| import org.eclipse.cdt.internal.core.parser.token.TokenFactory; |
| import org.eclipse.cdt.internal.core.parser.util.TraceUtil; |
| |
| /** |
| * @author jcamelon |
| */ |
| public class ExpressionParser implements IExpressionParser, IParserData { |
| |
| protected static final String EMPTY_STRING = ""; //$NON-NLS-1$ |
| private static int FIRST_ERROR_UNSET = -1; |
| protected boolean parsePassed = true; |
| protected int firstErrorOffset = FIRST_ERROR_UNSET; |
| protected int firstErrorLine = FIRST_ERROR_UNSET; |
| private BacktrackException backtrack = new BacktrackException(); |
| private int backtrackCount = 0; |
| |
| protected final void throwBacktrack( IProblem problem ) throws BacktrackException { |
| ++backtrackCount; |
| backtrack.initialize( problem ); |
| throw backtrack; |
| } |
| |
| protected final void throwBacktrack( int startingOffset, int endingOffset, int lineNumber ) throws BacktrackException { |
| ++backtrackCount; |
| backtrack.initialize( startingOffset, ( endingOffset == 0 ) ? startingOffset + 1 : endingOffset, lineNumber ); |
| throw backtrack; |
| } |
| |
| protected final IParserExtension extension; |
| |
| //TODO this stuff needs to be encapsulated by IParserData |
| protected final IParserLogService log; |
| protected ParserLanguage language = ParserLanguage.CPP; |
| protected IASTFactory astFactory = null; |
| protected IScanner scanner; |
| protected IToken currToken; |
| protected IToken lastToken; |
| private boolean limitReached = false; |
| private Stack templateIdScopes = null; |
| private TypeId typeIdInstance = new TypeId(); |
| |
| /** |
| * @return Returns the astFactory. |
| */ |
| public IASTFactory getAstFactory() { |
| return astFactory; |
| } |
| /** |
| * @return Returns the log. |
| */ |
| public IParserLogService getLog() { |
| return log; |
| } |
| |
| /** |
| * Look Ahead in the token list to see what is coming. |
| * |
| * @param i How far ahead do you wish to peek? |
| * @return the token you wish to observe |
| * @throws EndOfFileException if looking ahead encounters EOF, throw EndOfFile |
| */ |
| public IToken LA(int i) throws EndOfFileException { |
| |
| if (parserTimeout()) { |
| throw new ParseError(ParseError.ParseErrorKind.TIMEOUT); |
| } |
| |
| if (i < 1) // can't go backwards |
| return null; |
| if (currToken == null) |
| currToken = fetchToken(); |
| IToken retToken = currToken; |
| for (; i > 1; --i) { |
| retToken = retToken.getNext(); |
| if (retToken == null) |
| retToken = fetchToken(); |
| } |
| return retToken; |
| } |
| |
| /** |
| * Look ahead in the token list and return the token type. |
| * |
| * @param i How far ahead do you wish to peek? |
| * @return The type of that token |
| * @throws EndOfFileException if looking ahead encounters EOF, throw EndOfFile |
| */ |
| public int LT(int i) throws EndOfFileException { |
| return LA(i).getType(); |
| } |
| |
| /** |
| * Consume the next token available, regardless of the type. |
| * |
| * @return The token that was consumed and removed from our buffer. |
| * @throws EndOfFileException If there is no token to consume. |
| */ |
| public IToken consume() throws EndOfFileException { |
| |
| if (currToken == null) |
| currToken = fetchToken(); |
| if (currToken != null) |
| lastToken = currToken; |
| currToken = currToken.getNext(); |
| handleNewToken(lastToken); |
| return lastToken; |
| } |
| |
| /** |
| * Consume the next token available only if the type is as specified. |
| * |
| * @param type The type of token that you are expecting. |
| * @return the token that was consumed and removed from our buffer. |
| * @throws BacktrackException If LT(1) != type |
| */ |
| public IToken consume(int type) throws EndOfFileException, |
| BacktrackException { |
| if (LT(1) == type) |
| return consume(); |
| IToken la = LA(1); |
| throwBacktrack(la.getOffset(), la.getEndOffset(), la.getLineNumber()); |
| return null; |
| } |
| |
| /** |
| * Mark our place in the buffer so that we could return to it should we have to. |
| * |
| * @return The current token. |
| * @throws EndOfFileException If there are no more tokens. |
| */ |
| public IToken mark() throws EndOfFileException { |
| if (currToken == null) |
| currToken = fetchToken(); |
| return currToken; |
| } |
| |
| /** |
| * Rollback to a previous point, reseting the queue of tokens. |
| * |
| * @param mark The point that we wish to restore to. |
| * |
| */ |
| public void backup(IToken mark) { |
| currToken = mark; |
| lastToken = null; // this is not entirely right ... |
| } |
| |
| /** |
| * @param extension TODO |
| * @param scanner2 |
| * @param callback |
| * @param language2 |
| * @param log2 |
| */ |
| public ExpressionParser(IScanner scanner, ParserLanguage language, |
| IParserLogService log, IParserExtension extension) { |
| this.scanner = scanner; |
| this.language = language; |
| this.log = log; |
| this.extension = extension; |
| setupASTFactory(scanner, language); |
| } |
| |
| /** |
| * @param scanner |
| * @param language |
| */ |
| protected void setupASTFactory(IScanner scanner, ParserLanguage language) { |
| astFactory = ParserFactory.createASTFactory(this, |
| ParserMode.EXPRESSION_PARSE, language); |
| scanner.setASTFactory(astFactory); |
| astFactory.setLogger(log); |
| } |
| |
| /** |
| * This is the single entry point for setting parsePassed to |
| * false, and also making note what token offset we failed upon. |
| * |
| * @throws EndOfFileException |
| */ |
| protected void failParse() { |
| try { |
| if (firstErrorOffset == FIRST_ERROR_UNSET){ |
| firstErrorOffset = LA(1).getOffset(); |
| firstErrorLine = LA(1).getLineNumber(); |
| } |
| } catch (EndOfFileException eof) { |
| // do nothing |
| } finally { |
| parsePassed = false; |
| } |
| } |
| |
| /** |
| * Consumes template parameters. |
| * |
| * @param previousLast Previous "last" token (returned if nothing was consumed) |
| * @return Last consumed token, or <code>previousLast</code> if nothing was consumed |
| * @throws BacktrackException request a backtrack |
| */ |
| protected IToken consumeTemplateParameters(IToken previousLast) |
| throws EndOfFileException, BacktrackException { |
| if (language != ParserLanguage.CPP) |
| return previousLast; |
| int startingOffset = previousLast == null ? lastToken.getOffset() : previousLast.getOffset(); |
| IToken last = previousLast; |
| if (LT(1) == IToken.tLT) { |
| last = consume(IToken.tLT); |
| // until we get all the names sorted out |
| Stack scopes = new Stack(); |
| scopes.push(new Integer(IToken.tLT)); |
| |
| while (!scopes.empty()) { |
| int top; |
| last = consume(); |
| |
| switch (last.getType()) { |
| case IToken.tGT : |
| if (((Integer) scopes.peek()).intValue() == IToken.tLT) { |
| scopes.pop(); |
| } |
| break; |
| case IToken.tRBRACKET : |
| do { |
| top = ((Integer) scopes.pop()).intValue(); |
| } while (!scopes.empty() |
| && (top == IToken.tGT || top == IToken.tLT)); |
| if (top != IToken.tLBRACKET) |
| throwBacktrack(startingOffset, last.getEndOffset(), last.getLineNumber()); |
| |
| break; |
| case IToken.tRPAREN : |
| do { |
| top = ((Integer) scopes.pop()).intValue(); |
| } while (!scopes.empty() |
| && (top == IToken.tGT || top == IToken.tLT)); |
| if (top != IToken.tLPAREN) |
| throwBacktrack(startingOffset, last.getEndOffset(), last.getLineNumber()); |
| |
| break; |
| case IToken.tLT : |
| case IToken.tLBRACKET : |
| case IToken.tLPAREN : |
| scopes.push(new Integer(last.getType())); |
| break; |
| } |
| } |
| } |
| return last; |
| } |
| |
| protected List templateArgumentList(IASTScope scope, |
| IASTCompletionNode.CompletionKind kind) throws EndOfFileException, |
| BacktrackException { |
| IToken start = LA(1); |
| int startingOffset = start.getOffset(); |
| int startingLineNumber = start.getOffset(); |
| start = null; |
| IASTExpression expression = null; |
| List list = new LinkedList(); |
| |
| boolean completedArg = false; |
| boolean failed = false; |
| |
| if (templateIdScopes == null) { |
| templateIdScopes = new Stack(); |
| } |
| templateIdScopes.push(new Integer(IToken.tLT)); |
| |
| while (LT(1) != IToken.tGT) { |
| completedArg = false; |
| |
| IToken mark = mark(); |
| |
| try { |
| IASTTypeId typeId = typeId(scope, false, kind); |
| |
| expression = astFactory.createExpression(scope, |
| IASTExpression.Kind.POSTFIX_TYPEID_TYPEID, null, null, |
| null, typeId, null, EMPTY_STRING, null); |
| list.add(expression); |
| completedArg = true; |
| } catch (BacktrackException e) { |
| backup(mark); |
| } catch (ASTSemanticException e) { |
| backup(mark); |
| } |
| |
| if (!completedArg) { |
| try { |
| IToken la = LA(1); |
| int so = la.getOffset(); |
| int ln= la.getLineNumber(); |
| expression = assignmentExpression(scope, |
| CompletionKind.VARIABLE_TYPE, |
| KeywordSetKey.EXPRESSION); |
| |
| if (expression.getExpressionKind() == IASTExpression.Kind.PRIMARY_EMPTY) { |
| throwBacktrack(so, ( lastToken != null ) ? lastToken.getEndOffset() : 0, ln); |
| } |
| list.add(expression); |
| completedArg = true; |
| } catch (BacktrackException e) { |
| backup(mark); |
| } |
| } |
| if (!completedArg) { |
| try { |
| ITokenDuple nameDuple = name(scope, null, |
| KeywordSetKey.EMPTY); |
| expression = astFactory.createExpression(scope, |
| IASTExpression.Kind.ID_EXPRESSION, null, null, |
| null, null, nameDuple, EMPTY_STRING, null); |
| list.add(expression); |
| continue; |
| } catch (ASTSemanticException e) { |
| failed = true; |
| break; |
| } catch (BacktrackException e) { |
| failed = true; |
| break; |
| } catch (Exception e) { |
| logException("templateArgumentList::createExpression()", e); //$NON-NLS-1$ |
| failed = true; |
| break; |
| } |
| } |
| |
| if (LT(1) == IToken.tCOMMA) { |
| consume(); |
| } else if (LT(1) != IToken.tGT) { |
| failed = true; |
| break; |
| } |
| } |
| |
| templateIdScopes.pop(); |
| if (templateIdScopes.size() == 0) { |
| templateIdScopes = null; |
| } |
| |
| if (failed) { |
| if (expression != null) |
| expression.freeReferences(astFactory.getReferenceManager()); |
| throwBacktrack(startingOffset, 0, startingLineNumber ); |
| } |
| |
| return list; |
| } |
| |
| /** |
| * Parse a template-id, according to the ANSI C++ spec. |
| * |
| * template-id: template-name < template-argument-list opt > |
| * template-name : identifier |
| * |
| * @return the last token that we consumed in a successful parse |
| * |
| * @throws BacktrackException request a backtrack |
| */ |
| protected IToken templateId(IASTScope scope, CompletionKind kind) |
| throws EndOfFileException, BacktrackException { |
| ITokenDuple duple = name(scope, kind, KeywordSetKey.EMPTY); |
| //IToken last = consumeTemplateParameters(duple.getLastToken()); |
| return duple.getLastToken();//last; |
| } |
| |
| /** |
| * Parse a name. |
| * |
| * name |
| * : ("::")? name2 ("::" name2)* |
| * |
| * name2 |
| * : IDENTIFER |
| * : template-id |
| * |
| * @param key TODO |
| * @throws BacktrackException request a backtrack |
| */ |
| protected ITokenDuple name(IASTScope scope, |
| IASTCompletionNode.CompletionKind kind, KeywordSetKey key) |
| throws BacktrackException, EndOfFileException { |
| |
| TemplateParameterManager argumentList = TemplateParameterManager |
| .getInstance(); |
| |
| try { |
| IToken first = LA(1); |
| IToken last = null; |
| IToken mark = mark(); |
| |
| boolean hasTemplateId = false; |
| boolean startsWithColonColon = false; |
| |
| if (LT(1) == IToken.tCOLONCOLON) { |
| argumentList.addSegment(null); |
| last = consume(IToken.tCOLONCOLON); |
| setCompletionValues(scope, kind, KeywordSetKey.EMPTY, |
| getCompliationUnit()); |
| startsWithColonColon = true; |
| } |
| |
| if (LT(1) == IToken.tCOMPL) |
| consume(); |
| |
| switch (LT(1)) { |
| case IToken.tIDENTIFIER : |
| IToken prev = last; |
| last = consume(IToken.tIDENTIFIER); |
| if (startsWithColonColon) |
| setCompletionValues(scope, kind, getCompliationUnit()); |
| else if (prev != null) |
| setCompletionValues(scope, kind, first, prev, |
| KeywordSetKey.EMPTY); |
| else |
| setCompletionValuesNoContext(scope, kind, key); |
| |
| last = consumeTemplateArguments(scope, last, argumentList, |
| kind); |
| if (last.getType() == IToken.tGT) |
| hasTemplateId = true; |
| break; |
| |
| default : |
| IToken l = LA(1); |
| backup(mark); |
| throwBacktrack(first.getOffset(), l.getEndOffset(), first.getLineNumber()); |
| } |
| |
| while (LT(1) == IToken.tCOLONCOLON) { |
| IToken prev = last; |
| last = consume(IToken.tCOLONCOLON); |
| setCompletionValues(scope, kind, first, prev, |
| KeywordSetKey.EMPTY); |
| |
| if (queryLookaheadCapability() && LT(1) == IToken.t_template) |
| consume(); |
| |
| if (queryLookaheadCapability() && LT(1) == IToken.tCOMPL) |
| consume(); |
| |
| switch (LT(1)) { |
| case IToken.t_operator : |
| IToken l = LA(1); |
| backup(mark); |
| throwBacktrack(first.getOffset(), l.getEndOffset(), first.getLineNumber()); |
| case IToken.tIDENTIFIER : |
| prev = last; |
| last = consume(); |
| setCompletionValues(scope, kind, first, prev, |
| KeywordSetKey.EMPTY); |
| last = consumeTemplateArguments(scope, last, |
| argumentList, kind); |
| if (last.getType() == IToken.tGT) |
| hasTemplateId = true; |
| } |
| } |
| |
| ITokenDuple tokenDuple = TokenFactory.createTokenDuple(first, last, |
| (hasTemplateId |
| ? argumentList.getTemplateArgumentsList() |
| : null)); |
| setGreaterNameContext(tokenDuple); |
| return tokenDuple; |
| } finally { |
| TemplateParameterManager.returnInstance(argumentList); |
| } |
| |
| } |
| |
| /** |
| * @param scope |
| * @param kind |
| * @param key |
| */ |
| protected void setCompletionValuesNoContext(IASTScope scope, |
| CompletionKind kind, KeywordSetKey key) throws EndOfFileException { |
| } |
| /** |
| * @param tokenDuple |
| */ |
| protected void setGreaterNameContext(ITokenDuple tokenDuple) { |
| //do nothing in this implementation |
| } |
| |
| /** |
| * @param scope |
| * @param kind |
| */ |
| protected void setCompletionValues(IASTScope scope, CompletionKind kind, |
| IASTNode context) throws EndOfFileException { |
| } |
| |
| /** |
| * @param scope |
| * @param kind |
| */ |
| protected void setCompletionValues(IASTScope scope, CompletionKind kind) |
| throws EndOfFileException { |
| } |
| |
| /** |
| * @return |
| */ |
| protected IASTNode getCompliationUnit() { |
| return null; |
| } |
| |
| /** |
| * @param scope |
| * @param kind |
| * @param key |
| * @param node |
| */ |
| protected void setCompletionValues(IASTScope scope, CompletionKind kind, |
| KeywordSetKey key, IASTNode node) throws EndOfFileException { |
| } |
| |
| /** |
| * @param scope |
| * @param last |
| * @param argumentList |
| * @return |
| * @throws EndOfFileException |
| * @throws BacktrackException |
| */ |
| protected IToken consumeTemplateArguments(IASTScope scope, IToken last, |
| TemplateParameterManager argumentList, |
| IASTCompletionNode.CompletionKind completionKind) |
| throws EndOfFileException, BacktrackException { |
| if (language != ParserLanguage.CPP) |
| return last; |
| if (LT(1) == IToken.tLT) { |
| IToken secondMark = mark(); |
| consume(IToken.tLT); |
| try { |
| List list = templateArgumentList(scope, completionKind); |
| argumentList.addSegment(list); |
| last = consume(IToken.tGT); |
| } catch (BacktrackException bt) { |
| argumentList.addSegment(null); |
| backup(secondMark); |
| } |
| } else { |
| argumentList.addSegment(null); |
| } |
| return last; |
| } |
| |
| /** |
| * Parse a const-volatile qualifier. |
| * |
| * cvQualifier |
| * : "const" | "volatile" |
| * |
| * TODO: fix this |
| * @param ptrOp Pointer Operator that const-volatile applies to. |
| * @return Returns the same object sent in. |
| * @throws BacktrackException |
| */ |
| protected IToken cvQualifier(IDeclarator declarator) |
| throws EndOfFileException, BacktrackException { |
| IToken result = null; |
| int startingOffset = LA(1).getOffset(); |
| switch (LT(1)) { |
| case IToken.t_const : |
| result = consume(IToken.t_const); |
| declarator.addPointerOperator(ASTPointerOperator.CONST_POINTER); |
| break; |
| case IToken.t_volatile : |
| result = consume(IToken.t_volatile); |
| declarator |
| .addPointerOperator(ASTPointerOperator.VOLATILE_POINTER); |
| break; |
| case IToken.t_restrict : |
| if (language == ParserLanguage.C) { |
| result = consume(IToken.t_restrict); |
| declarator |
| .addPointerOperator(ASTPointerOperator.RESTRICT_POINTER); |
| break; |
| } |
| if (extension.isValidCVModifier(language, IToken.t_restrict)) { |
| result = consume(IToken.t_restrict); |
| declarator.addPointerOperator(extension.getPointerOperator( |
| language, IToken.t_restrict)); |
| break; |
| } |
| IToken la = LA(1); |
| throwBacktrack(startingOffset, la.getEndOffset(), la.getLineNumber()); |
| |
| default : |
| if (extension.isValidCVModifier(language, LT(1))) { |
| result = consume(); |
| declarator.addPointerOperator(extension.getPointerOperator( |
| language, result.getType())); |
| } |
| } |
| return result; |
| } |
| |
| protected IToken consumeArrayModifiers(IDeclarator d, IASTScope scope) |
| throws EndOfFileException, BacktrackException { |
| int startingOffset = LA(1).getOffset(); |
| IToken last = null; |
| while (LT(1) == IToken.tLBRACKET) { |
| consume(IToken.tLBRACKET); // eat the '[' |
| |
| IASTExpression exp = null; |
| if (LT(1) != IToken.tRBRACKET) { |
| exp = constantExpression(scope, |
| CompletionKind.SINGLE_NAME_REFERENCE, |
| KeywordSetKey.EXPRESSION); |
| } |
| last = consume(IToken.tRBRACKET); |
| IASTArrayModifier arrayMod = null; |
| try { |
| arrayMod = astFactory.createArrayModifier(exp); |
| } catch (Exception e) { |
| logException("consumeArrayModifiers::createArrayModifier()", e); //$NON-NLS-1$ |
| throwBacktrack(startingOffset, last.getEndOffset(), last.getLineNumber()); |
| } |
| d.addArrayModifier(arrayMod); |
| } |
| return last; |
| } |
| |
| protected void operatorId(Declarator d, IToken originalToken, |
| TemplateParameterManager templateArgs, |
| IASTCompletionNode.CompletionKind completionKind) |
| throws BacktrackException, EndOfFileException { |
| // we know this is an operator |
| IToken operatorToken = consume(IToken.t_operator); |
| IToken toSend = null; |
| if (LA(1).isOperator() || LT(1) == IToken.tLPAREN |
| || LT(1) == IToken.tLBRACKET) { |
| if ((LT(1) == IToken.t_new || LT(1) == IToken.t_delete) |
| && LT(2) == IToken.tLBRACKET && LT(3) == IToken.tRBRACKET) { |
| consume(); |
| consume(IToken.tLBRACKET); |
| toSend = consume(IToken.tRBRACKET); |
| // vector new and delete operators |
| } else if (LT(1) == IToken.tLPAREN && LT(2) == IToken.tRPAREN) { |
| // operator () |
| consume(IToken.tLPAREN); |
| toSend = consume(IToken.tRPAREN); |
| } else if (LT(1) == IToken.tLBRACKET && LT(2) == IToken.tRBRACKET) { |
| consume(IToken.tLBRACKET); |
| toSend = consume(IToken.tRBRACKET); |
| } else if (LA(1).isOperator()) |
| toSend = consume(); |
| else |
| throwBacktrack(operatorToken.getOffset(), toSend != null ? toSend.getEndOffset() : 0, operatorToken.getLineNumber() ); |
| } else { |
| // must be a conversion function |
| typeId(d.getDeclarationWrapper().getScope(), true, |
| CompletionKind.TYPE_REFERENCE); |
| toSend = lastToken; |
| } |
| |
| boolean hasTemplateId = (templateArgs != null); |
| boolean grabbedNewInstance = false; |
| if (templateArgs == null) { |
| templateArgs = TemplateParameterManager.getInstance(); |
| grabbedNewInstance = true; |
| } |
| |
| try { |
| toSend = consumeTemplateArguments(d.getDeclarationWrapper() |
| .getScope(), toSend, templateArgs, completionKind); |
| if (toSend.getType() == IToken.tGT) { |
| hasTemplateId = true; |
| } |
| |
| ITokenDuple duple = TokenFactory.createTokenDuple( |
| originalToken == null ? operatorToken : originalToken, |
| toSend, (hasTemplateId ? templateArgs |
| .getTemplateArgumentsList() : null)); |
| |
| d.setName(duple); |
| } finally { |
| if (grabbedNewInstance) |
| TemplateParameterManager.returnInstance(templateArgs); |
| } |
| } |
| |
| /** |
| * Parse a Pointer Operator. |
| * |
| * ptrOperator |
| * : "*" (cvQualifier)* |
| * | "&" |
| * | ::? nestedNameSpecifier "*" (cvQualifier)* |
| * |
| * @param owner Declarator that this pointer operator corresponds to. |
| * @throws BacktrackException request a backtrack |
| */ |
| protected IToken consumePointerOperators(IDeclarator d) |
| throws EndOfFileException, BacktrackException { |
| IToken result = null; |
| for (;;) { |
| if (LT(1) == IToken.tAMPER) { |
| result = consume(IToken.tAMPER); |
| d.addPointerOperator(ASTPointerOperator.REFERENCE); |
| return result; |
| |
| } |
| IToken mark = mark(); |
| |
| ITokenDuple nameDuple = null; |
| if (LT(1) == IToken.tIDENTIFIER || LT(1) == IToken.tCOLONCOLON) { |
| try { |
| try { |
| nameDuple = name(d.getScope(), |
| CompletionKind.SINGLE_NAME_REFERENCE, |
| KeywordSetKey.EMPTY); |
| } catch (OffsetLimitReachedException olre) { |
| backup(mark); |
| return null; |
| } |
| } catch (BacktrackException bt) { |
| backup(mark); |
| return null; |
| } |
| } |
| if (LT(1) == IToken.tSTAR) { |
| result = consume(IToken.tSTAR); |
| |
| d.setPointerOperatorName(nameDuple); |
| |
| IToken successful = null; |
| for (;;) { |
| IToken newSuccess = cvQualifier(d); |
| if (newSuccess != null) |
| successful = newSuccess; |
| else |
| break; |
| |
| } |
| |
| if (successful == null) { |
| d.addPointerOperator(ASTPointerOperator.POINTER); |
| } |
| continue; |
| } |
| if (nameDuple != null) |
| nameDuple.freeReferences(astFactory.getReferenceManager()); |
| backup(mark); |
| return result; |
| } |
| } |
| |
| /** |
| * @param expression |
| * @throws BacktrackException |
| */ |
| protected IASTExpression constantExpression(IASTScope scope, |
| CompletionKind kind, KeywordSetKey key) throws BacktrackException, |
| EndOfFileException { |
| return conditionalExpression(scope, kind, key); |
| } |
| |
| public IASTExpression expression(IASTScope scope, CompletionKind kind, |
| KeywordSetKey key) throws BacktrackException, EndOfFileException { |
| IToken la = LA(1); |
| int startingOffset = la.getOffset(); |
| int ln = la.getLineNumber(); |
| IASTExpression assignmentExpression = assignmentExpression(scope, kind, |
| key); |
| while (LT(1) == IToken.tCOMMA) { |
| consume(IToken.tCOMMA); |
| setParameterListExpression(assignmentExpression); |
| IASTExpression secondExpression = assignmentExpression(scope, kind, |
| key); |
| setParameterListExpression(null); |
| int endOffset = lastToken != null ? lastToken.getEndOffset() : 0 ; |
| try { |
| assignmentExpression = astFactory.createExpression(scope, |
| IASTExpression.Kind.EXPRESSIONLIST, |
| assignmentExpression, secondExpression, null, null, |
| null, EMPTY_STRING, null); |
| } catch (ASTSemanticException e) { |
| throwBacktrack(e.getProblem()); |
| } catch (Exception e) { |
| logException("expression::createExpression()", e); //$NON-NLS-1$ |
| throwBacktrack(startingOffset, endOffset, ln); |
| } |
| } |
| return assignmentExpression; |
| } |
| |
| /** |
| * @param assignmentExpression |
| */ |
| protected void setParameterListExpression( |
| IASTExpression assignmentExpression) { |
| } |
| /** |
| * @param expression |
| * @throws BacktrackException |
| */ |
| protected IASTExpression assignmentExpression(IASTScope scope, |
| CompletionKind kind, KeywordSetKey key) throws EndOfFileException, |
| BacktrackException { |
| setCompletionValues(scope, kind, key); |
| if (LT(1) == IToken.t_throw) { |
| return throwExpression(scope, key); |
| } |
| IASTExpression conditionalExpression = conditionalExpression(scope, |
| kind, key); |
| // if the condition not taken, try assignment operators |
| if (conditionalExpression != null |
| && conditionalExpression.getExpressionKind() == IASTExpression.Kind.CONDITIONALEXPRESSION) |
| return conditionalExpression; |
| switch (LT(1)) { |
| case IToken.tASSIGN : |
| return assignmentOperatorExpression(scope, |
| IASTExpression.Kind.ASSIGNMENTEXPRESSION_NORMAL, |
| conditionalExpression, kind, key); |
| case IToken.tSTARASSIGN : |
| return assignmentOperatorExpression(scope, |
| IASTExpression.Kind.ASSIGNMENTEXPRESSION_MULT, |
| conditionalExpression, kind, key); |
| case IToken.tDIVASSIGN : |
| return assignmentOperatorExpression(scope, |
| IASTExpression.Kind.ASSIGNMENTEXPRESSION_DIV, |
| conditionalExpression, kind, key); |
| case IToken.tMODASSIGN : |
| return assignmentOperatorExpression(scope, |
| IASTExpression.Kind.ASSIGNMENTEXPRESSION_MOD, |
| conditionalExpression, kind, key); |
| case IToken.tPLUSASSIGN : |
| return assignmentOperatorExpression(scope, |
| IASTExpression.Kind.ASSIGNMENTEXPRESSION_PLUS, |
| conditionalExpression, kind, key); |
| case IToken.tMINUSASSIGN : |
| return assignmentOperatorExpression(scope, |
| IASTExpression.Kind.ASSIGNMENTEXPRESSION_MINUS, |
| conditionalExpression, kind, key); |
| case IToken.tSHIFTRASSIGN : |
| return assignmentOperatorExpression(scope, |
| IASTExpression.Kind.ASSIGNMENTEXPRESSION_RSHIFT, |
| conditionalExpression, kind, key); |
| case IToken.tSHIFTLASSIGN : |
| return assignmentOperatorExpression(scope, |
| IASTExpression.Kind.ASSIGNMENTEXPRESSION_LSHIFT, |
| conditionalExpression, kind, key); |
| case IToken.tAMPERASSIGN : |
| return assignmentOperatorExpression(scope, |
| IASTExpression.Kind.ASSIGNMENTEXPRESSION_AND, |
| conditionalExpression, kind, key); |
| case IToken.tXORASSIGN : |
| return assignmentOperatorExpression(scope, |
| IASTExpression.Kind.ASSIGNMENTEXPRESSION_XOR, |
| conditionalExpression, kind, key); |
| case IToken.tBITORASSIGN : |
| return assignmentOperatorExpression(scope, |
| IASTExpression.Kind.ASSIGNMENTEXPRESSION_OR, |
| conditionalExpression, kind, key); |
| } |
| return conditionalExpression; |
| } |
| |
| /** |
| * @param expression |
| * @throws BacktrackException |
| */ |
| protected IASTExpression throwExpression(IASTScope scope, KeywordSetKey key) |
| throws EndOfFileException, BacktrackException { |
| IToken throwToken = consume(IToken.t_throw); |
| setCompletionValues(scope, CompletionKind.SINGLE_NAME_REFERENCE, |
| KeywordSetKey.EXPRESSION); |
| IASTExpression throwExpression = null; |
| try { |
| throwExpression = expression(scope, |
| CompletionKind.SINGLE_NAME_REFERENCE, key); |
| } catch (BacktrackException b) { |
| } |
| int endOffset = ( lastToken != null ) ? lastToken.getEndOffset() : 0; |
| try { |
| return astFactory.createExpression(scope, |
| IASTExpression.Kind.THROWEXPRESSION, throwExpression, null, |
| null, null, null, EMPTY_STRING, null); |
| } catch (ASTSemanticException e) { |
| throwBacktrack(e.getProblem()); |
| } catch (Exception e) { |
| logException("throwExpression::createExpression()", e); //$NON-NLS-1$ |
| throwBacktrack(throwToken.getOffset(), endOffset, throwToken.getLineNumber() ); |
| |
| } |
| return null; |
| } |
| |
| /** |
| * @param expression |
| * @return |
| * @throws BacktrackException |
| */ |
| protected IASTExpression conditionalExpression(IASTScope scope, |
| CompletionKind kind, KeywordSetKey key) throws BacktrackException, |
| EndOfFileException { |
| IToken la = LA(1); |
| int startingOffset = la.getOffset(); |
| int ln = la.getLineNumber(); |
| la = null; |
| IASTExpression firstExpression = logicalOrExpression(scope, kind, key); |
| if (LT(1) == IToken.tQUESTION) { |
| consume(IToken.tQUESTION); |
| IASTExpression secondExpression = expression(scope, kind, key); |
| consume(IToken.tCOLON); |
| IASTExpression thirdExpression = assignmentExpression(scope, kind, |
| key); |
| int endOffset = ( lastToken != null ) ? lastToken.getEndOffset() : 0; |
| try { |
| return astFactory.createExpression(scope, |
| IASTExpression.Kind.CONDITIONALEXPRESSION, |
| firstExpression, secondExpression, thirdExpression, |
| null, null, EMPTY_STRING, null); |
| } catch (ASTSemanticException e) { |
| throwBacktrack(e.getProblem()); |
| } catch (Exception e) { |
| logException("conditionalExpression::createExpression()", e); //$NON-NLS-1$ |
| throwBacktrack(startingOffset, endOffset, ln); |
| } |
| } |
| return firstExpression; |
| } |
| |
| /** |
| * @param expression |
| * @throws BacktrackException |
| */ |
| protected IASTExpression logicalOrExpression(IASTScope scope, |
| CompletionKind kind, KeywordSetKey key) throws BacktrackException, |
| EndOfFileException { |
| int startingOffset = LA(1).getOffset(); |
| int line = LA(1).getLineNumber(); |
| IASTExpression firstExpression = logicalAndExpression(scope, kind, key); |
| while (LT(1) == IToken.tOR) { |
| consume(IToken.tOR); |
| IASTExpression secondExpression = logicalAndExpression(scope, kind, |
| key); |
| int endOffset = ( lastToken != null ) ? lastToken.getEndOffset() : 0; |
| try { |
| firstExpression = astFactory.createExpression(scope, |
| IASTExpression.Kind.LOGICALOREXPRESSION, |
| firstExpression, secondExpression, null, null, null, |
| EMPTY_STRING, null); |
| } catch (ASTSemanticException e) { |
| throwBacktrack(e.getProblem()); |
| } catch (Exception e) { |
| logException("logicalOrExpression::createExpression()", e); //$NON-NLS-1$ |
| throwBacktrack(startingOffset, endOffset, line); |
| } |
| } |
| return firstExpression; |
| } |
| |
| /** |
| * @param expression |
| * @throws BacktrackException |
| */ |
| protected IASTExpression logicalAndExpression(IASTScope scope, |
| CompletionKind kind, KeywordSetKey key) throws BacktrackException, |
| EndOfFileException { |
| int startingOffset = LA(1).getOffset(); |
| int line = LA(1).getLineNumber(); |
| IASTExpression firstExpression = inclusiveOrExpression(scope, kind, key); |
| while (LT(1) == IToken.tAND) { |
| consume(IToken.tAND); |
| IASTExpression secondExpression = inclusiveOrExpression(scope, |
| kind, key); |
| int endOffset = ( lastToken != null ) ? lastToken.getEndOffset() : 0; |
| try { |
| firstExpression = astFactory.createExpression(scope, |
| IASTExpression.Kind.LOGICALANDEXPRESSION, |
| firstExpression, secondExpression, null, null, null, |
| EMPTY_STRING, null); |
| } catch (ASTSemanticException e) { |
| throwBacktrack(e.getProblem()); |
| } catch (Exception e) { |
| logException("logicalAndExpression::createExpression()", e); //$NON-NLS-1$ |
| throwBacktrack(startingOffset, endOffset, line); |
| } |
| } |
| return firstExpression; |
| } |
| |
| /** |
| * @param expression |
| * @throws BacktrackException |
| */ |
| protected IASTExpression inclusiveOrExpression(IASTScope scope, |
| CompletionKind kind, KeywordSetKey key) throws BacktrackException, |
| EndOfFileException { |
| int startingOffset = LA(1).getOffset(); |
| int line = LA(1).getLineNumber(); |
| IASTExpression firstExpression = exclusiveOrExpression(scope, kind, key); |
| while (LT(1) == IToken.tBITOR) { |
| consume(); |
| IASTExpression secondExpression = exclusiveOrExpression(scope, |
| kind, key); |
| int endOffset = ( lastToken != null ) ? lastToken.getEndOffset() : 0; |
| try { |
| firstExpression = astFactory.createExpression(scope, |
| IASTExpression.Kind.INCLUSIVEOREXPRESSION, |
| firstExpression, secondExpression, null, null, null, |
| EMPTY_STRING, null); |
| } catch (ASTSemanticException e) { |
| throwBacktrack(e.getProblem()); |
| } catch (Exception e) { |
| logException("inclusiveOrExpression::createExpression()", e); //$NON-NLS-1$ |
| throwBacktrack(startingOffset, endOffset, line); |
| } |
| } |
| return firstExpression; |
| } |
| |
| /** |
| * @param expression |
| * @throws BacktrackException |
| */ |
| protected IASTExpression exclusiveOrExpression(IASTScope scope, |
| CompletionKind kind, KeywordSetKey key) throws BacktrackException, |
| EndOfFileException { |
| int startingOffset = LA(1).getOffset(); |
| int line = LA(1).getLineNumber(); |
| IASTExpression firstExpression = andExpression(scope, kind, key); |
| while (LT(1) == IToken.tXOR) { |
| consume(); |
| |
| IASTExpression secondExpression = andExpression(scope, kind, key); |
| int endOffset = ( lastToken != null ) ? lastToken.getEndOffset() : 0; |
| try { |
| firstExpression = astFactory.createExpression(scope, |
| IASTExpression.Kind.EXCLUSIVEOREXPRESSION, |
| firstExpression, secondExpression, null, null, null, |
| EMPTY_STRING, null); |
| } catch (ASTSemanticException e) { |
| throwBacktrack(e.getProblem()); |
| } catch (Exception e) { |
| logException("exclusiveORExpression::createExpression()", e); //$NON-NLS-1$ |
| throwBacktrack(startingOffset, endOffset, line); |
| } |
| } |
| return firstExpression; |
| } |
| |
| /** |
| * @param expression |
| * @throws BacktrackException |
| */ |
| protected IASTExpression andExpression(IASTScope scope, |
| CompletionKind kind, KeywordSetKey key) throws EndOfFileException, |
| BacktrackException { |
| int startingOffset = LA(1).getOffset(); |
| int line = LA(1).getLineNumber(); |
| IASTExpression firstExpression = equalityExpression(scope, kind, key); |
| while (LT(1) == IToken.tAMPER) { |
| consume(); |
| IASTExpression secondExpression = equalityExpression(scope, kind, |
| key); |
| int endOffset = ( lastToken != null ) ? lastToken.getEndOffset() : 0; |
| try { |
| firstExpression = astFactory.createExpression(scope, |
| IASTExpression.Kind.ANDEXPRESSION, firstExpression, |
| secondExpression, null, null, null, EMPTY_STRING, null); |
| } catch (ASTSemanticException e) { |
| throwBacktrack(e.getProblem()); |
| } catch (Exception e) { |
| logException("andExpression::createExpression()", e); //$NON-NLS-1$ |
| throwBacktrack(startingOffset, endOffset, line); |
| } |
| } |
| return firstExpression; |
| } |
| |
| /** |
| * @param methodName |
| * @param e |
| */ |
| public void logException(String methodName, Exception e) { |
| if (!(e instanceof EndOfFileException) && e != null && log.isTracing()) { |
| StringBuffer buffer = new StringBuffer(); |
| buffer.append("Parser: Unexpected exception in "); //$NON-NLS-1$ |
| buffer.append(methodName); |
| buffer.append(":"); //$NON-NLS-1$ |
| buffer.append(e.getClass().getName()); |
| buffer.append("::"); //$NON-NLS-1$ |
| buffer.append(e.getMessage()); |
| buffer.append(". w/"); //$NON-NLS-1$ |
| buffer.append(scanner.toString()); |
| log.traceLog(buffer.toString()); |
| // log.errorLog(buffer.toString()); |
| } |
| } |
| |
| /** |
| * @param expression |
| * @throws BacktrackException |
| */ |
| protected IASTExpression equalityExpression(IASTScope scope, |
| CompletionKind kind, KeywordSetKey key) throws EndOfFileException, |
| BacktrackException { |
| int startingOffset = LA(1).getOffset(); |
| int line = LA(1).getLineNumber(); |
| IASTExpression firstExpression = relationalExpression(scope, kind, key); |
| for (;;) { |
| switch (LT(1)) { |
| case IToken.tEQUAL : |
| case IToken.tNOTEQUAL : |
| IToken t = consume(); |
| IASTExpression secondExpression = relationalExpression( |
| scope, kind, key); |
| int endOffset = ( lastToken != null ) ? lastToken.getEndOffset() : 0; |
| try { |
| firstExpression = astFactory.createExpression(scope, (t |
| .getType() == IToken.tEQUAL) |
| ? IASTExpression.Kind.EQUALITY_EQUALS |
| : IASTExpression.Kind.EQUALITY_NOTEQUALS, |
| firstExpression, secondExpression, null, null, |
| null, EMPTY_STRING, null); |
| } catch (ASTSemanticException e) { |
| throwBacktrack(e.getProblem()); |
| } catch (Exception e) { |
| logException( |
| "equalityExpression::createExpression()", e); //$NON-NLS-1$ |
| throwBacktrack(startingOffset, endOffset, line); |
| } |
| break; |
| default : |
| return firstExpression; |
| } |
| } |
| } |
| |
| /** |
| * @param expression |
| * @throws BacktrackException |
| */ |
| protected IASTExpression relationalExpression(IASTScope scope, |
| CompletionKind kind, KeywordSetKey key) throws BacktrackException, |
| EndOfFileException { |
| int startingOffset = LA(1).getOffset(); |
| int line = LA(1).getLineNumber(); |
| IASTExpression firstExpression = shiftExpression(scope, kind, key); |
| for (;;) { |
| switch (LT(1)) { |
| case IToken.tGT : |
| if (templateIdScopes != null |
| && ((Integer) templateIdScopes.peek()).intValue() == IToken.tLT) { |
| return firstExpression; |
| } |
| case IToken.tLT : |
| case IToken.tLTEQUAL : |
| case IToken.tGTEQUAL : |
| IToken mark = mark(); |
| int t = consume().getType(); |
| IASTExpression secondExpression = shiftExpression(scope, |
| kind, key); |
| if (LA(1) == mark.getNext()) { |
| // we did not consume anything |
| // this is most likely an error |
| backup(mark); |
| return firstExpression; |
| } |
| IASTExpression.Kind expressionKind = null; |
| switch (t) { |
| case IToken.tGT : |
| expressionKind = IASTExpression.Kind.RELATIONAL_GREATERTHAN; |
| break; |
| case IToken.tLT : |
| expressionKind = IASTExpression.Kind.RELATIONAL_LESSTHAN; |
| break; |
| case IToken.tLTEQUAL : |
| expressionKind = IASTExpression.Kind.RELATIONAL_LESSTHANEQUALTO; |
| break; |
| case IToken.tGTEQUAL : |
| expressionKind = IASTExpression.Kind.RELATIONAL_GREATERTHANEQUALTO; |
| break; |
| } |
| int endOffset = ( lastToken != null ) ? lastToken.getEndOffset() : 0; |
| try { |
| firstExpression = astFactory.createExpression(scope, |
| expressionKind, firstExpression, |
| secondExpression, null, null, null, |
| EMPTY_STRING, null); |
| } catch (ASTSemanticException e) { |
| throwBacktrack(e.getProblem()); |
| } catch (Exception e) { |
| logException( |
| "relationalExpression::createExpression()", e); //$NON-NLS-1$ |
| throwBacktrack(startingOffset, endOffset, line); |
| } |
| break; |
| default : |
| if (extension.isValidRelationalExpressionStart(language, |
| LT(1))) { |
| IASTExpression extensionExpression = extension |
| .parseRelationalExpression(scope, this, kind, |
| key, firstExpression); |
| if (extensionExpression != null) |
| return extensionExpression; |
| } |
| return firstExpression; |
| } |
| } |
| } |
| |
| /** |
| * @param expression |
| * @throws BacktrackException |
| */ |
| public IASTExpression shiftExpression(IASTScope scope, CompletionKind kind, |
| KeywordSetKey key) throws BacktrackException, EndOfFileException { |
| int startingOffset = LA(1).getOffset(); |
| int line = LA(1).getLineNumber(); |
| IASTExpression firstExpression = additiveExpression(scope, kind, key); |
| for (;;) { |
| switch (LT(1)) { |
| case IToken.tSHIFTL : |
| case IToken.tSHIFTR : |
| IToken t = consume(); |
| IASTExpression secondExpression = additiveExpression(scope, |
| kind, key); |
| int endOffset = ( lastToken != null ) ? lastToken.getEndOffset() : 0; |
| try { |
| firstExpression = astFactory.createExpression(scope, |
| ((t.getType() == IToken.tSHIFTL) |
| ? IASTExpression.Kind.SHIFT_LEFT |
| : IASTExpression.Kind.SHIFT_RIGHT), |
| firstExpression, secondExpression, null, null, |
| null, EMPTY_STRING, null); |
| } catch (ASTSemanticException e) { |
| throwBacktrack(e.getProblem()); |
| } catch (Exception e) { |
| logException("shiftExpression::createExpression()", e); //$NON-NLS-1$ |
| throwBacktrack(startingOffset, endOffset, line); |
| } |
| break; |
| default : |
| return firstExpression; |
| } |
| } |
| } |
| |
| /** |
| * @param expression |
| * @throws BacktrackException |
| */ |
| protected IASTExpression additiveExpression(IASTScope scope, |
| CompletionKind kind, KeywordSetKey key) throws BacktrackException, |
| EndOfFileException { |
| int startingOffset = LA(1).getOffset(); |
| int line = LA(1).getLineNumber(); |
| IASTExpression firstExpression = multiplicativeExpression(scope, kind, |
| key); |
| for (;;) { |
| switch (LT(1)) { |
| case IToken.tPLUS : |
| case IToken.tMINUS : |
| IToken t = consume(); |
| IASTExpression secondExpression = multiplicativeExpression( |
| scope, kind, key); |
| int endOffset = ( lastToken != null ) ? lastToken.getEndOffset() : 0; |
| try { |
| firstExpression = astFactory.createExpression(scope, |
| ((t.getType() == IToken.tPLUS) |
| ? IASTExpression.Kind.ADDITIVE_PLUS |
| : IASTExpression.Kind.ADDITIVE_MINUS), |
| firstExpression, secondExpression, null, null, |
| null, EMPTY_STRING, null); |
| } catch (ASTSemanticException e) { |
| throwBacktrack(e.getProblem()); |
| } catch (Exception e) { |
| logException( |
| "additiveExpression::createExpression()", e); //$NON-NLS-1$ |
| throwBacktrack(startingOffset, endOffset, line); |
| } |
| break; |
| default : |
| return firstExpression; |
| } |
| } |
| } |
| |
| /** |
| * @param expression |
| * @throws BacktrackException |
| */ |
| protected IASTExpression multiplicativeExpression(IASTScope scope, |
| CompletionKind kind, KeywordSetKey key) throws BacktrackException, |
| EndOfFileException { |
| int startingOffset = LA(1).getOffset(); |
| int line = LA(1).getLineNumber(); |
| IASTExpression firstExpression = pmExpression(scope, kind, key); |
| for (;;) { |
| switch (LT(1)) { |
| case IToken.tSTAR : |
| case IToken.tDIV : |
| case IToken.tMOD : |
| IToken t = consume(); |
| IASTExpression secondExpression = pmExpression(scope, kind, |
| key); |
| IASTExpression.Kind expressionKind = null; |
| switch (t.getType()) { |
| case IToken.tSTAR : |
| expressionKind = IASTExpression.Kind.MULTIPLICATIVE_MULTIPLY; |
| break; |
| case IToken.tDIV : |
| expressionKind = IASTExpression.Kind.MULTIPLICATIVE_DIVIDE; |
| break; |
| case IToken.tMOD : |
| expressionKind = IASTExpression.Kind.MULTIPLICATIVE_MODULUS; |
| break; |
| } |
| int endOffset = ( lastToken != null ) ? lastToken.getEndOffset() : 0; |
| try { |
| firstExpression = astFactory.createExpression(scope, |
| expressionKind, firstExpression, |
| secondExpression, null, null, null, |
| EMPTY_STRING, null); |
| } catch (ASTSemanticException e) { |
| firstExpression.freeReferences(astFactory |
| .getReferenceManager()); |
| throwBacktrack(e.getProblem()); |
| } catch (Exception e) { |
| logException( |
| "multiplicativeExpression::createExpression()", e); //$NON-NLS-1$ |
| throwBacktrack(startingOffset, endOffset, line); |
| } |
| break; |
| default : |
| return firstExpression; |
| } |
| } |
| } |
| |
| /** |
| * @param expression |
| * @throws BacktrackException |
| */ |
| protected IASTExpression pmExpression(IASTScope scope, CompletionKind kind, |
| KeywordSetKey key) throws EndOfFileException, BacktrackException { |
| int startingOffset = LA(1).getOffset(); |
| int line = LA(1).getLineNumber(); |
| IASTExpression firstExpression = castExpression(scope, kind, key); |
| for (;;) { |
| switch (LT(1)) { |
| case IToken.tDOTSTAR : |
| case IToken.tARROWSTAR : |
| IToken t = consume(); |
| IASTExpression secondExpression = castExpression(scope, |
| kind, key); |
| int endOffset = ( lastToken != null ) ? lastToken.getEndOffset() : 0; |
| try { |
| firstExpression = astFactory.createExpression(scope, |
| ((t.getType() == IToken.tDOTSTAR) |
| ? IASTExpression.Kind.PM_DOTSTAR |
| : IASTExpression.Kind.PM_ARROWSTAR), |
| firstExpression, secondExpression, null, null, |
| null, EMPTY_STRING, null); |
| } catch (ASTSemanticException e) { |
| throwBacktrack(e.getProblem()); |
| } catch (Exception e) { |
| logException("pmExpression::createExpression()", e); //$NON-NLS-1$ |
| throwBacktrack(startingOffset, endOffset, line); |
| } |
| break; |
| default : |
| return firstExpression; |
| } |
| } |
| } |
| |
| /** |
| * castExpression |
| * : unaryExpression |
| * | "(" typeId ")" castExpression |
| */ |
| protected IASTExpression castExpression(IASTScope scope, |
| CompletionKind kind, KeywordSetKey key) throws EndOfFileException, |
| BacktrackException { |
| // TO DO: we need proper symbol checkint to ensure type name |
| if (LT(1) == IToken.tLPAREN) { |
| int startingOffset = LA(1).getOffset(); |
| int line = LA(1).getLineNumber(); |
| IToken mark = mark(); |
| consume(); |
| if (templateIdScopes != null) { |
| templateIdScopes.push(new Integer(IToken.tLPAREN)); |
| } |
| boolean popped = false; |
| IASTTypeId typeId = null; |
| // If this isn't a type name, then we shouldn't be here |
| try { |
| try { |
| typeId = typeId(scope, false, getCastExpressionKind(kind)); |
| consume(IToken.tRPAREN); |
| } catch (BacktrackException bte) { |
| backup(mark); |
| if (typeId != null) |
| typeId.freeReferences(astFactory.getReferenceManager()); |
| throw bte; |
| } |
| |
| if (templateIdScopes != null) { |
| templateIdScopes.pop(); |
| popped = true; |
| } |
| IASTExpression castExpression = castExpression(scope, kind, key); |
| if( castExpression != null && castExpression.getExpressionKind() == IASTExpression.Kind.PRIMARY_EMPTY ) |
| { |
| backup( mark ); |
| if (typeId != null) |
| typeId.freeReferences(astFactory.getReferenceManager()); |
| return unaryExpression(scope, kind, key); |
| } |
| int endOffset = ( lastToken != null ) ? lastToken.getEndOffset() : 0; |
| mark = null; // clean up mark so that we can garbage collect |
| try { |
| return astFactory.createExpression(scope, |
| IASTExpression.Kind.CASTEXPRESSION, castExpression, |
| null, null, typeId, null, EMPTY_STRING, null); |
| } catch (ASTSemanticException e) { |
| throwBacktrack(e.getProblem()); |
| } catch (Exception e) { |
| logException("castExpression::createExpression()", e); //$NON-NLS-1$ |
| throwBacktrack(startingOffset, endOffset, line); |
| } |
| } catch (BacktrackException b) { |
| if (templateIdScopes != null && !popped) { |
| templateIdScopes.pop(); |
| } |
| } |
| } |
| return unaryExpression(scope, kind, key); |
| |
| } |
| |
| /** |
| * @param kind |
| * @return |
| */ |
| private CompletionKind getCastExpressionKind(CompletionKind kind) { |
| return ((kind == CompletionKind.SINGLE_NAME_REFERENCE || kind == CompletionKind.FUNCTION_REFERENCE) |
| ? kind |
| : CompletionKind.TYPE_REFERENCE); |
| } |
| |
| /** |
| * @param completionKind TODO |
| * @throws BacktrackException |
| */ |
| public IASTTypeId typeId(IASTScope scope, boolean skipArrayModifiers, |
| CompletionKind completionKind) throws EndOfFileException, |
| BacktrackException { |
| IToken mark = mark(); |
| ITokenDuple name = null; |
| boolean isConst = false, isVolatile = false; |
| boolean isSigned = false, isUnsigned = false; |
| boolean isShort = false, isLong = false; |
| boolean isTypename = false; |
| |
| IASTSimpleTypeSpecifier.Type kind = null; |
| do { |
| try { |
| name = name(scope, completionKind, |
| KeywordSetKey.DECL_SPECIFIER_SEQUENCE); |
| kind = IASTSimpleTypeSpecifier.Type.CLASS_OR_TYPENAME; |
| break; |
| } catch (BacktrackException b) { |
| // do nothing |
| } |
| |
| boolean encounteredType = false; |
| simpleMods : for (;;) { |
| switch (LT(1)) { |
| case IToken.t_signed : |
| consume(); |
| isSigned = true; |
| break; |
| |
| case IToken.t_unsigned : |
| consume(); |
| isUnsigned = true; |
| break; |
| |
| case IToken.t_short : |
| consume(); |
| isShort = true; |
| break; |
| |
| case IToken.t_long : |
| consume(); |
| isLong = true; |
| break; |
| |
| case IToken.t_const : |
| consume(); |
| isConst = true; |
| break; |
| |
| case IToken.t_volatile : |
| consume(); |
| isVolatile = true; |
| break; |
| |
| case IToken.tIDENTIFIER : |
| if (encounteredType) |
| break simpleMods; |
| encounteredType = true; |
| name = name(scope, completionKind, KeywordSetKey.EMPTY); |
| kind = IASTSimpleTypeSpecifier.Type.CLASS_OR_TYPENAME; |
| break; |
| |
| case IToken.t_int : |
| if (encounteredType) |
| break simpleMods; |
| encounteredType = true; |
| kind = IASTSimpleTypeSpecifier.Type.INT; |
| consume(); |
| break; |
| |
| case IToken.t_char : |
| if (encounteredType) |
| break simpleMods; |
| encounteredType = true; |
| kind = IASTSimpleTypeSpecifier.Type.CHAR; |
| consume(); |
| break; |
| |
| case IToken.t_bool : |
| if (encounteredType) |
| break simpleMods; |
| encounteredType = true; |
| kind = IASTSimpleTypeSpecifier.Type.BOOL; |
| consume(); |
| break; |
| |
| case IToken.t_double : |
| if (encounteredType) |
| break simpleMods; |
| encounteredType = true; |
| kind = IASTSimpleTypeSpecifier.Type.DOUBLE; |
| consume(); |
| break; |
| |
| case IToken.t_float : |
| if (encounteredType) |
| break simpleMods; |
| encounteredType = true; |
| kind = IASTSimpleTypeSpecifier.Type.FLOAT; |
| consume(); |
| break; |
| |
| case IToken.t_wchar_t : |
| if (encounteredType) |
| break simpleMods; |
| encounteredType = true; |
| kind = IASTSimpleTypeSpecifier.Type.WCHAR_T; |
| consume(); |
| break; |
| |
| case IToken.t_void : |
| if (encounteredType) |
| break simpleMods; |
| encounteredType = true; |
| kind = IASTSimpleTypeSpecifier.Type.VOID; |
| consume(); |
| break; |
| |
| case IToken.t__Bool : |
| if (encounteredType) |
| break simpleMods; |
| encounteredType = true; |
| kind = IASTSimpleTypeSpecifier.Type._BOOL; |
| consume(); |
| break; |
| |
| default : |
| break simpleMods; |
| } |
| } |
| |
| if (kind != null) |
| break; |
| |
| if (isShort || isLong || isUnsigned || isSigned) { |
| kind = IASTSimpleTypeSpecifier.Type.INT; |
| break; |
| } |
| |
| if (LT(1) == IToken.t_typename || LT(1) == IToken.t_struct |
| || LT(1) == IToken.t_class || LT(1) == IToken.t_enum |
| || LT(1) == IToken.t_union) { |
| consume(); |
| try { |
| name = name(scope, completionKind, KeywordSetKey.EMPTY); |
| kind = IASTSimpleTypeSpecifier.Type.CLASS_OR_TYPENAME; |
| } catch (BacktrackException b) { |
| backup(mark); |
| throwBacktrack(b); |
| } |
| } |
| |
| } while (false); |
| |
| int endOffset = ( lastToken != null ) ? lastToken.getEndOffset() : 0; |
| if (kind == null) |
| throwBacktrack(mark.getOffset(), endOffset, mark.getLineNumber()); |
| |
| TypeId id = getTypeIdInstance(scope); |
| IToken last = lastToken; |
| IToken temp = last; |
| |
| //template parameters are consumed as part of name |
| //lastToken = consumeTemplateParameters( last ); |
| //if( lastToken == null ) lastToken = last; |
| |
| temp = consumePointerOperators(id); |
| if (temp != null) |
| last = temp; |
| |
| if (!skipArrayModifiers) { |
| temp = consumeArrayModifiers(id, scope); |
| if (temp != null) |
| last = temp; |
| } |
| |
| endOffset = ( lastToken != null ) ? lastToken.getEndOffset() : 0; |
| try { |
| String signature = "";//$NON-NLS-1$ |
| if (last != null) |
| { |
| if( lastToken == null ) |
| lastToken = last; |
| signature = TokenFactory.createStringRepresentation(mark, |
| last); |
| } |
| return astFactory.createTypeId(scope, kind, isConst, isVolatile, |
| isShort, isLong, isSigned, isUnsigned, isTypename, name, id |
| .getPointerOperators(), id.getArrayModifiers(), |
| signature); |
| } catch (ASTSemanticException e) { |
| backup(mark); |
| throwBacktrack(e.getProblem()); |
| } catch (Exception e) { |
| logException("typeId::createTypeId()", e); //$NON-NLS-1$ |
| throwBacktrack(mark.getOffset(), endOffset, mark.getLineNumber()); |
| } |
| return null; |
| } |
| |
| /** |
| * @param scope |
| * @return |
| */ |
| private TypeId getTypeIdInstance(IASTScope scope) { |
| typeIdInstance.reset(scope); |
| return typeIdInstance; |
| } |
| /** |
| * @param expression |
| * @throws BacktrackException |
| */ |
| protected IASTExpression deleteExpression(IASTScope scope, |
| CompletionKind kind, KeywordSetKey key) throws EndOfFileException, |
| BacktrackException { |
| int startingOffset = LA(1).getOffset(); |
| int line = LA(1).getLineNumber(); |
| if (LT(1) == IToken.tCOLONCOLON) { |
| // global scope |
| consume(IToken.tCOLONCOLON); |
| } |
| |
| consume(IToken.t_delete); |
| |
| boolean vectored = false; |
| if (LT(1) == IToken.tLBRACKET) { |
| // array delete |
| consume(); |
| consume(IToken.tRBRACKET); |
| vectored = true; |
| } |
| IASTExpression castExpression = castExpression(scope, kind, key); |
| int endOffset = ( lastToken != null ) ? lastToken.getEndOffset() : 0; |
| try { |
| return astFactory.createExpression(scope, (vectored |
| ? IASTExpression.Kind.DELETE_VECTORCASTEXPRESSION |
| : IASTExpression.Kind.DELETE_CASTEXPRESSION), |
| castExpression, null, null, null, null, EMPTY_STRING, null); |
| } catch (ASTSemanticException e) { |
| throwBacktrack(e.getProblem()); |
| } catch (Exception e) { |
| logException("deleteExpression::createExpression()", e); //$NON-NLS-1$ |
| throwBacktrack(startingOffset, endOffset, line); |
| } |
| return null; |
| } |
| |
| /** |
| * Pazse a new-expression. |
| * |
| * @param expression |
| * @throws BacktrackException |
| * |
| * |
| * newexpression: ::? new newplacement? newtypeid newinitializer? |
| * ::? new newplacement? ( typeid ) newinitializer? |
| * newplacement: ( expressionlist ) |
| * newtypeid: typespecifierseq newdeclarator? |
| * newdeclarator: ptroperator newdeclarator? | directnewdeclarator |
| * directnewdeclarator: [ expression ] |
| * directnewdeclarator [ constantexpression ] |
| * newinitializer: ( expressionlist? ) |
| */ |
| protected IASTExpression newExpression(IASTScope scope, KeywordSetKey key) |
| throws BacktrackException, EndOfFileException { |
| setCompletionValues(scope, CompletionKind.NEW_TYPE_REFERENCE, |
| KeywordSetKey.EMPTY); |
| int startingOffset = LA(1).getOffset(); |
| int line = LA(1).getLineNumber(); |
| if (LT(1) == IToken.tCOLONCOLON) { |
| // global scope |
| consume(IToken.tCOLONCOLON); |
| } |
| consume(IToken.t_new); |
| boolean typeIdInParen = false; |
| boolean placementParseFailure = true; |
| IToken beforeSecondParen = null; |
| IToken backtrackMarker = null; |
| IASTTypeId typeId = null; |
| ArrayList newPlacementExpressions = new ArrayList(); |
| ArrayList newTypeIdExpressions = new ArrayList(); |
| ArrayList newInitializerExpressions = new ArrayList(); |
| |
| if (LT(1) == IToken.tLPAREN) { |
| consume(IToken.tLPAREN); |
| if (templateIdScopes != null) { |
| templateIdScopes.push(new Integer(IToken.tLPAREN)); |
| } |
| try { |
| // Try to consume placement list |
| // Note: since expressionList and expression are the same... |
| backtrackMarker = mark(); |
| newPlacementExpressions.add(expression(scope, |
| CompletionKind.SINGLE_NAME_REFERENCE, key)); |
| consume(IToken.tRPAREN); |
| if (templateIdScopes != null) { |
| templateIdScopes.pop(); |
| } //pop 1st Parent |
| placementParseFailure = false; |
| if (LT(1) == IToken.tLPAREN) { |
| beforeSecondParen = mark(); |
| consume(IToken.tLPAREN); |
| if (templateIdScopes != null) { |
| templateIdScopes.push(new Integer(IToken.tLPAREN)); |
| } //push 2nd Paren |
| typeIdInParen = true; |
| } |
| } catch (BacktrackException e) { |
| backup(backtrackMarker); |
| } |
| if (placementParseFailure) { |
| // CASE: new (typeid-not-looking-as-placement) ... |
| // the first expression in () is not a placement |
| // - then it has to be typeId |
| typeId = typeId(scope, true, CompletionKind.NEW_TYPE_REFERENCE); |
| consume(IToken.tRPAREN); |
| if (templateIdScopes != null) { |
| templateIdScopes.pop(); |
| } //pop 1st Paren |
| } else { |
| if (!typeIdInParen) { |
| if (LT(1) == IToken.tLBRACKET) { |
| // CASE: new (typeid-looking-as-placement) [expr]... |
| // the first expression in () has been parsed as a placement; |
| // however, we assume that it was in fact typeId, and this |
| // new statement creates an array. |
| // Do nothing, fallback to array/initializer processing |
| } else { |
| // CASE: new (placement) typeid ... |
| // the first expression in () is parsed as a placement, |
| // and the next expression doesn't start with '(' or '[' |
| // - then it has to be typeId |
| try { |
| backtrackMarker = mark(); |
| typeId = typeId(scope, true, |
| CompletionKind.NEW_TYPE_REFERENCE); |
| } catch (BacktrackException e) { |
| // Hmmm, so it wasn't typeId after all... Then it is |
| // CASE: new (typeid-looking-as-placement) |
| backup(backtrackMarker); |
| // TODO fix this |
| return null; |
| } |
| } |
| } else { |
| // Tricky cases: first expression in () is parsed as a placement, |
| // and the next expression starts with '('. |
| // The problem is, the first expression might as well be a typeid |
| try { |
| typeId = typeId(scope, true, |
| CompletionKind.NEW_TYPE_REFERENCE); |
| consume(IToken.tRPAREN); |
| if (templateIdScopes != null) { |
| templateIdScopes.pop(); |
| } //popping the 2nd Paren |
| |
| if (LT(1) == IToken.tLPAREN |
| || LT(1) == IToken.tLBRACKET) { |
| // CASE: new (placement)(typeid)(initializer) |
| // CASE: new (placement)(typeid)[] ... |
| // Great, so far all our assumptions have been correct |
| // Do nothing, fallback to array/initializer processing |
| } else { |
| // CASE: new (placement)(typeid) |
| // CASE: new (typeid-looking-as-placement)(initializer-looking-as-typeid) |
| // Worst-case scenario - this cannot be resolved w/o more semantic information. |
| // Luckily, we don't need to know what was that - we only know that |
| // new-expression ends here. |
| int endOffset = ( lastToken != null ) ? lastToken.getEndOffset() : 0; |
| try { |
| setCompletionValues(scope, |
| CompletionKind.NO_SUCH_KIND, |
| KeywordSetKey.EMPTY); |
| return astFactory.createExpression(scope, |
| IASTExpression.Kind.NEW_TYPEID, null, |
| null, null, typeId, null, EMPTY_STRING, |
| astFactory.createNewDescriptor( |
| newPlacementExpressions, |
| newTypeIdExpressions, |
| newInitializerExpressions)); |
| } catch (ASTSemanticException e) { |
| throwBacktrack(e.getProblem()); |
| } catch (Exception e) { |
| logException( |
| "newExpression_1::createExpression()", e); //$NON-NLS-1$ |
| throwBacktrack(startingOffset, endOffset, line); |
| } |
| } |
| } catch (BacktrackException e) { |
| // CASE: new (typeid-looking-as-placement)(initializer-not-looking-as-typeid) |
| // Fallback to initializer processing |
| backup(beforeSecondParen); |
| if (templateIdScopes != null) { |
| templateIdScopes.pop(); |
| }//pop that 2nd paren |
| } |
| } |
| } |
| } else { |
| // CASE: new typeid ... |
| // new parameters do not start with '(' |
| // i.e it has to be a plain typeId |
| typeId = typeId(scope, true, CompletionKind.NEW_TYPE_REFERENCE); |
| } |
| while (LT(1) == IToken.tLBRACKET) { |
| // array new |
| consume(); |
| |
| if (templateIdScopes != null) { |
| templateIdScopes.push(new Integer(IToken.tLBRACKET)); |
| } |
| |
| newTypeIdExpressions.add(assignmentExpression(scope, |
| CompletionKind.SINGLE_NAME_REFERENCE, key)); |
| consume(IToken.tRBRACKET); |
| |
| if (templateIdScopes != null) { |
| templateIdScopes.pop(); |
| } |
| } |
| // newinitializer |
| if (LT(1) == IToken.tLPAREN) { |
| consume(IToken.tLPAREN); |
| setCurrentFunctionName(((typeId != null) ? typeId |
| .getFullSignature() : EMPTY_STRING)); |
| setCompletionValues(scope, CompletionKind.CONSTRUCTOR_REFERENCE); |
| if (templateIdScopes != null) { |
| templateIdScopes.push(new Integer(IToken.tLPAREN)); |
| } |
| |
| //we want to know the difference between no newInitializer and an empty new Initializer |
| //if the next token is the RPAREN, then we have an Empty expression in our list. |
| newInitializerExpressions.add(expression(scope, |
| CompletionKind.CONSTRUCTOR_REFERENCE, key)); |
| |
| setCurrentFunctionName(EMPTY_STRING); |
| consume(IToken.tRPAREN); |
| if (templateIdScopes != null) { |
| templateIdScopes.pop(); |
| } |
| } |
| setCompletionValues(scope, CompletionKind.NO_SUCH_KIND, |
| KeywordSetKey.EMPTY); |
| int endOffset = ( lastToken != null ) ? lastToken.getEndOffset() : 0; |
| try { |
| return astFactory.createExpression(scope, |
| IASTExpression.Kind.NEW_TYPEID, null, null, null, typeId, |
| null, EMPTY_STRING, astFactory.createNewDescriptor( |
| newPlacementExpressions, newTypeIdExpressions, |
| newInitializerExpressions)); |
| } catch (ASTSemanticException e) { |
| throwBacktrack(e.getProblem()); |
| return null; |
| } catch (Exception e) { |
| logException("newExpression_2::createExpression()", e); //$NON-NLS-1$ |
| throwBacktrack(startingOffset, endOffset, line); |
| } |
| return null; |
| } |
| |
| /** |
| * @param functionName |
| */ |
| protected void setCurrentFunctionName(String functionName) { |
| } |
| |
| /** |
| * @param expression |
| * @throws BacktrackException |
| */ |
| public IASTExpression unaryExpression(IASTScope scope, CompletionKind kind, |
| KeywordSetKey key) throws EndOfFileException, BacktrackException { |
| int startingOffset = LA(1).getOffset(); |
| int line = LA(1).getLineNumber(); |
| switch (LT(1)) { |
| case IToken.tSTAR : |
| consume(); |
| return unaryOperatorCastExpression(scope, |
| IASTExpression.Kind.UNARY_STAR_CASTEXPRESSION, kind, |
| key); |
| case IToken.tAMPER : |
| consume(); |
| return unaryOperatorCastExpression(scope, |
| IASTExpression.Kind.UNARY_AMPSND_CASTEXPRESSION, kind, |
| key); |
| case IToken.tPLUS : |
| consume(); |
| return unaryOperatorCastExpression(scope, |
| IASTExpression.Kind.UNARY_PLUS_CASTEXPRESSION, kind, |
| key); |
| case IToken.tMINUS : |
| consume(); |
| return unaryOperatorCastExpression(scope, |
| IASTExpression.Kind.UNARY_MINUS_CASTEXPRESSION, kind, |
| key); |
| case IToken.tNOT : |
| consume(); |
| return unaryOperatorCastExpression(scope, |
| IASTExpression.Kind.UNARY_NOT_CASTEXPRESSION, kind, key); |
| case IToken.tCOMPL : |
| consume(); |
| return unaryOperatorCastExpression(scope, |
| IASTExpression.Kind.UNARY_TILDE_CASTEXPRESSION, kind, |
| key); |
| case IToken.tINCR : |
| consume(); |
| return unaryOperatorCastExpression(scope, |
| IASTExpression.Kind.UNARY_INCREMENT, kind, key); |
| case IToken.tDECR : |
| consume(); |
| return unaryOperatorCastExpression(scope, |
| IASTExpression.Kind.UNARY_DECREMENT, kind, key); |
| case IToken.t_sizeof : |
| consume(IToken.t_sizeof); |
| IToken mark = LA(1); |
| IASTTypeId d = null; |
| IASTExpression unaryExpression = null; |
| if (LT(1) == IToken.tLPAREN) { |
| try { |
| consume(IToken.tLPAREN); |
| d = typeId(scope, false, |
| CompletionKind.SINGLE_NAME_REFERENCE); |
| consume(IToken.tRPAREN); |
| } catch (BacktrackException bt) { |
| backup(mark); |
| unaryExpression = unaryExpression(scope, kind, key); |
| } |
| } else { |
| unaryExpression = unaryExpression(scope, kind, key); |
| } |
| int endOffset = ( lastToken != null ) ? lastToken.getEndOffset() : 0; |
| if (unaryExpression == null) |
| try { |
| return astFactory.createExpression(scope, |
| IASTExpression.Kind.UNARY_SIZEOF_TYPEID, null, |
| null, null, d, null, EMPTY_STRING, null); |
| } catch (ASTSemanticException e) { |
| throwBacktrack(e.getProblem()); |
| } catch (Exception e) { |
| logException("unaryExpression_1::createExpression()", e); //$NON-NLS-1$ |
| throwBacktrack(startingOffset, endOffset, line); |
| } |
| try { |
| return astFactory.createExpression(scope, |
| IASTExpression.Kind.UNARY_SIZEOF_UNARYEXPRESSION, |
| unaryExpression, null, null, null, null, |
| EMPTY_STRING, null); |
| } catch (ASTSemanticException e1) { |
| throwBacktrack(e1.getProblem()); |
| } catch (Exception e) { |
| logException("unaryExpression_1::createExpression()", e); //$NON-NLS-1$ |
| throwBacktrack(startingOffset, endOffset, line); |
| } |
| case IToken.t_new : |
| return newExpression(scope, key); |
| case IToken.t_delete : |
| return deleteExpression(scope, kind, key); |
| case IToken.tCOLONCOLON : |
| if (queryLookaheadCapability(2)) { |
| switch (LT(2)) { |
| case IToken.t_new : |
| return newExpression(scope, key); |
| case IToken.t_delete : |
| return deleteExpression(scope, kind, key); |
| default : |
| return postfixExpression(scope, kind, key); |
| } |
| } |
| default : |
| if (extension.isValidUnaryExpressionStart(LT(1))) { |
| IASTExpression extensionExpression = extension |
| .parseUnaryExpression(scope, this, kind, key); |
| if (extensionExpression != null) |
| return extensionExpression; |
| } |
| return postfixExpression(scope, kind, key); |
| } |
| } |
| |
| /** |
| * @param expression |
| * @throws BacktrackException |
| */ |
| protected IASTExpression postfixExpression(IASTScope scope, |
| CompletionKind kind, KeywordSetKey key) throws EndOfFileException, |
| BacktrackException { |
| int startingOffset = LA(1).getOffset(); |
| int line = LA(1).getLineNumber(); |
| IASTExpression firstExpression = null; |
| boolean isTemplate = false; |
| |
| setCompletionValues(scope, kind, key); |
| switch (LT(1)) { |
| case IToken.t_typename : |
| consume(IToken.t_typename); |
| |
| boolean templateTokenConsumed = false; |
| if (LT(1) == IToken.t_template) { |
| consume(IToken.t_template); |
| templateTokenConsumed = true; |
| } |
| ITokenDuple nestedName = name(scope, |
| CompletionKind.TYPE_REFERENCE, KeywordSetKey.EMPTY); |
| |
| consume(IToken.tLPAREN); |
| if (templateIdScopes != null) { |
| templateIdScopes.push(new Integer(IToken.tLPAREN)); |
| } |
| IASTExpression expressionList = expression(scope, |
| CompletionKind.TYPE_REFERENCE, key); |
| int endOffset = consume(IToken.tRPAREN).getEndOffset(); |
| if (templateIdScopes != null) { |
| templateIdScopes.pop(); |
| } |
| |
| try { |
| firstExpression = astFactory |
| .createExpression( |
| scope, |
| (templateTokenConsumed |
| ? IASTExpression.Kind.POSTFIX_TYPENAME_TEMPLATEID |
| : IASTExpression.Kind.POSTFIX_TYPENAME_IDENTIFIER), |
| expressionList, null, null, null, |
| nestedName, EMPTY_STRING, null); |
| } catch (ASTSemanticException ase) { |
| throwBacktrack(ase.getProblem()); |
| } catch (Exception e) { |
| logException("postfixExpression_1::createExpression()", e); //$NON-NLS-1$ |
| throwBacktrack(startingOffset, endOffset, line); |
| } |
| break; |
| // simple-type-specifier ( assignment-expression , .. ) |
| case IToken.t_char : |
| firstExpression = simpleTypeConstructorExpression(scope, |
| IASTExpression.Kind.POSTFIX_SIMPLETYPE_CHAR, key); |
| break; |
| case IToken.t_wchar_t : |
| firstExpression = simpleTypeConstructorExpression(scope, |
| IASTExpression.Kind.POSTFIX_SIMPLETYPE_WCHART, key); |
| break; |
| case IToken.t_bool : |
| firstExpression = simpleTypeConstructorExpression(scope, |
| IASTExpression.Kind.POSTFIX_SIMPLETYPE_BOOL, key); |
| break; |
| case IToken.t_short : |
| firstExpression = simpleTypeConstructorExpression(scope, |
| IASTExpression.Kind.POSTFIX_SIMPLETYPE_SHORT, key); |
| break; |
| case IToken.t_int : |
| firstExpression = simpleTypeConstructorExpression(scope, |
| IASTExpression.Kind.POSTFIX_SIMPLETYPE_INT, key); |
| break; |
| case IToken.t_long : |
| firstExpression = simpleTypeConstructorExpression(scope, |
| IASTExpression.Kind.POSTFIX_SIMPLETYPE_LONG, key); |
| break; |
| case IToken.t_signed : |
| firstExpression = simpleTypeConstructorExpression(scope, |
| IASTExpression.Kind.POSTFIX_SIMPLETYPE_SIGNED, key); |
| break; |
| case IToken.t_unsigned : |
| firstExpression = simpleTypeConstructorExpression(scope, |
| IASTExpression.Kind.POSTFIX_SIMPLETYPE_UNSIGNED, key); |
| break; |
| case IToken.t_float : |
| firstExpression = simpleTypeConstructorExpression(scope, |
| IASTExpression.Kind.POSTFIX_SIMPLETYPE_FLOAT, key); |
| break; |
| case IToken.t_double : |
| firstExpression = simpleTypeConstructorExpression(scope, |
| IASTExpression.Kind.POSTFIX_SIMPLETYPE_DOUBLE, key); |
| break; |
| case IToken.t_dynamic_cast : |
| firstExpression = specialCastExpression(scope, |
| IASTExpression.Kind.POSTFIX_DYNAMIC_CAST, key); |
| break; |
| case IToken.t_static_cast : |
| firstExpression = specialCastExpression(scope, |
| IASTExpression.Kind.POSTFIX_STATIC_CAST, key); |
| break; |
| case IToken.t_reinterpret_cast : |
| firstExpression = specialCastExpression(scope, |
| IASTExpression.Kind.POSTFIX_REINTERPRET_CAST, key); |
| break; |
| case IToken.t_const_cast : |
| firstExpression = specialCastExpression(scope, |
| IASTExpression.Kind.POSTFIX_CONST_CAST, key); |
| break; |
| case IToken.t_typeid : |
| consume(); |
| consume(IToken.tLPAREN); |
| if (templateIdScopes != null) { |
| templateIdScopes.push(new Integer(IToken.tLPAREN)); |
| } |
| boolean isTypeId = true; |
| IASTExpression lhs = null; |
| IASTTypeId typeId = null; |
| try { |
| typeId = typeId(scope, false, CompletionKind.TYPE_REFERENCE); |
| } catch (BacktrackException b) { |
| isTypeId = false; |
| lhs = expression(scope, CompletionKind.TYPE_REFERENCE, key); |
| } |
| endOffset = consume(IToken.tRPAREN).getEndOffset(); |
| if (templateIdScopes != null) { |
| templateIdScopes.pop(); |
| } |
| try { |
| firstExpression = astFactory |
| .createExpression( |
| scope, |
| (isTypeId |
| ? IASTExpression.Kind.POSTFIX_TYPEID_TYPEID |
| : IASTExpression.Kind.POSTFIX_TYPEID_EXPRESSION), |
| lhs, null, null, typeId, null, |
| EMPTY_STRING, null); |
| } catch (ASTSemanticException e6) { |
| throwBacktrack(e6.getProblem()); |
| } catch (Exception e) { |
| logException("postfixExpression_2::createExpression()", e); //$NON-NLS-1$ |
| throwBacktrack(startingOffset, endOffset, line); |
| } |
| break; |
| default : |
| firstExpression = primaryExpression(scope, kind, key); |
| } |
| IASTExpression secondExpression = null; |
| for (;;) { |
| switch (LT(1)) { |
| case IToken.tLBRACKET : |
| // array access |
| consume(IToken.tLBRACKET); |
| if (templateIdScopes != null) { |
| templateIdScopes.push(new Integer(IToken.tLBRACKET)); |
| } |
| secondExpression = expression(scope, |
| CompletionKind.SINGLE_NAME_REFERENCE, key); |
| int endOffset = consume(IToken.tRBRACKET).getEndOffset(); |
| if (templateIdScopes != null) { |
| templateIdScopes.pop(); |
| } |
| try { |
| firstExpression = astFactory.createExpression(scope, |
| IASTExpression.Kind.POSTFIX_SUBSCRIPT, |
| firstExpression, secondExpression, null, null, |
| null, EMPTY_STRING, null); |
| } catch (ASTSemanticException e2) { |
| throwBacktrack(e2.getProblem()); |
| } catch (Exception e) { |
| logException( |
| "postfixExpression_3::createExpression()", e); //$NON-NLS-1$ |
| throwBacktrack(startingOffset, endOffset, line); |
| } |
| break; |
| case IToken.tLPAREN : |
| // function call |
| consume(IToken.tLPAREN); |
| IASTNode context = null; |
| if (firstExpression != null) { |
| if (firstExpression.getExpressionKind() == IASTExpression.Kind.ID_EXPRESSION) |
| setCurrentFunctionName(firstExpression |
| .getIdExpression()); |
| else if (firstExpression.getRHSExpression() != null |
| && firstExpression.getRHSExpression() |
| .getIdExpression() != null) { |
| setCurrentFunctionName(firstExpression |
| .getRHSExpression().getIdExpression()); |
| context = astFactory |
| .expressionToMostPreciseASTNode(scope, |
| firstExpression.getLHSExpression()); |
| } |
| } |
| |
| if (templateIdScopes != null) { |
| templateIdScopes.push(new Integer(IToken.tLPAREN)); |
| } |
| setCompletionValues(scope, |
| CompletionKind.FUNCTION_REFERENCE, context); |
| secondExpression = expression(scope, |
| CompletionKind.FUNCTION_REFERENCE, key); |
| setCurrentFunctionName(EMPTY_STRING); |
| endOffset = consume(IToken.tRPAREN).getEndOffset(); |
| if (templateIdScopes != null) { |
| templateIdScopes.pop(); |
| } |
| try { |
| firstExpression = astFactory.createExpression(scope, |
| IASTExpression.Kind.POSTFIX_FUNCTIONCALL, |
| firstExpression, secondExpression, null, null, |
| null, EMPTY_STRING, null); |
| } catch (ASTSemanticException e3) { |
| throwBacktrack(e3.getProblem()); |
| } catch (Exception e) { |
| logException( |
| "postfixExpression_4::createExpression()", e); //$NON-NLS-1$ |
| throwBacktrack(startingOffset, endOffset, line); |
| } |
| break; |
| case IToken.tINCR : |
| endOffset = consume(IToken.tINCR).getEndOffset(); |
| try { |
| firstExpression = astFactory.createExpression(scope, |
| IASTExpression.Kind.POSTFIX_INCREMENT, |
| firstExpression, null, null, null, null, |
| EMPTY_STRING, null); |
| } catch (ASTSemanticException e1) { |
| throwBacktrack(e1.getProblem()); |
| } catch (Exception e) { |
| logException( |
| "postfixExpression_5::createExpression()", e); //$NON-NLS-1$ |
| throwBacktrack(startingOffset, endOffset, line); |
| } |
| break; |
| case IToken.tDECR : |
| endOffset = consume().getEndOffset(); |
| try { |
| firstExpression = astFactory.createExpression(scope, |
| IASTExpression.Kind.POSTFIX_DECREMENT, |
| firstExpression, null, null, null, null, |
| EMPTY_STRING, null); |
| } catch (ASTSemanticException e4) { |
| throwBacktrack(e4.getProblem()); |
| } catch (Exception e) { |
| logException( |
| "postfixExpression_6::createExpression()", e); //$NON-NLS-1$ |
| throwBacktrack(startingOffset, endOffset, line); |
| } |
| break; |
| case IToken.tDOT : |
| // member access |
| consume(IToken.tDOT); |
| |
| if (queryLookaheadCapability()) |
| if (LT(1) == IToken.t_template) { |
| consume(IToken.t_template); |
| isTemplate = true; |
| } |
| |
| Kind memberCompletionKind = (isTemplate |
| ? IASTExpression.Kind.POSTFIX_DOT_TEMPL_IDEXPRESS |
| : IASTExpression.Kind.POSTFIX_DOT_IDEXPRESSION); |
| |
| setCompletionValues(scope, CompletionKind.MEMBER_REFERENCE, |
| KeywordSetKey.EMPTY, firstExpression, |
| memberCompletionKind); |
| secondExpression = primaryExpression(scope, |
| CompletionKind.MEMBER_REFERENCE, key); |
| endOffset = ( lastToken != null ) ? lastToken.getEndOffset() : 0; |
| if (secondExpression != null |
| && secondExpression.getExpressionKind() == Kind.ID_EXPRESSION |
| && secondExpression.getIdExpression().indexOf('~') != -1) |
| memberCompletionKind = Kind.POSTFIX_DOT_DESTRUCTOR; |
| |
| try { |
| firstExpression = astFactory.createExpression(scope, |
| memberCompletionKind, firstExpression, |
| secondExpression, null, null, null, |
| EMPTY_STRING, null); |
| } catch (ASTSemanticException e5) { |
| throwBacktrack(e5.getProblem()); |
| } catch (Exception e) { |
| logException( |
| "postfixExpression_7::createExpression()", e); //$NON-NLS-1$ |
| throwBacktrack(startingOffset, endOffset, line); |
| } |
| break; |
| case IToken.tARROW : |
| // member access |
| consume(IToken.tARROW); |
| |
| if (queryLookaheadCapability()) |
| if (LT(1) == IToken.t_template) { |
| consume(IToken.t_template); |
| isTemplate = true; |
| } |
| |
| Kind arrowCompletionKind = (isTemplate |
| ? IASTExpression.Kind.POSTFIX_ARROW_TEMPL_IDEXP |
| : IASTExpression.Kind.POSTFIX_ARROW_IDEXPRESSION); |
| |
| setCompletionValues(scope, CompletionKind.MEMBER_REFERENCE, |
| KeywordSetKey.EMPTY, firstExpression, |
| arrowCompletionKind); |
| secondExpression = primaryExpression(scope, |
| CompletionKind.MEMBER_REFERENCE, key); |
| endOffset = ( lastToken != null ) ? lastToken.getEndOffset() : 0; |
| if (secondExpression != null |
| && secondExpression.getExpressionKind() == Kind.ID_EXPRESSION |
| && secondExpression.getIdExpression().indexOf('~') != -1) |
| arrowCompletionKind = Kind.POSTFIX_ARROW_DESTRUCTOR; |
| try { |
| firstExpression = astFactory.createExpression(scope, |
| arrowCompletionKind, firstExpression, |
| secondExpression, null, null, null, |
| EMPTY_STRING, null); |
| } catch (ASTSemanticException e) { |
| throwBacktrack(e.getProblem()); |
| } catch (Exception e) { |
| logException( |
| "postfixExpression_8::createExpression()", e); //$NON-NLS-1$ |
| throwBacktrack(startingOffset, endOffset, line); |
| } |
| break; |
| default : |
| return firstExpression; |
| } |
| } |
| } |
| |
| /** |
| * @return |
| * @throws EndOfFileException |
| */ |
| protected boolean queryLookaheadCapability(int count) |
| throws EndOfFileException { |
| //make sure we can look ahead one before doing this |
| boolean result = true; |
| try { |
| LA(count); |
| } catch (EndOfFileException olre) { |
| result = false; |
| } |
| return result; |
| } |
| |
| protected boolean queryLookaheadCapability() throws EndOfFileException { |
| return queryLookaheadCapability(1); |
| } |
| |
| protected void checkEndOfFile() throws EndOfFileException { |
| LA(1); |
| } |
| |
| protected IASTExpression simpleTypeConstructorExpression(IASTScope scope, |
| Kind type, KeywordSetKey key) throws EndOfFileException, |
| BacktrackException { |
| int startingOffset = LA(1).getOffset(); |
| int line = LA(1).getLineNumber(); |
| String typeName = consume().getImage(); |
| consume(IToken.tLPAREN); |
| setCurrentFunctionName(typeName); |
| IASTExpression inside = expression(scope, |
| CompletionKind.CONSTRUCTOR_REFERENCE, key); |
| setCurrentFunctionName(EMPTY_STRING); |
| int endOffset = consume(IToken.tRPAREN).getEndOffset(); |
| try { |
| return astFactory.createExpression(scope, type, inside, null, null, |
| null, null, EMPTY_STRING, null); |
| } catch (ASTSemanticException e) { |
| throwBacktrack(e.getProblem()); |
| } catch (Exception e) { |
| logException( |
| "simpleTypeConstructorExpression::createExpression()", e); //$NON-NLS-1$ |
| throwBacktrack(startingOffset, endOffset, line); |
| } |
| return null; |
| } |
| |
| /** |
| * @param expression |
| * @throws BacktrackException |
| */ |
| protected IASTExpression primaryExpression(IASTScope scope, |
| CompletionKind kind, KeywordSetKey key) throws EndOfFileException, |
| BacktrackException { |
| IToken t = null; |
| switch (LT(1)) { |
| // TO DO: we need more literals... |
| case IToken.tINTEGER : |
| t = consume(); |
| try { |
| return astFactory.createExpression(scope, |
| IASTExpression.Kind.PRIMARY_INTEGER_LITERAL, null, |
| null, null, null, null, t.getImage(), null); |
| } catch (ASTSemanticException e1) { |
| throwBacktrack(e1.getProblem()); |
| } catch (Exception e) { |
| logException("primaryExpression_1::createExpression()", e); //$NON-NLS-1$ |
| throwBacktrack(t.getOffset(), t.getEndOffset(), t.getLineNumber()); |
| } |
| case IToken.tFLOATINGPT : |
| t = consume(); |
| try { |
| return astFactory.createExpression(scope, |
| IASTExpression.Kind.PRIMARY_FLOAT_LITERAL, null, |
| null, null, null, null, t.getImage(), null); |
| } catch (ASTSemanticException e2) { |
| throwBacktrack(e2.getProblem()); |
| } catch (Exception e) { |
| logException("primaryExpression_2::createExpression()", e); //$NON-NLS-1$ |
| throwBacktrack(t.getOffset(), t.getEndOffset(), t.getLineNumber()); |
| } |
| case IToken.tSTRING : |
| case IToken.tLSTRING : |
| t = consume(); |
| try { |
| return astFactory.createExpression(scope, |
| IASTExpression.Kind.PRIMARY_STRING_LITERAL, null, |
| null, null, null, null, t.getImage(), null); |
| } catch (ASTSemanticException e5) { |
| throwBacktrack(e5.getProblem()); |
| } catch (Exception e) { |
| logException("primaryExpression_3::createExpression()", e); //$NON-NLS-1$ |
| throwBacktrack(t.getOffset(), t.getEndOffset(), t.getLineNumber()); |
| } |
| |
| case IToken.t_false : |
| case IToken.t_true : |
| t = consume(); |
| try { |
| return astFactory.createExpression(scope, |
| IASTExpression.Kind.PRIMARY_BOOLEAN_LITERAL, null, |
| null, null, null, null, t.getImage(), null); |
| } catch (ASTSemanticException e3) { |
| throwBacktrack(e3.getProblem()); |
| } catch (Exception e) { |
| logException("primaryExpression_4::createExpression()", e); //$NON-NLS-1$ |
| throwBacktrack(t.getOffset(), t.getEndOffset(), t.getLineNumber()); |
| } |
| |
| case IToken.tCHAR : |
| case IToken.tLCHAR : |
| |
| t = consume(); |
| try { |
| return astFactory.createExpression(scope, |
| IASTExpression.Kind.PRIMARY_CHAR_LITERAL, null, |
| null, null, null, null, t.getImage(), null); |
| } catch (ASTSemanticException e4) { |
| throwBacktrack(e4.getProblem()); |
| } catch (Exception e) { |
| logException("primaryExpression_5::createExpression()", e); //$NON-NLS-1$ |
| throwBacktrack(t.getOffset(), t.getEndOffset(), t.getLineNumber()); |
| } |
| |
| case IToken.t_this : |
| t = consume(IToken.t_this); |
| try { |
| return astFactory.createExpression(scope, |
| IASTExpression.Kind.PRIMARY_THIS, null, null, null, |
| null, null, EMPTY_STRING, null); |
| } catch (ASTSemanticException e7) { |
| throwBacktrack(e7.getProblem()); |
| } catch (Exception e) { |
| logException("primaryExpression_6::createExpression()", e); //$NON-NLS-1$ |
| throwBacktrack(t.getOffset(), t.getEndOffset(), t.getLineNumber()); |
| } |
| case IToken.tLPAREN : |
| t = consume(); |
| if (templateIdScopes != null) { |
| templateIdScopes.push(new Integer(IToken.tLPAREN)); |
| } |
| IASTExpression lhs = expression(scope, kind, key); |
| int endOffset = consume(IToken.tRPAREN).getEndOffset(); |
| if (templateIdScopes != null) { |
| templateIdScopes.pop(); |
| } |
| try { |
| return astFactory.createExpression(scope, |
| IASTExpression.Kind.PRIMARY_BRACKETED_EXPRESSION, |
| lhs, null, null, null, null, EMPTY_STRING, null); |
| } catch (ASTSemanticException e6) { |
| throwBacktrack(e6.getProblem()); |
| } catch (Exception e) { |
| logException("primaryExpression_7::createExpression()", e); //$NON-NLS-1$ |
| throwBacktrack(t.getOffset(), endOffset, t.getLineNumber() ); |
| } |
| case IToken.tIDENTIFIER : |
| case IToken.tCOLONCOLON : |
| case IToken.t_operator : |
| case IToken.tCOMPL : |
| ITokenDuple duple = null; |
| int startingOffset = LA(1).getOffset(); |
| int line = LA(1).getLineNumber(); |
| try { |
| duple = name(scope, kind, key); |
| } catch (BacktrackException bt) { |
| IToken mark = mark(); |
| Declarator d = new Declarator(new DeclarationWrapper(scope, |
| mark.getOffset(), mark.getLineNumber(), null)); |
| |
| if (LT(1) == IToken.tCOLONCOLON |
| || LT(1) == IToken.tIDENTIFIER) { |
| IToken start = consume(); |
| IToken end = null; |
| if (start.getType() == IToken.tIDENTIFIER) |
| end = consumeTemplateParameters(end); |
| while (LT(1) == IToken.tCOLONCOLON |
| || LT(1) == IToken.tIDENTIFIER) { |
| end = consume(); |
| if (end.getType() == IToken.tIDENTIFIER) |
| end = consumeTemplateParameters(end); |
| } |
| if (LT(1) == IToken.t_operator) |
| operatorId(d, start, null, kind); |
| else { |
| backup(mark); |
| throwBacktrack(startingOffset, end.getEndOffset(), end.getLineNumber()); |
| } |
| } else if (LT(1) == IToken.t_operator) |
| operatorId(d, null, null, kind); |
| |
| duple = d.getNameDuple(); |
| } |
| |
| endOffset = ( lastToken != null ) ? lastToken.getEndOffset() : 0; |
| try { |
| return astFactory.createExpression(scope, |
| IASTExpression.Kind.ID_EXPRESSION, null, null, |
| null, null, duple, EMPTY_STRING, null); |
| } catch (ASTSemanticException e8) { |
| throwBacktrack(e8.getProblem()); |
| } catch (Exception e) { |
| logException("primaryExpression_8::createExpression()", e); //$NON-NLS-1$ |
| throwBacktrack(startingOffset, endOffset, line); |
| } |
| default : |
| startingOffset = LA(1).getOffset(); |
| line = LA(1).getLineNumber(); |
| if (!queryLookaheadCapability(2)) { |
| if (LA(1).canBeAPrefix()) { |
| consume(); |
| checkEndOfFile(); |
| } |
| } |
| IASTExpression empty = null; |
| try { |
| empty = astFactory.createExpression(scope, |
| IASTExpression.Kind.PRIMARY_EMPTY, null, null, |
| null, null, null, EMPTY_STRING, null); |
| } catch (ASTSemanticException e9) { |
| throwBacktrack( e9.getProblem() ); |
| return null; |
| } catch (Exception e) { |
| logException("primaryExpression_9::createExpression()", e); //$NON-NLS-1$ |
| throwBacktrack(startingOffset, 0, line); |
| } |
| return empty; |
| } |
| |
| } |
| |
| /** |
| * Fetches a token from the scanner. |
| * |
| * @return the next token from the scanner |
| * @throws EndOfFileException thrown when the scanner.nextToken() yields no tokens |
| */ |
| protected IToken fetchToken() throws EndOfFileException { |
| if (limitReached) |
| throw new EndOfFileException(); |
| |
| try { |
| IToken value = scanner.nextToken(); |
| return value; |
| } catch (OffsetLimitReachedException olre) { |
| limitReached = true; |
| handleOffsetLimitException(olre); |
| return null; |
| } catch (ScannerException e) { |
| TraceUtil |
| .outputTrace( |
| log, |
| "ScannerException thrown : ", e.getProblem(), null, null, null); //$NON-NLS-1$ |
| // log.errorLog("Scanner Exception: " + e.getProblem().getMessage()); //$NON-NLS-1$ |
| return fetchToken(); |
| } |
| } |
| |
| /** |
| * @param value |
| */ |
| protected void handleNewToken(IToken value) { |
| } |
| |
| protected void handleOffsetLimitException( |
| OffsetLimitReachedException exception) throws EndOfFileException { |
| // unexpected, throw EOF instead (equivalent) |
| throw new EndOfFileException(); |
| } |
| |
| protected IASTExpression assignmentOperatorExpression(IASTScope scope, |
| IASTExpression.Kind kind, IASTExpression lhs, |
| CompletionKind completionKind, KeywordSetKey key) |
| throws EndOfFileException, BacktrackException { |
| IToken t = consume(); |
| IASTExpression assignmentExpression = assignmentExpression(scope, |
| completionKind, key); |
| int endOffset = ( lastToken != null ) ? lastToken.getEndOffset() : 0; |
| try { |
| return astFactory.createExpression(scope, kind, lhs, |
| assignmentExpression, null, null, null, EMPTY_STRING, null); |
| } catch (ASTSemanticException e) { |
| throwBacktrack(e.getProblem()); |
| } catch (Exception e) { |
| logException("assignmentOperatorExpression::createExpression()", e); //$NON-NLS-1$ |
| throwBacktrack(t.getOffset(), endOffset, t.getLineNumber()); |
| } |
| return null; |
| } |
| |
| protected void setCompletionValues(IASTScope scope, |
| IASTCompletionNode.CompletionKind kind, KeywordSetKey key) |
| throws EndOfFileException { |
| } |
| |
| protected void setCompletionValues(IASTScope scope, |
| IASTCompletionNode.CompletionKind kind, KeywordSetKey key, |
| IASTNode node, String prefix) throws EndOfFileException { |
| } |
| |
| protected void setCompletionValues(IASTScope scope, CompletionKind kind, |
| KeywordSetKey key, IASTExpression firstExpression, |
| Kind expressionKind) throws EndOfFileException { |
| } |
| |
| protected void setCompletionValues(IASTScope scope, CompletionKind kind, |
| IToken first, IToken last, KeywordSetKey key) |
| throws EndOfFileException { |
| } |
| |
| protected IASTExpression unaryOperatorCastExpression(IASTScope scope, |
| IASTExpression.Kind kind, CompletionKind completionKind, |
| KeywordSetKey key) throws EndOfFileException, BacktrackException { |
| int startingOffset = LA(1).getOffset(); |
| int line = LA(1).getLineNumber(); |
| IASTExpression castExpression = castExpression(scope, completionKind, |
| key); |
| int endOffset = ( lastToken != null ) ? lastToken.getEndOffset() : 0; |
| try { |
| return astFactory.createExpression(scope, kind, castExpression, |
| null, null, null, null, EMPTY_STRING, null); |
| } catch (ASTSemanticException e) { |
| throwBacktrack(e.getProblem()); |
| } catch (Exception e) { |
| logException("unaryOperatorCastExpression::createExpression()", e); //$NON-NLS-1$ |
| throwBacktrack(startingOffset, endOffset, line); |
| } |
| return null; |
| } |
| |
| protected IASTExpression specialCastExpression(IASTScope scope, |
| IASTExpression.Kind kind, KeywordSetKey key) |
| throws EndOfFileException, BacktrackException { |
| int line = LA(1).getLineNumber(); |
| int startingOffset = consume().getOffset(); |
| consume(IToken.tLT); |
| IASTTypeId duple = typeId(scope, false, CompletionKind.TYPE_REFERENCE); |
| consume(IToken.tGT); |
| consume(IToken.tLPAREN); |
| IASTExpression lhs = expression(scope, |
| CompletionKind.SINGLE_NAME_REFERENCE, key); |
| int endOffset = consume(IToken.tRPAREN).getEndOffset(); |
| try { |
| return astFactory.createExpression(scope, kind, lhs, null, null, |
| duple, null, EMPTY_STRING, null); |
| } catch (ASTSemanticException e) { |
| throwBacktrack(e.getProblem()); |
| } catch (Exception e) { |
| logException("specialCastExpression::createExpression()", e); //$NON-NLS-1$ |
| throwBacktrack(startingOffset, endOffset, line ); |
| } |
| return null; |
| } |
| |
| public char[] getCurrentFilename() { |
| return scanner.getCurrentFilename(); |
| } |
| |
| protected boolean parserTimeout() { |
| return false; |
| } |
| /* (non-Javadoc) |
| * @see org.eclipse.cdt.internal.core.parser.IParserData#getLastToken() |
| */ |
| public IToken getLastToken() { |
| return lastToken; |
| } |
| /* (non-Javadoc) |
| * @see org.eclipse.cdt.internal.core.parser.IParserData#getParserLanguage() |
| */ |
| public final ParserLanguage getParserLanguage() { |
| return language; |
| } |
| /** |
| * Parse an identifier. |
| * |
| * @throws BacktrackException request a backtrack |
| */ |
| public IToken identifier() throws EndOfFileException, BacktrackException { |
| IToken first = consume(IToken.tIDENTIFIER); // throws backtrack if its not that |
| if( first instanceof ITokenDuple ) setGreaterNameContext((ITokenDuple) first); |
| return first; |
| } |
| /* (non-Javadoc) |
| * @see org.eclipse.cdt.core.parser.IFilenameProvider#getCurrentFileIndex() |
| */ |
| public int getCurrentFileIndex() { |
| return scanner.getCurrentFileIndex(); |
| } |
| /* (non-Javadoc) |
| * @see org.eclipse.cdt.core.parser.IFilenameProvider#getFilenameForIndex(int) |
| */ |
| public String getFilenameForIndex(int index) { |
| return scanner.getFilenameForIndex(index); |
| } |
| |
| public boolean validateCaches() { |
| return true; |
| } |
| |
| /* (non-Javadoc) |
| * @see java.lang.Object#toString() |
| */ |
| public String toString() { |
| return scanner.toString(); //$NON-NLS-1$ |
| } |
| |
| /** |
| * @return Returns the backtrackCount. |
| */ |
| public final int getBacktrackCount() { |
| return backtrackCount; |
| } |
| |
| /** |
| * @param bt |
| */ |
| protected void throwBacktrack(BacktrackException bt) throws BacktrackException { |
| throw bt; |
| } |
| |
| /** |
| * @throws EndOfFileException |
| */ |
| protected void errorHandling() throws EndOfFileException { |
| int depth = ( LT(1) == IToken.tLBRACE ) ? 1 : 0; |
| consume(); |
| while (!((LT(1) == IToken.tSEMI && depth == 0) |
| || (LT(1) == IToken.tRBRACE && depth == 1))) |
| { |
| switch (LT(1)) |
| { |
| case IToken.tLBRACE : |
| ++depth; |
| break; |
| case IToken.tRBRACE : |
| --depth; |
| break; |
| } |
| if( depth < 0 ) |
| return; |
| |
| consume(); |
| } |
| // eat the SEMI/RBRACE as well |
| consume(); |
| } |
| } |