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