package org.eclipse.jdt.internal.compiler.parser; | |
/* | |
* (c) Copyright IBM Corp. 2000, 2001. | |
* All Rights Reserved. | |
*/ | |
/** | |
* Internal structure for parsing recovery | |
*/ | |
import org.eclipse.jdt.internal.compiler.ast.*; | |
public class RecoveredElement { | |
public RecoveredElement parent; | |
public int bracketBalance; | |
public boolean foundOpeningBrace; | |
private Parser recoveringParser; | |
public RecoveredElement(RecoveredElement parent, int bracketBalance){ | |
this(parent, bracketBalance, null); | |
} | |
public RecoveredElement(RecoveredElement parent, int bracketBalance, Parser parser){ | |
this.parent = parent; | |
this.bracketBalance = bracketBalance; | |
this.recoveringParser = parser; | |
} | |
/* | |
* Record a method declaration | |
*/ | |
public RecoveredElement add(AbstractMethodDeclaration methodDeclaration, int bracketBalance) { | |
/* default behavior is to delegate recording to parent if any */ | |
if (parent == null) { | |
return this; // ignore | |
} else { | |
this.updateSourceEndIfNecessary(this.previousAvailableLineEnd(methodDeclaration.declarationSourceStart - 1)); | |
return this.parent.add(methodDeclaration, bracketBalance); | |
} | |
} | |
/* | |
* Record a nested block declaration | |
*/ | |
public RecoveredElement add(Block nestedBlockDeclaration, int bracketBalance) { | |
/* default behavior is to delegate recording to parent if any */ | |
if (parent == null) { | |
return this; // ignore | |
} else { | |
this.updateSourceEndIfNecessary(this.previousAvailableLineEnd(nestedBlockDeclaration.sourceStart - 1)); | |
return this.parent.add(nestedBlockDeclaration, bracketBalance); | |
} | |
} | |
/* | |
* Record a field declaration | |
*/ | |
public RecoveredElement add(FieldDeclaration fieldDeclaration, int bracketBalance) { | |
/* default behavior is to delegate recording to parent if any */ | |
if (parent == null) { | |
return this; // ignore | |
} else { | |
this.updateSourceEndIfNecessary(this.previousAvailableLineEnd(fieldDeclaration.declarationSourceStart - 1)); | |
return this.parent.add(fieldDeclaration, bracketBalance); | |
} | |
} | |
/* | |
* Record an import reference | |
*/ | |
public RecoveredElement add(ImportReference importReference, int bracketBalance){ | |
/* default behavior is to delegate recording to parent if any */ | |
if (parent == null) { | |
return this; // ignore | |
} else { | |
this.updateSourceEndIfNecessary(this.previousAvailableLineEnd(importReference.declarationSourceStart - 1)); | |
return this.parent.add(importReference, bracketBalance); | |
} | |
} | |
/* | |
* Record a local declaration | |
*/ | |
public RecoveredElement add(LocalDeclaration localDeclaration, int bracketBalance) { | |
/* default behavior is to delegate recording to parent if any */ | |
if (parent == null) { | |
return this; // ignore | |
} else { | |
this.updateSourceEndIfNecessary(this.previousAvailableLineEnd(localDeclaration.declarationSourceStart - 1)); | |
return this.parent.add(localDeclaration, bracketBalance); | |
} | |
} | |
/* | |
* Record a statement | |
*/ | |
public RecoveredElement add(Statement statement, int bracketBalance) { | |
/* default behavior is to delegate recording to parent if any */ | |
if (parent == null) { | |
return this; // ignore | |
} else { | |
this.updateSourceEndIfNecessary(this.previousAvailableLineEnd(statement.sourceStart - 1)); | |
return this.parent.add(statement, bracketBalance); | |
} | |
} | |
/* | |
* Record a type declaration | |
*/ | |
public RecoveredElement add(TypeDeclaration typeDeclaration, int bracketBalance){ | |
/* default behavior is to delegate recording to parent if any */ | |
if (parent == null) { | |
return this; // ignore | |
} else { | |
this.updateSourceEndIfNecessary(this.previousAvailableLineEnd(typeDeclaration.declarationSourceStart - 1)); | |
return this.parent.add(typeDeclaration, bracketBalance); | |
} | |
} | |
/* | |
* Answer the depth of this element, considering the parent link. | |
*/ | |
public int depth(){ | |
int depth = 0; | |
RecoveredElement current = this; | |
while ((current = current.parent) != null) depth++; | |
return depth; | |
} | |
/* | |
* Answer the enclosing method node, or null if none | |
*/ | |
public RecoveredMethod enclosingMethod(){ | |
RecoveredElement current = this; | |
while (current != null){ | |
if (current instanceof RecoveredMethod){ | |
return (RecoveredMethod) current; | |
} | |
current = current.parent; | |
} | |
return null; | |
} | |
/* | |
* Answer the enclosing type node, or null if none | |
*/ | |
public RecoveredType enclosingType(){ | |
RecoveredElement current = this; | |
while (current != null){ | |
if (current instanceof RecoveredType){ | |
return (RecoveredType) current; | |
} | |
current = current.parent; | |
} | |
return null; | |
} | |
/* | |
* Answer the closest specified parser | |
*/ | |
public Parser parser(){ | |
RecoveredElement current = this; | |
while (current != null){ | |
if (current.recoveringParser != null){ | |
return current.recoveringParser; | |
} | |
current = current.parent; | |
} | |
return null; | |
} | |
/* | |
* Answer the associated parsed structure | |
*/ | |
public AstNode parseTree(){ | |
return null; | |
} | |
/* | |
* Iterate the enclosing blocks and tag them so as to preserve their content | |
*/ | |
public void preserveEnclosingBlocks(){ | |
RecoveredElement current = this; | |
while (current != null){ | |
if (current instanceof RecoveredBlock){ | |
((RecoveredBlock)current).preserveContent = true; | |
} | |
if (current instanceof RecoveredType){ // for anonymous types | |
((RecoveredType)current).preserveContent = true; | |
} | |
current = current.parent; | |
} | |
} | |
/* | |
* Answer the position of the previous line end if | |
* there is nothing but spaces in between it and the | |
* line end. Used to trim spaces on unclosed elements. | |
*/ | |
public int previousAvailableLineEnd(int position){ | |
Parser parser = this.parser(); | |
if (parser == null) return position; | |
Scanner scanner = parser.scanner; | |
if (scanner.lineEnds == null) return position; | |
int index = scanner.searchLineNumber(position); | |
if (index < 2) return position; | |
int previousLineEnd = scanner.lineEnds[index-2]; | |
char[] source = scanner.source; | |
for (int i = previousLineEnd+1; i < position; i++){ | |
if (!(source[i] == ' ' || source[i] == '\t')) return position; | |
} | |
return previousLineEnd; | |
} | |
/* | |
* Answer the very source end of the corresponding parse node | |
*/ | |
public int sourceEnd(){ | |
return 0; | |
} | |
protected String tabString(int tab) { | |
StringBuffer result = new StringBuffer(); | |
for (int i = tab; i > 0; i--) { | |
result.append(" "); //$NON-NLS-1$ | |
} | |
return result.toString(); | |
} | |
/* | |
* Answer the top node | |
*/ | |
public RecoveredElement topElement(){ | |
RecoveredElement current = this; | |
while (current.parent != null){ | |
current = current.parent; | |
} | |
return current; | |
} | |
public String toString() { | |
return toString(0); | |
} | |
public String toString(int tab) { | |
return super.toString(); | |
} | |
/* | |
* Answer the enclosing type node, or null if none | |
*/ | |
public RecoveredType type(){ | |
RecoveredElement current = this; | |
while (current != null){ | |
if (current instanceof RecoveredType){ | |
return (RecoveredType) current; | |
} | |
current = current.parent; | |
} | |
return null; | |
} | |
/* | |
* Update the bodyStart of the corresponding parse node | |
*/ | |
public void updateBodyStart(int bodyStart){ | |
this.foundOpeningBrace = true; | |
} | |
/* | |
* Update the corresponding parse node from parser state which | |
* is about to disappear because of restarting recovery | |
*/ | |
public void updateFromParserState(){ | |
} | |
/* | |
* A closing brace got consumed, might have closed the current element, | |
* in which case both the currentElement is exited | |
*/ | |
public RecoveredElement updateOnClosingBrace(int braceStart, int braceEnd){ | |
if ((--bracketBalance <= 0) && (parent != null)){ | |
this.updateSourceEndIfNecessary(braceEnd); | |
return parent; | |
} | |
return this; | |
} | |
/* | |
* An opening brace got consumed, might be the expected opening one of the current element, | |
* in which case the bodyStart is updated. | |
*/ | |
public RecoveredElement updateOnOpeningBrace(int braceEnd){ | |
if (bracketBalance++ == 0){ | |
this.updateBodyStart(braceEnd + 1); | |
return this; | |
} | |
return null; // no update is necessary | |
} | |
/* | |
* Final update the corresponding parse node | |
*/ | |
public void updateParseTree(){ | |
} | |
/* | |
* Update the declarationSourceEnd of the corresponding parse node | |
*/ | |
public void updateSourceEndIfNecessary(int sourceEnd){ | |
} | |
} |