blob: cf8f766983be7b145dc0760ccba34eec5c57c6c3 [file] [log] [blame]
/*******************************************************************************
* 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();
}
}