/******************************************************************************* * Copyright (c) 2000, 2003 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 net.sourceforge.phpdt.internal.compiler.parser; import net.sourceforge.phpeclipse.internal.compiler.ast.ASTNode; import net.sourceforge.phpeclipse.internal.compiler.ast.Block; import net.sourceforge.phpeclipse.internal.compiler.ast.Statement; /** * Internal structure for parsing recovery */ public class RecoveredElement { public RecoveredElement parent; public int bracketBalance; public boolean foundOpeningBrace; protected 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 RecoveredInitializer enclosingInitializer(){ // RecoveredElement current = this; // while (current != null){ // if (current instanceof RecoveredInitializer){ // return (RecoveredInitializer) current; // } // current = current.parent; // } // return null; //} /* * 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.getLineNumber(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){ } }