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