1 /*******************************************************************************
 
   2  * Copyright (c) 2000, 2003 IBM Corporation and others.
 
   3  * All rights reserved. This program and the accompanying materials 
 
   4  * are made available under the terms of the Common Public License v1.0
 
   5  * which accompanies this distribution, and is available at
 
   6  * http://www.eclipse.org/legal/cpl-v10.html
 
   9  *     IBM Corporation - initial API and implementation
 
  10  *******************************************************************************/
 
  11 package net.sourceforge.phpdt.internal.compiler.parser;
 
  13 import net.sourceforge.phpeclipse.internal.compiler.ast.ASTNode;
 
  14 import net.sourceforge.phpeclipse.internal.compiler.ast.Block;
 
  15 import net.sourceforge.phpeclipse.internal.compiler.ast.Statement;
 
  18  * Internal structure for parsing recovery 
 
  20 public class RecoveredElement {
 
  22         public RecoveredElement parent;
 
  23         public int bracketBalance;
 
  24         public boolean foundOpeningBrace;
 
  25         protected Parser recoveringParser;
 
  26 public RecoveredElement(RecoveredElement parent, int bracketBalance){
 
  27         this(parent, bracketBalance, null);
 
  29 public RecoveredElement(RecoveredElement parent, int bracketBalance, Parser parser){
 
  31         this.bracketBalance = bracketBalance;
 
  32         this.recoveringParser = parser;
 
  35  *      Record a method declaration
 
  37 //public RecoveredElement add(AbstractMethodDeclaration methodDeclaration, int bracketBalance) {
 
  39 //      /* default behavior is to delegate recording to parent if any */
 
  40 //      if (parent == null) {
 
  41 //              return this; // ignore
 
  43 //              this.updateSourceEndIfNecessary(this.previousAvailableLineEnd(methodDeclaration.declarationSourceStart - 1));   
 
  44 //              return this.parent.add(methodDeclaration, bracketBalance);
 
  48  * Record a nested block declaration
 
  50 public RecoveredElement add(Block nestedBlockDeclaration, int bracketBalance) {
 
  52         /* default behavior is to delegate recording to parent if any */
 
  54                 return this; // ignore
 
  56                 this.updateSourceEndIfNecessary(this.previousAvailableLineEnd(nestedBlockDeclaration.sourceStart - 1)); 
 
  57                 return this.parent.add(nestedBlockDeclaration, bracketBalance);
 
  61  * Record a field declaration
 
  63 //public RecoveredElement add(FieldDeclaration fieldDeclaration, int bracketBalance) {
 
  65 //      /* default behavior is to delegate recording to parent if any */
 
  66 //      if (parent == null) {
 
  67 //              return this; // ignore
 
  69 //              this.updateSourceEndIfNecessary(this.previousAvailableLineEnd(fieldDeclaration.declarationSourceStart - 1));    
 
  70 //              return this.parent.add(fieldDeclaration, bracketBalance);
 
  74 // *    Record an import reference
 
  76 //public RecoveredElement add(ImportReference importReference, int bracketBalance){
 
  78 //      /* default behavior is to delegate recording to parent if any */
 
  79 //      if (parent == null) {
 
  80 //              return this; // ignore
 
  82 //              this.updateSourceEndIfNecessary(this.previousAvailableLineEnd(importReference.declarationSourceStart - 1));     
 
  83 //              return this.parent.add(importReference, bracketBalance);
 
  87 // * Record a local declaration
 
  89 //public RecoveredElement add(LocalDeclaration localDeclaration, int bracketBalance) {
 
  91 //      /* default behavior is to delegate recording to parent if any */
 
  92 //      if (parent == null) {
 
  93 //              return this; // ignore
 
  95 //              this.updateSourceEndIfNecessary(this.previousAvailableLineEnd(localDeclaration.declarationSourceStart - 1));    
 
  96 //              return this.parent.add(localDeclaration, bracketBalance);
 
 102 public RecoveredElement add(Statement statement, int bracketBalance) {
 
 104         /* default behavior is to delegate recording to parent if any */
 
 105         if (parent == null) {
 
 106                 return this; // ignore
 
 108                 this.updateSourceEndIfNecessary(this.previousAvailableLineEnd(statement.sourceStart - 1));      
 
 109                 return this.parent.add(statement, bracketBalance);
 
 113  *      Record a type declaration
 
 115 //public RecoveredElement add(TypeDeclaration typeDeclaration, int bracketBalance){
 
 117 //      /* default behavior is to delegate recording to parent if any */
 
 118 //      if (parent == null) {
 
 119 //              return this; // ignore
 
 121 //              this.updateSourceEndIfNecessary(this.previousAvailableLineEnd(typeDeclaration.declarationSourceStart - 1));     
 
 122 //              return this.parent.add(typeDeclaration, bracketBalance);
 
 126  * Answer the depth of this element, considering the parent link.
 
 130         RecoveredElement current = this;
 
 131         while ((current = current.parent) != null) depth++;
 
 135  * Answer the enclosing method node, or null if none
 
 137 //public RecoveredInitializer enclosingInitializer(){
 
 138 //      RecoveredElement current = this;
 
 139 //      while (current != null){
 
 140 //              if (current instanceof RecoveredInitializer){
 
 141 //                      return (RecoveredInitializer) current;
 
 143 //              current = current.parent;
 
 148  * Answer the enclosing method node, or null if none
 
 150 //public RecoveredMethod enclosingMethod(){
 
 151 //      RecoveredElement current = this;
 
 152 //      while (current != null){
 
 153 //              if (current instanceof RecoveredMethod){
 
 154 //                      return (RecoveredMethod) current;
 
 156 //              current = current.parent;
 
 161  * Answer the enclosing type node, or null if none
 
 163 //public RecoveredType enclosingType(){
 
 164 //      RecoveredElement current = this;
 
 165 //      while (current != null){
 
 166 //              if (current instanceof RecoveredType){
 
 167 //                      return (RecoveredType) current;
 
 169 //              current = current.parent;
 
 174  * Answer the closest specified parser
 
 176 public Parser parser(){
 
 177         RecoveredElement current = this;
 
 178         while (current != null){
 
 179                 if (current.recoveringParser != null){
 
 180                         return current.recoveringParser;
 
 182                 current = current.parent;
 
 187  * Answer the associated parsed structure
 
 189 public ASTNode parseTree(){
 
 193  * Iterate the enclosing blocks and tag them so as to preserve their content
 
 195 //public void preserveEnclosingBlocks(){
 
 196 //      RecoveredElement current = this;
 
 197 //      while (current != null){
 
 198 //              if (current instanceof RecoveredBlock){
 
 199 //                      ((RecoveredBlock)current).preserveContent = true;
 
 201 //              if (current instanceof RecoveredType){ // for anonymous types
 
 202 //                      ((RecoveredType)current).preserveContent = true;
 
 204 //              current = current.parent;
 
 208  * Answer the position of the previous line end if
 
 209  * there is nothing but spaces in between it and the
 
 210  * line end. Used to trim spaces on unclosed elements.
 
 212 public int previousAvailableLineEnd(int position){
 
 214         Parser parser = this.parser();
 
 215         if (parser == null) return position;
 
 217         Scanner scanner = parser.scanner;
 
 218         if (scanner.lineEnds == null) return position;
 
 220         int index = scanner.getLineNumber(position);
 
 221         if (index < 2) return position;
 
 222         int previousLineEnd = scanner.lineEnds[index-2];
 
 224         char[] source = scanner.source;
 
 225         for (int i = previousLineEnd+1; i < position; i++){
 
 226                 if (!(source[i] == ' ' || source[i] == '\t')) return position;
 
 228         return previousLineEnd;
 
 231  * Answer the very source end of the corresponding parse node
 
 233 public int sourceEnd(){
 
 236 protected String tabString(int tab) {
 
 237         StringBuffer result = new StringBuffer();
 
 238         for (int i = tab; i > 0; i--) {
 
 239                 result.append("  "); //$NON-NLS-1$
 
 241         return result.toString();
 
 244  * Answer the top node
 
 246 public RecoveredElement topElement(){
 
 247         RecoveredElement current = this;
 
 248         while (current.parent != null){
 
 249                 current = current.parent;
 
 253 public String toString() {
 
 256 public String toString(int tab) {
 
 257         return super.toString();
 
 260  * Answer the enclosing type node, or null if none
 
 262 //public RecoveredType type(){
 
 263 //      RecoveredElement current = this;
 
 264 //      while (current != null){
 
 265 //              if (current instanceof RecoveredType){
 
 266 //                      return (RecoveredType) current;
 
 268 //              current = current.parent;
 
 273  * Update the bodyStart of the corresponding parse node
 
 275 public void updateBodyStart(int bodyStart){
 
 276         this.foundOpeningBrace = true;  
 
 279  * Update the corresponding parse node from parser state which
 
 280  * is about to disappear because of restarting recovery
 
 282 public void updateFromParserState(){
 
 285  * A closing brace got consumed, might have closed the current element,
 
 286  * in which case both the currentElement is exited
 
 288 public RecoveredElement updateOnClosingBrace(int braceStart, int braceEnd){
 
 289         if ((--bracketBalance <= 0) && (parent != null)){
 
 290                 this.updateSourceEndIfNecessary(braceEnd);
 
 296  * An opening brace got consumed, might be the expected opening one of the current element,
 
 297  * in which case the bodyStart is updated.
 
 299 public RecoveredElement updateOnOpeningBrace(int braceEnd){
 
 301         if (bracketBalance++ == 0){
 
 302                 this.updateBodyStart(braceEnd + 1);
 
 305         return null; // no update is necessary
 
 308  * Final update the corresponding parse node
 
 310 public void updateParseTree(){
 
 313  * Update the declarationSourceEnd of the corresponding parse node
 
 315 public void updateSourceEndIfNecessary(int sourceEnd){