blob: 6805658dff373013f5cb7da704d638cb8dec9ad0 [file] [log] [blame]
package org.eclipse.jdt.internal.codeassist.impl;
/*
* (c) Copyright IBM Corp. 2000, 2001.
* All Rights Reserved.
*/
/*
* Parser extension for code assist task
*
*/
import org.eclipse.jdt.internal.compiler.ast.*;
import org.eclipse.jdt.internal.compiler.parser.*;
import org.eclipse.jdt.internal.compiler.problem.*;
public abstract class AssistParser extends Parser {
public AstNode assistNode;
public boolean isOrphanCompletionNode;
/* recovery */
int[] blockStarts = new int[30];
// the previous token read by the scanner
protected int previousToken;
// the index in the identifier stack of the previous identifier
protected int previousIdentifierPtr;
// the stacks of selectors for invocations (ie. method invocations, allocation expressions and
// explicit constructor invocations)
// the selector stack contains pointers to the identifier stack or one of the selector constants below
protected int invocationPtr;
protected int[] selectorStack = new int[StackIncrement];
// selector constants
protected static final int THIS_CONSTRUCTOR = -1;
protected static final int SUPER_CONSTRUCTOR = -2;
// whether the parser is in a field initializer
// (false is pushed each time a new type is entered,
// it is changed to true when the initializer is entered,
// it is changed back to false when the initializer is exited,
// and it is poped when the type is exited)
protected int inInitializerPtr;
protected boolean[] inInitializerStack = new boolean[StackIncrement];
// whether the parser is in a method, constructor or initializer
// (false is pushed each time a new type is entered,
// it is changed to true when the method is entered,
// it is changed back to false when the method is exited,
// and it is poped when the type is exited)
protected int inMethodPtr;
protected boolean[] inMethodStack = new boolean[StackIncrement];
public AssistParser(ProblemReporter problemReporter, boolean assertMode) {
super(problemReporter, false, assertMode);
}
public abstract char[] assistIdentifier();
public int bodyEnd(AbstractMethodDeclaration method){
return method.declarationSourceEnd;
}
public int bodyEnd(Initializer initializer){
return initializer.declarationSourceEnd;
}
/*
* Build initial recovery state.
* Recovery state is inferred from the current state of the parser (reduced node stack).
*/
public RecoveredElement buildInitialRecoveryState(){
if (!ENABLE_RECOVERY) return null; // do not resume to recovery
/* recovery in unit structure */
if (referenceContext instanceof CompilationUnitDeclaration){
RecoveredElement element = super.buildInitialRecoveryState();
flushAssistState();
return element;
}
/* recovery in method body */
lastCheckPoint = 0;
RecoveredElement element = null;
if (referenceContext instanceof AbstractMethodDeclaration){
element = new RecoveredMethod((AbstractMethodDeclaration) referenceContext, null, 0, this);
lastCheckPoint = ((AbstractMethodDeclaration) referenceContext).bodyStart;
} else {
/* Initializer bodies are parsed in the context of the type declaration, we must thus search it inside */
if (referenceContext instanceof TypeDeclaration){
TypeDeclaration type = (TypeDeclaration) referenceContext;
for (int i = 0; i < type.fields.length; i++){
FieldDeclaration field = type.fields[i];
if (!field.isField()
&& field.declarationSourceStart <= scanner.initialPosition
&& scanner.initialPosition <= field.declarationSourceEnd
&& scanner.eofPosition <= field.declarationSourceEnd+1){
element = new RecoveredInitializer((Initializer) field, null, 1, this);
lastCheckPoint = field.declarationSourceStart;
break;
}
}
}
}
if (element == null) return element;
/* add initial block */
Block block = new Block(0);
int lastStart = blockStarts[0];
block.sourceStart = lastStart;
element = element.add(block, 1);
int blockIndex = 1; // ignore first block start, since manually rebuilt here
for(int i = 0; i <= astPtr; i++){
AstNode node = astStack[i];
/* check for intermediate block creation, so recovery can properly close them afterwards */
int nodeStart = node.sourceStart;
for (int j = blockIndex; j <= realBlockPtr; j++){
if (blockStarts[j] > nodeStart){
blockIndex = j; // shift the index to the new block
break;
}
if (blockStarts[j] != lastStart){ // avoid multiple block if at same position
block = new Block(0);
block.sourceStart = lastStart = blockStarts[j];
element = element.add(block, 1);
}
blockIndex = j+1; // shift the index to the new block
}
if (node instanceof LocalDeclaration){
LocalDeclaration local = (LocalDeclaration) node;
if (local.declarationSourceEnd == 0){
element = element.add(local, 0);
if (local.initialization == null){
lastCheckPoint = local.sourceEnd + 1;
} else {
lastCheckPoint = local.initialization.sourceEnd + 1;
}
} else {
element = element.add(local, 0);
lastCheckPoint = local.declarationSourceEnd + 1;
}
continue;
}
if (node instanceof AbstractMethodDeclaration){
AbstractMethodDeclaration method = (AbstractMethodDeclaration) node;
if (method.declarationSourceEnd == 0){
element = element.add(method, 0);
lastCheckPoint = method.bodyStart;
} else {
element = element.add(method, 0);
lastCheckPoint = method.declarationSourceEnd + 1;
}
continue;
}
if (node instanceof Initializer){
Initializer initializer = (Initializer) node;
if (initializer.declarationSourceEnd == 0){
element = element.add(initializer, 1);
lastCheckPoint = initializer.bodyStart;
} else {
element = element.add(initializer, 0);
lastCheckPoint = initializer.declarationSourceEnd + 1;
}
continue;
}
if (node instanceof FieldDeclaration){
FieldDeclaration field = (FieldDeclaration) node;
if (field.declarationSourceEnd == 0){
element = element.add(field, 0);
if (field.initialization == null){
lastCheckPoint = field.sourceEnd + 1;
} else {
lastCheckPoint = field.initialization.sourceEnd + 1;
}
} else {
element = element.add(field, 0);
lastCheckPoint = field.declarationSourceEnd + 1;
}
continue;
}
if (node instanceof TypeDeclaration){
TypeDeclaration type = (TypeDeclaration) node;
if (type.declarationSourceEnd == 0){
element = element.add(type, 0);
lastCheckPoint = type.bodyStart;
} else {
element = element.add(type, 0);
lastCheckPoint = type.declarationSourceEnd + 1;
}
continue;
}
if (node instanceof ImportReference){
ImportReference importRef = (ImportReference) node;
element = element.add(importRef, 0);
lastCheckPoint = importRef.declarationSourceEnd + 1;
}
}
if (this.currentToken == TokenNameRBRACE) {
this.currentToken = 0; // closing brace has already been taken care of
}
/* might need some extra block (after the last reduced node) */
int pos = this.assistNode == null ? lastCheckPoint : this.assistNode.sourceStart;
for (int j = blockIndex; j <= realBlockPtr; j++){
if ((blockStarts[j] < pos) && (blockStarts[j] != lastStart)){ // avoid multiple block if at same position
block = new Block(0);
block.sourceStart = lastStart = blockStarts[j];
element = element.add(block, 1);
}
}
return element;
}
protected void consumeClassBodyDeclarationsopt() {
super.consumeClassBodyDeclarationsopt();
this.inInitializerPtr--;
this.inMethodPtr--;
}
protected void consumeClassBodyopt() {
super.consumeClassBodyopt();
this.invocationPtr--; // NB: This can be decremented below -1 only if in diet mode and not in field initializer
}
protected void consumeClassHeader() {
super.consumeClassHeader();
this.pushNotInInitializer();
this.pushNotInMethod();
}
protected void consumeConstructorBody() {
super.consumeConstructorBody();
this.inMethodStack[this.inMethodPtr] = false;
}
protected void consumeConstructorHeader() {
super.consumeConstructorHeader();
this.inMethodStack[this.inMethodPtr] = true;
}
protected void consumeEmptyClassBodyDeclarationsopt() {
super.consumeEmptyClassBodyDeclarationsopt();
this.inInitializerPtr--;
this.inMethodPtr--;
}
protected void consumeEnterAnonymousClassBody() {
super.consumeEnterAnonymousClassBody();
this.invocationPtr--; // NB: This can be decremented below -1 only if in diet mode and not in field initializer
this.pushNotInInitializer();
this.pushNotInMethod();
}
protected void consumeExplicitConstructorInvocation(int flag, int recFlag) {
super.consumeExplicitConstructorInvocation(flag, recFlag);
this.invocationPtr--; // NB: This can be decremented below -1 only if in diet mode and not in field initializer
}
protected void consumeForceNoDiet() {
super.consumeForceNoDiet();
// if we are not in a method (ie. we are not in a local variable initializer)
// then we are entering a field initializer
if (!this.inMethodStack[this.inMethodPtr]) {
this.inInitializerStack[this.inInitializerPtr] = true;
}
}
protected void consumeInterfaceHeader() {
super.consumeInterfaceHeader();
this.pushNotInInitializer();
this.pushNotInMethod();
}
protected void consumeInterfaceMemberDeclarationsopt() {
super.consumeInterfaceMemberDeclarationsopt();
this.inInitializerPtr--;
this.inMethodPtr--;
}
protected void consumeMethodBody() {
super.consumeMethodBody();
this.inMethodStack[this.inMethodPtr] = false;
}
protected void consumeMethodHeader() {
super.consumeMethodHeader();
this.inMethodStack[this.inMethodPtr] = true;
}
protected void consumeMethodInvocationName() {
super.consumeMethodInvocationName();
this.invocationPtr--; // NB: This can be decremented below -1 only if in diet mode and not in field initializer
MessageSend messageSend = (MessageSend)expressionStack[expressionPtr];
if (messageSend == assistNode){
this.lastCheckPoint = messageSend.sourceEnd + 1;
}
}
protected void consumeMethodInvocationPrimary() {
super.consumeMethodInvocationPrimary();
this.invocationPtr--; // NB: This can be decremented below -1 only if in diet mode and not in field initializer
MessageSend messageSend = (MessageSend)expressionStack[expressionPtr];
if (messageSend == assistNode){
this.lastCheckPoint = messageSend.sourceEnd + 1;
}
}
protected void consumeMethodInvocationSuper() {
super.consumeMethodInvocationSuper();
this.invocationPtr--; // NB: This can be decremented below -1 only if in diet mode and not in field initializer
MessageSend messageSend = (MessageSend)expressionStack[expressionPtr];
if (messageSend == assistNode){
this.lastCheckPoint = messageSend.sourceEnd + 1;
}
}
protected void consumeNestedMethod() {
super.consumeNestedMethod();
this.inMethodStack[this.inMethodPtr] = true;
}
protected void consumeOpenBlock() {
// OpenBlock ::= $empty
super.consumeOpenBlock();
try {
blockStarts[realBlockPtr] = scanner.startPosition;
} catch (IndexOutOfBoundsException e) {
//realBlockPtr is correct
int oldStackLength = blockStarts.length;
int oldStack[] = blockStarts;
blockStarts = new int[oldStackLength + StackIncrement];
System.arraycopy(oldStack, 0, blockStarts, 0, oldStackLength);
blockStarts[realBlockPtr] = scanner.startPosition;
}
}
protected void consumePackageDeclarationName() {
// PackageDeclarationName ::= 'package' Name
/* build an ImportRef build from the last name
stored in the identifier stack. */
int index;
/* no need to take action if not inside assist identifiers */
if ((index = indexOfAssistIdentifier()) < 0) {
super.consumePackageDeclarationName();
return;
}
/* retrieve identifiers subset and whole positions, the assist node positions
should include the entire replaced source. */
int length = identifierLengthStack[identifierLengthPtr];
char[][] subset = identifierSubSet(index+1); // include the assistIdentifier
identifierLengthPtr--;
identifierPtr -= length;
long[] positions = new long[length];
System.arraycopy(
identifierPositionStack,
identifierPtr + 1,
positions,
0,
length);
/* build specific assist node on package statement */
ImportReference reference = this.createAssistPackageReference(subset, positions);
assistNode = reference;
this.lastCheckPoint = reference.sourceEnd + 1;
compilationUnit.currentPackage = reference;
if (currentToken == TokenNameSEMICOLON){
reference.declarationSourceEnd = scanner.currentPosition - 1;
} else {
reference.declarationSourceEnd = (int) positions[length-1];
}
//endPosition is just before the ;
reference.declarationSourceStart = intStack[intPtr--];
// flush annotations defined prior to import statements
reference.declarationSourceEnd = this.flushAnnotationsDefinedPriorTo(reference.declarationSourceEnd);
// recovery
if (currentElement != null){
lastCheckPoint = reference.declarationSourceEnd+1;
restartRecovery = true; // used to avoid branching back into the regular automaton
}
}
protected void consumeRestoreDiet() {
super.consumeRestoreDiet();
// if we are not in a method (ie. we were not in a local variable initializer)
// then we are exiting a field initializer
if (!this.inMethodStack[this.inMethodPtr]) {
this.inInitializerStack[this.inInitializerPtr] = false;
}
}
protected void consumeSingleTypeImportDeclarationName() {
// SingleTypeImportDeclarationName ::= 'import' Name
/* push an ImportRef build from the last name
stored in the identifier stack. */
int index;
/* no need to take action if not inside assist identifiers */
if ((index = indexOfAssistIdentifier()) < 0) {
super.consumeSingleTypeImportDeclarationName();
return;
}
/* retrieve identifiers subset and whole positions, the assist node positions
should include the entire replaced source. */
int length = identifierLengthStack[identifierLengthPtr];
char[][] subset = identifierSubSet(index+1); // include the assistIdentifier
identifierLengthPtr--;
identifierPtr -= length;
long[] positions = new long[length];
System.arraycopy(
identifierPositionStack,
identifierPtr + 1,
positions,
0,
length);
/* build specific assist node on import statement */
ImportReference reference = this.createAssistImportReference(subset, positions);
assistNode = reference;
this.lastCheckPoint = reference.sourceEnd + 1;
pushOnAstStack(reference);
if (currentToken == TokenNameSEMICOLON){
reference.declarationSourceEnd = scanner.currentPosition - 1;
} else {
reference.declarationSourceEnd = (int) positions[length-1];
}
//endPosition is just before the ;
reference.declarationSourceStart = intStack[intPtr--];
// flush annotations defined prior to import statements
reference.declarationSourceEnd = this.flushAnnotationsDefinedPriorTo(reference.declarationSourceEnd);
// recovery
if (currentElement != null){
lastCheckPoint = reference.declarationSourceEnd+1;
currentElement = currentElement.add(reference, 0);
lastIgnoredToken = -1;
restartRecovery = true; // used to avoid branching back into the regular automaton
}
}
protected void consumeStaticInitializer() {
super.consumeStaticInitializer();
this.inMethodStack[this.inMethodPtr] = false;
}
protected void consumeStaticOnly() {
super.consumeStaticOnly();
this.inMethodStack[this.inMethodPtr] = true;
}
protected void consumeToken(int token) {
super.consumeToken(token);
// register message send selector only if inside a method or if looking at a field initializer
// and if the current token is an open parenthesis
if ((this.inMethodStack[this.inMethodPtr] || this.inInitializerStack[this.inInitializerPtr]) && token == TokenNameLPAREN) {
switch (this.previousToken) {
case TokenNameIdentifier:
this.pushOnSelectorStack(this.identifierPtr);
break;
case TokenNamethis: // explicit constructor invocation, eg. this(1, 2)
this.pushOnSelectorStack(THIS_CONSTRUCTOR);
break;
case TokenNamesuper: // explicit constructor invocation, eg. super(1, 2)
this.pushOnSelectorStack(SUPER_CONSTRUCTOR);
break;
}
}
this.previousToken = token;
if (token == TokenNameIdentifier) {
this.previousIdentifierPtr = this.identifierPtr;
}
}
protected void consumeTypeImportOnDemandDeclarationName() {
// TypeImportOnDemandDeclarationName ::= 'import' Name '.' '*'
/* push an ImportRef build from the last name
stored in the identifier stack. */
int index;
/* no need to take action if not inside assist identifiers */
if ((index = indexOfAssistIdentifier()) < 0) {
super.consumeTypeImportOnDemandDeclarationName();
return;
}
/* retrieve identifiers subset and whole positions, the assist node positions
should include the entire replaced source. */
int length = identifierLengthStack[identifierLengthPtr];
char[][] subset = identifierSubSet(index+1); // include the assistIdentifier
identifierLengthPtr--;
identifierPtr -= length;
long[] positions = new long[length];
System.arraycopy(
identifierPositionStack,
identifierPtr + 1,
positions,
0,
length);
/* build specific assist node on import statement */
ImportReference reference = this.createAssistImportReference(subset, positions);
reference.onDemand = true;
assistNode = reference;
this.lastCheckPoint = reference.sourceEnd + 1;
pushOnAstStack(reference);
if (currentToken == TokenNameSEMICOLON){
reference.declarationSourceEnd = scanner.currentPosition - 1;
} else {
reference.declarationSourceEnd = (int) positions[length-1];
}
//endPosition is just before the ;
reference.declarationSourceStart = intStack[intPtr--];
// flush annotations defined prior to import statements
reference.declarationSourceEnd = this.flushAnnotationsDefinedPriorTo(reference.declarationSourceEnd);
// recovery
if (currentElement != null){
lastCheckPoint = reference.declarationSourceEnd+1;
currentElement = currentElement.add(reference, 0);
lastIgnoredToken = -1;
restartRecovery = true; // used to avoid branching back into the regular automaton
}
}
public abstract ImportReference createAssistImportReference(char[][] tokens, long[] positions);
public abstract ImportReference createAssistPackageReference(char[][] tokens, long[] positions);
public abstract NameReference createQualifiedAssistNameReference(char[][] previousIdentifiers, char[] name, long[] positions);
public abstract TypeReference createQualifiedAssistTypeReference(char[][] previousIdentifiers, char[] name, long[] positions);
public abstract NameReference createSingleAssistNameReference(char[] name, long position);
public abstract TypeReference createSingleAssistTypeReference(char[] name, long position);
/*
* Flush parser/scanner state regarding to code assist
*/
public void flushAssistState(){
this.assistNode = null;
this.isOrphanCompletionNode = false;
}
/*
* Build specific type reference nodes in case the cursor is located inside the type reference
*/
protected TypeReference getTypeReference(int dim) {
int index;
/* no need to take action if not inside completed identifiers */
if ((index = indexOfAssistIdentifier()) < 0) {
return super.getTypeReference(dim);
}
/* retrieve identifiers subset and whole positions, the assist node positions
should include the entire replaced source. */
int length = identifierLengthStack[identifierLengthPtr];
char[][] subset = identifierSubSet(index);
identifierLengthPtr--;
identifierPtr -= length;
long[] positions = new long[length];
System.arraycopy(
identifierPositionStack,
identifierPtr + 1,
positions,
0,
length);
/* build specific assist on type reference */
TypeReference reference;
if (index == 0) {
/* assist inside first identifier */
reference = this.createSingleAssistTypeReference(
assistIdentifier(),
positions[0]);
} else {
/* assist inside subsequent identifier */
reference = this.createQualifiedAssistTypeReference(
subset,
assistIdentifier(),
positions);
}
assistNode = reference;
this.lastCheckPoint = reference.sourceEnd + 1;
return reference;
}
/*
* Copy of code from superclass with the following change:
* In the case of qualified name reference if the cursor location is on the
* qualified name reference, then create a CompletionOnQualifiedNameReference
* instead.
*/
protected NameReference getUnspecifiedReferenceOptimized() {
int completionIndex;
/* no need to take action if not inside completed identifiers */
if ((completionIndex = indexOfAssistIdentifier()) < 0) {
return super.getUnspecifiedReferenceOptimized();
}
/* retrieve identifiers subset and whole positions, the completion node positions
should include the entire replaced source. */
int length = identifierLengthStack[identifierLengthPtr];
char[][] subset = identifierSubSet(completionIndex);
identifierLengthPtr--;
identifierPtr -= length;
long[] positions = new long[length];
System.arraycopy(
identifierPositionStack,
identifierPtr + 1,
positions,
0,
length);
/* build specific completion on name reference */
NameReference reference;
if (completionIndex == 0) {
/* completion inside first identifier */
reference = this.createSingleAssistNameReference(assistIdentifier(), positions[0]);
} else {
/* completion inside subsequent identifier */
reference = this.createQualifiedAssistNameReference(subset, assistIdentifier(), positions);
};
reference.bits &= ~AstNode.RestrictiveFlagMASK;
reference.bits |= LOCAL | FIELD;
assistNode = reference;
lastCheckPoint = reference.sourceEnd + 1;
return reference;
}
public void goForBlockStatementsopt() {
//tells the scanner to go for block statements opt parsing
firstToken = TokenNameTWIDDLE;
scanner.recordLineSeparator = false;
}
public void goForConstructorBlockStatementsopt() {
//tells the scanner to go for constructor block statements opt parsing
firstToken = TokenNameNOT;
scanner.recordLineSeparator = false;
}
/*
* Retrieve a partial subset of a qualified name reference up to the completion point.
* It does not pop the actual awaiting identifiers, so as to be able to retrieve position
* information afterwards.
*/
protected char[][] identifierSubSet(int subsetLength){
if (subsetLength == 0) return null;
char[][] subset;
System.arraycopy(
identifierStack,
identifierPtr - identifierLengthStack[identifierLengthPtr] + 1,
(subset = new char[subsetLength][]),
0,
subsetLength);
return subset;
}
/*
* Iterate the most recent group of awaiting identifiers (grouped for qualified name reference (eg. aa.bb.cc)
* so as to check whether one of them is the assist identifier.
* If so, then answer the index of the assist identifier (0 being the first identifier of the set).
* eg. aa(0).bb(1).cc(2)
* If no assist identifier was found, answers -1.
*/
protected int indexOfAssistIdentifier(){
if (identifierLengthPtr < 0){
return -1; // no awaiting identifier
}
char[] assistIdentifier ;
if ((assistIdentifier = this.assistIdentifier()) == null){
return -1; // no assist identifier found yet
}
// iterate awaiting identifiers backwards
int length = identifierLengthStack[identifierLengthPtr];
for (int i = 0; i < length; i++){
if (identifierStack[identifierPtr - i] == assistIdentifier){
return length - i - 1;
}
}
// none of the awaiting identifiers is the completion one
return -1;
}
public void initialize() {
super.initialize();
this.flushAssistState();
this.invocationPtr = -1;
this.inMethodStack[this.inMethodPtr = 0] = false;
this.inInitializerStack[this.inInitializerPtr = 0] = false;
this.previousIdentifierPtr = -1;
}
public abstract void initializeScanner();
/**
* Parse the block statements inside the given method declaration and try to complete at the
* cursor location.
*/
public void parseBlockStatements(AbstractMethodDeclaration md, CompilationUnitDeclaration unit) {
if (md instanceof MethodDeclaration) {
parseBlockStatements((MethodDeclaration) md, unit);
} else if (md instanceof ConstructorDeclaration) {
parseBlockStatements((ConstructorDeclaration) md, unit);
}
}
/**
* Parse the block statements inside the given constructor declaration and try to complete at the
* cursor location.
*/
public void parseBlockStatements(ConstructorDeclaration cd, CompilationUnitDeclaration unit) {
//only parse the method body of cd
//fill out its statements
//convert bugs into parse error
initialize();
// simulate goForConstructorBody except that we don't want to balance brackets because they are not going to be balanced
goForConstructorBlockStatementsopt();
referenceContext = cd;
compilationUnit = unit;
scanner.resetTo(cd.bodyStart, bodyEnd(cd));
consumeNestedMethod();
try {
parse();
} catch (AbortCompilation ex) {
lastAct = ERROR_ACTION;
}
}
/**
* Parse the block statements inside the given initializer and try to complete at the
* cursor location.
*/
public void parseBlockStatements(
Initializer ini,
TypeDeclaration type,
CompilationUnitDeclaration unit) {
initialize();
// simulate goForInitializer except that we don't want to balance brackets because they are not going to be balanced
goForBlockStatementsopt();
referenceContext = type;
compilationUnit = unit;
scanner.resetTo(ini.sourceStart, bodyEnd(ini)); // just after the beginning {
consumeNestedMethod();
try {
parse();
} catch (AbortCompilation ex) {
lastAct = ERROR_ACTION;
} finally {
nestedMethod[nestedType]--;
}
}
/**
* Parse the block statements inside the given method declaration and try to complete at the
* cursor location.
*/
public void parseBlockStatements(MethodDeclaration md, CompilationUnitDeclaration unit) {
//only parse the method body of md
//fill out method statements
//convert bugs into parse error
if (md.isAbstract())
return;
if (md.isNative())
return;
if ((md.modifiers & AccSemicolonBody) != 0)
return;
initialize();
// simulate goForMethodBody except that we don't want to balance brackets because they are not going to be balanced
goForBlockStatementsopt();
referenceContext = md;
compilationUnit = unit;
scanner.resetTo(md.bodyStart, bodyEnd(md)); // reset the scanner to parser from { down to the cursor location
consumeNestedMethod();
try {
parse();
} catch (AbortCompilation ex) {
lastAct = ERROR_ACTION;
} finally {
nestedMethod[nestedType]--;
}
}
/*
* Prepares the state of the parser to go for BlockStatements.
*/
protected void prepareForBlockStatements() {
this.nestedMethod[this.nestedType = 0] = 1;
this.variablesCounter[this.nestedType] = 0;
this.realBlockStack[this.realBlockPtr = 1] = 0;
this.invocationPtr = -1;
}
/*
* Pushes 'false' on the inInitializerStack.
*/
protected void pushNotInInitializer() {
try {
this.inInitializerStack[++this.inInitializerPtr] = false;
} catch (IndexOutOfBoundsException e) {
//except in test's cases, it should never raise
int oldStackLength = this.inInitializerStack.length;
System.arraycopy(this.inInitializerStack , 0, (this.inInitializerStack = new boolean[oldStackLength + StackIncrement]), 0, oldStackLength);
this.inInitializerStack[this.inInitializerPtr] = false;
}
}
/*
* Pushes 'false' on the inMethodStack.
*/
protected void pushNotInMethod() {
try {
this.inMethodStack[++this.inMethodPtr] = false;
} catch (IndexOutOfBoundsException e) {
//except in test's cases, it should never raise
int oldStackLength = this.inMethodStack.length;
System.arraycopy(this.inMethodStack , 0, (this.inMethodStack = new boolean[oldStackLength + StackIncrement]), 0, oldStackLength);
this.inMethodStack[this.inMethodPtr] = false;
}
}
/**
* Pushes the given the given selector (an identifier pointer to the identifier stack) on the selector stack.
*/
protected void pushOnSelectorStack(int selectorIdPtr) {
if (this.invocationPtr < -1) return;
try {
this.selectorStack[++this.invocationPtr] = selectorIdPtr;
} catch (IndexOutOfBoundsException e) {
int oldStackLength = this.selectorStack.length;
int oldSelectorStack[] = this.selectorStack;
this.selectorStack = new int[oldStackLength + StackIncrement];
System.arraycopy(oldSelectorStack, 0, this.selectorStack, 0, oldStackLength);
this.selectorStack[this.invocationPtr] = selectorIdPtr;
}
}
public void reset(){
this.flushAssistState();
}
/*
* Reset context so as to resume to regular parse loop
*/
protected void resetStacks() {
super.resetStacks();
this.inInitializerStack[this.inInitializerPtr = 0] = false;
this.inMethodStack[this.inMethodPtr = 0] = false;
}
/*
* Reset context so as to resume to regular parse loop
* If unable to reset for resuming, answers false.
*
* Move checkpoint location, reset internal stacks and
* decide which grammar goal is activated.
*/
protected boolean resumeAfterRecovery() {
// reset internal stacks
astPtr = -1;
astLengthPtr = -1;
expressionPtr = -1;
expressionLengthPtr = -1;
identifierPtr = -1;
identifierLengthPtr = -1;
intPtr = -1;
dimensions = 0 ;
recoveredStaticInitializerStart = 0;
// if in diet mode, reset the diet counter because we're going to restart outside an initializer.
if (diet) dietInt = 0;
/* attempt to move checkpoint location */
if (!this.moveRecoveryCheckpoint()) return false;
// only look for headers
if (referenceContext instanceof CompilationUnitDeclaration
|| this.assistNode != null){
nestedMethod[nestedType = 0] = 0;
variablesCounter[nestedType] = 0;
realBlockStack[realBlockPtr = 0] = 0;
goForHeaders();
diet = true; // passed this point, will not consider method bodies
return true;
}
if (referenceContext instanceof AbstractMethodDeclaration
|| referenceContext instanceof TypeDeclaration){
if (currentElement instanceof RecoveredType){
nestedMethod[nestedType = 0] = 0;
variablesCounter[nestedType] = 0;
realBlockStack[realBlockPtr = 0] = 0;
goForHeaders();
} else {
this.prepareForBlockStatements();
goForBlockStatementsOrMethodHeaders();
}
return true;
}
// does not know how to restart
return false;
}
public abstract void setAssistIdentifier(char[] assistIdent);
/**
* If the given ast node is inside an explicit constructor call
* then wrap it with a fake constructor call.
* Returns the wrapped completion node or the completion node itself.
*/
protected AstNode wrapWithExplicitConstructorCallIfNeeded(AstNode ast) {
int selector;
if (ast != null && this.invocationPtr >= 0 && ast instanceof Expression &&
(((selector = this.selectorStack[this.invocationPtr]) == THIS_CONSTRUCTOR) ||
(selector == SUPER_CONSTRUCTOR))) {
ExplicitConstructorCall call = new ExplicitConstructorCall(
(selector == THIS_CONSTRUCTOR) ?
ExplicitConstructorCall.This :
ExplicitConstructorCall.Super
);
call.arguments = new Expression[] {(Expression)ast};
call.sourceStart = ast.sourceStart;
call.sourceEnd = ast.sourceEnd;
return call;
} else {
return ast;
}
}
}