misc parser bugfixes; still very ugly state
[phpeclipse.git] / net.sourceforge.phpeclipse / src / net / sourceforge / phpdt / internal / compiler / parser / RecoveredElement.java
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
7  * 
8  * Contributors:
9  *     IBM Corporation - initial API and implementation
10  *******************************************************************************/
11 package net.sourceforge.phpdt.internal.compiler.parser;
12
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.FieldDeclaration;
16 import net.sourceforge.phpeclipse.internal.compiler.ast.Statement;
17
18 /**
19  * Internal structure for parsing recovery 
20  */
21
22 public class RecoveredElement {
23
24         public RecoveredElement parent;
25         public int bracketBalance;
26         public boolean foundOpeningBrace;
27         protected Parser recoveringParser;
28 public RecoveredElement(RecoveredElement parent, int bracketBalance){
29         this(parent, bracketBalance, null);
30 }
31 public RecoveredElement(RecoveredElement parent, int bracketBalance, Parser parser){
32         this.parent = parent;
33         this.bracketBalance = bracketBalance;
34         this.recoveringParser = parser;
35 }
36 /*
37  *      Record a method declaration
38  */
39 //public RecoveredElement add(AbstractMethodDeclaration methodDeclaration, int bracketBalance) {
40 //
41 //      /* default behavior is to delegate recording to parent if any */
42 //      if (parent == null) {
43 //              return this; // ignore
44 //      } else {
45 //              this.updateSourceEndIfNecessary(this.previousAvailableLineEnd(methodDeclaration.declarationSourceStart - 1));   
46 //              return this.parent.add(methodDeclaration, bracketBalance);
47 //      }
48 //}
49 /*
50  * Record a nested block declaration
51  */
52 public RecoveredElement add(Block nestedBlockDeclaration, int bracketBalance) {
53
54         /* default behavior is to delegate recording to parent if any */
55         if (parent == null) {
56                 return this; // ignore
57         } else {
58                 this.updateSourceEndIfNecessary(this.previousAvailableLineEnd(nestedBlockDeclaration.sourceStart - 1)); 
59                 return this.parent.add(nestedBlockDeclaration, bracketBalance);
60         }
61 }
62 /*
63  * Record a field declaration
64  */
65 //public RecoveredElement add(FieldDeclaration fieldDeclaration, int bracketBalance) {
66 //
67 //      /* default behavior is to delegate recording to parent if any */
68 //      if (parent == null) {
69 //              return this; // ignore
70 //      } else {
71 //              this.updateSourceEndIfNecessary(this.previousAvailableLineEnd(fieldDeclaration.declarationSourceStart - 1));    
72 //              return this.parent.add(fieldDeclaration, bracketBalance);
73 //      }
74 //}
75 ///*
76 // *    Record an import reference
77 // */
78 //public RecoveredElement add(ImportReference importReference, int bracketBalance){
79 //
80 //      /* default behavior is to delegate recording to parent if any */
81 //      if (parent == null) {
82 //              return this; // ignore
83 //      } else {
84 //              this.updateSourceEndIfNecessary(this.previousAvailableLineEnd(importReference.declarationSourceStart - 1));     
85 //              return this.parent.add(importReference, bracketBalance);
86 //      }
87 //}
88 ///*
89 // * Record a local declaration
90 // */
91 //public RecoveredElement add(LocalDeclaration localDeclaration, int bracketBalance) {
92 //
93 //      /* default behavior is to delegate recording to parent if any */
94 //      if (parent == null) {
95 //              return this; // ignore
96 //      } else {
97 //              this.updateSourceEndIfNecessary(this.previousAvailableLineEnd(localDeclaration.declarationSourceStart - 1));    
98 //              return this.parent.add(localDeclaration, bracketBalance);
99 //      }
100 //}
101 /*
102  * Record a statement
103  */
104 public RecoveredElement add(Statement statement, int bracketBalance) {
105
106         /* default behavior is to delegate recording to parent if any */
107         if (parent == null) {
108                 return this; // ignore
109         } else {
110                 this.updateSourceEndIfNecessary(this.previousAvailableLineEnd(statement.sourceStart - 1));      
111                 return this.parent.add(statement, bracketBalance);
112         }
113 }
114 /*
115  *      Record a type declaration
116  */
117 //public RecoveredElement add(TypeDeclaration typeDeclaration, int bracketBalance){
118 //
119 //      /* default behavior is to delegate recording to parent if any */
120 //      if (parent == null) {
121 //              return this; // ignore
122 //      } else {
123 //              this.updateSourceEndIfNecessary(this.previousAvailableLineEnd(typeDeclaration.declarationSourceStart - 1));     
124 //              return this.parent.add(typeDeclaration, bracketBalance);
125 //      }
126 //}
127 /*
128  * Answer the depth of this element, considering the parent link.
129  */
130 public int depth(){
131         int depth = 0;
132         RecoveredElement current = this;
133         while ((current = current.parent) != null) depth++;
134         return depth;
135 }
136 /*
137  * Answer the enclosing method node, or null if none
138  */
139 //public RecoveredInitializer enclosingInitializer(){
140 //      RecoveredElement current = this;
141 //      while (current != null){
142 //              if (current instanceof RecoveredInitializer){
143 //                      return (RecoveredInitializer) current;
144 //              }
145 //              current = current.parent;
146 //      }
147 //      return null;
148 //}
149 /*
150  * Answer the enclosing method node, or null if none
151  */
152 //public RecoveredMethod enclosingMethod(){
153 //      RecoveredElement current = this;
154 //      while (current != null){
155 //              if (current instanceof RecoveredMethod){
156 //                      return (RecoveredMethod) current;
157 //              }
158 //              current = current.parent;
159 //      }
160 //      return null;
161 //}
162 /*
163  * Answer the enclosing type node, or null if none
164  */
165 //public RecoveredType enclosingType(){
166 //      RecoveredElement current = this;
167 //      while (current != null){
168 //              if (current instanceof RecoveredType){
169 //                      return (RecoveredType) current;
170 //              }
171 //              current = current.parent;
172 //      }
173 //      return null;
174 //}
175 /*
176  * Answer the closest specified parser
177  */
178 public Parser parser(){
179         RecoveredElement current = this;
180         while (current != null){
181                 if (current.recoveringParser != null){
182                         return current.recoveringParser;
183                 }
184                 current = current.parent;
185         }
186         return null;
187 }
188 /* 
189  * Answer the associated parsed structure
190  */
191 public AstNode parseTree(){
192         return null;
193 }
194 /*
195  * Iterate the enclosing blocks and tag them so as to preserve their content
196  */
197 //public void preserveEnclosingBlocks(){
198 //      RecoveredElement current = this;
199 //      while (current != null){
200 //              if (current instanceof RecoveredBlock){
201 //                      ((RecoveredBlock)current).preserveContent = true;
202 //              }
203 //              if (current instanceof RecoveredType){ // for anonymous types
204 //                      ((RecoveredType)current).preserveContent = true;
205 //              }
206 //              current = current.parent;
207 //      }
208 //}
209 /*
210  * Answer the position of the previous line end if
211  * there is nothing but spaces in between it and the
212  * line end. Used to trim spaces on unclosed elements.
213  */
214 public int previousAvailableLineEnd(int position){
215
216         Parser parser = this.parser();
217         if (parser == null) return position;
218         
219         Scanner scanner = parser.scanner;
220         if (scanner.lineEnds == null) return position;
221         
222         int index = scanner.getLineNumber(position);
223         if (index < 2) return position;
224         int previousLineEnd = scanner.lineEnds[index-2];
225
226         char[] source = scanner.source;
227         for (int i = previousLineEnd+1; i < position; i++){
228                 if (!(source[i] == ' ' || source[i] == '\t')) return position;
229         }
230         return previousLineEnd;
231 }
232 /*
233  * Answer the very source end of the corresponding parse node
234  */
235 public int sourceEnd(){
236         return 0;
237 }
238 protected String tabString(int tab) {
239         StringBuffer result = new StringBuffer();
240         for (int i = tab; i > 0; i--) {
241                 result.append("  "); //$NON-NLS-1$
242         }
243         return result.toString();
244 }
245 /*
246  * Answer the top node
247  */
248 public RecoveredElement topElement(){
249         RecoveredElement current = this;
250         while (current.parent != null){
251                 current = current.parent;
252         }
253         return current;
254 }
255 public String toString() {
256         return toString(0);
257 }
258 public String toString(int tab) {
259         return super.toString();
260 }
261 /*
262  * Answer the enclosing type node, or null if none
263  */
264 //public RecoveredType type(){
265 //      RecoveredElement current = this;
266 //      while (current != null){
267 //              if (current instanceof RecoveredType){
268 //                      return (RecoveredType) current;
269 //              }
270 //              current = current.parent;
271 //      }
272 //      return null;
273 //}
274 /*
275  * Update the bodyStart of the corresponding parse node
276  */
277 public void updateBodyStart(int bodyStart){
278         this.foundOpeningBrace = true;  
279 }
280 /*
281  * Update the corresponding parse node from parser state which
282  * is about to disappear because of restarting recovery
283  */
284 public void updateFromParserState(){
285 }
286 /*
287  * A closing brace got consumed, might have closed the current element,
288  * in which case both the currentElement is exited
289  */
290 public RecoveredElement updateOnClosingBrace(int braceStart, int braceEnd){
291         if ((--bracketBalance <= 0) && (parent != null)){
292                 this.updateSourceEndIfNecessary(braceEnd);
293                 return parent;
294         }
295         return this;
296 }
297 /*
298  * An opening brace got consumed, might be the expected opening one of the current element,
299  * in which case the bodyStart is updated.
300  */
301 public RecoveredElement updateOnOpeningBrace(int braceEnd){
302
303         if (bracketBalance++ == 0){
304                 this.updateBodyStart(braceEnd + 1);
305                 return this;
306         }
307         return null; // no update is necessary
308 }
309 /*
310  * Final update the corresponding parse node
311  */
312 public void updateParseTree(){
313 }
314 /*
315  * Update the declarationSourceEnd of the corresponding parse node
316  */
317 public void updateSourceEndIfNecessary(int sourceEnd){
318 }
319 }