Makefile fixup
[org.ibex.tool.git] / repo / org.ibex.tool / src / org / eclipse / jdt / internal / compiler / parser / RecoveredBlock.java
1 /*******************************************************************************
2  * Copyright (c) 2000, 2004 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 org.eclipse.jdt.internal.compiler.parser;
12
13 /**
14  * Internal block structure for parsing recovery 
15  */
16 import org.eclipse.jdt.core.compiler.*;
17 import org.eclipse.jdt.internal.compiler.ast.Argument;
18 import org.eclipse.jdt.internal.compiler.ast.ASTNode;
19 import org.eclipse.jdt.internal.compiler.ast.Block;
20 import org.eclipse.jdt.internal.compiler.ast.FieldDeclaration;
21 import org.eclipse.jdt.internal.compiler.ast.LocalDeclaration;
22 import org.eclipse.jdt.internal.compiler.ast.Statement;
23 import org.eclipse.jdt.internal.compiler.ast.TypeDeclaration;
24 import org.eclipse.jdt.internal.compiler.lookup.BaseTypes;
25 import org.eclipse.jdt.internal.compiler.lookup.CompilerModifiers;
26
27 public class RecoveredBlock extends RecoveredStatement implements CompilerModifiers, TerminalTokens, BaseTypes {
28
29         public Block blockDeclaration;
30         public RecoveredStatement[] statements;
31         public int statementCount;
32         public boolean preserveContent = false;
33         public RecoveredLocalVariable pendingArgument;
34         
35 public RecoveredBlock(Block block, RecoveredElement parent, int bracketBalance){
36         super(block, parent, bracketBalance);
37         this.blockDeclaration = block;
38         this.foundOpeningBrace = true;
39 }
40 /*
41  * Record a nested block declaration 
42  */
43 public RecoveredElement add(Block nestedBlockDeclaration, int bracketBalanceValue) {
44
45         /* do not consider a nested block starting passed the block end (if set)
46                 it must be belonging to an enclosing block */
47         if (this.blockDeclaration.sourceEnd != 0 
48                 && nestedBlockDeclaration.sourceStart > this.blockDeclaration.sourceEnd){
49                 return this.parent.add(nestedBlockDeclaration, bracketBalanceValue);
50         }
51                         
52         RecoveredBlock element = new RecoveredBlock(nestedBlockDeclaration, this, bracketBalanceValue);
53
54         // if we have a pending Argument, promote it into the new block
55         if (this.pendingArgument != null){
56                 element.attach(this.pendingArgument);
57                 this.pendingArgument = null;
58         }
59         this.attach(element);
60         if (nestedBlockDeclaration.sourceEnd == 0) return element;
61         return this;    
62 }
63 /*
64  * Record a local declaration 
65  */
66 public RecoveredElement add(LocalDeclaration localDeclaration, int bracketBalanceValue) {
67         return this.add(localDeclaration, bracketBalanceValue, false);
68 }
69 /*
70  * Record a local declaration 
71  */
72 public RecoveredElement add(LocalDeclaration localDeclaration, int bracketBalanceValue, boolean delegatedByParent) {
73
74         /* local variables inside method can only be final and non void */
75 /*      
76         char[][] localTypeName; 
77         if ((localDeclaration.modifiers & ~AccFinal) != 0 // local var can only be final 
78                 || (localDeclaration.type == null) // initializer
79                 || ((localTypeName = localDeclaration.type.getTypeName()).length == 1 // non void
80                         && CharOperation.equals(localTypeName[0], VoidBinding.sourceName()))){ 
81
82                 if (delegatedByParent){
83                         return this; //ignore
84                 } else {
85                         this.updateSourceEndIfNecessary(this.previousAvailableLineEnd(localDeclaration.declarationSourceStart - 1));
86                         return this.parent.add(localDeclaration, bracketBalance);
87                 }
88         }
89 */      
90                 /* do not consider a local variable starting passed the block end (if set)
91                 it must be belonging to an enclosing block */
92         if (this.blockDeclaration.sourceEnd != 0 
93                         && localDeclaration.declarationSourceStart > this.blockDeclaration.sourceEnd){
94                 if (delegatedByParent) return this; //ignore
95                 return this.parent.add(localDeclaration, bracketBalanceValue);
96         }
97
98         RecoveredLocalVariable element = new RecoveredLocalVariable(localDeclaration, this, bracketBalanceValue);
99
100         if (localDeclaration instanceof Argument){
101                 this.pendingArgument = element;
102                 return this;
103         }
104         
105         this.attach(element);
106         if (localDeclaration.declarationSourceEnd == 0) return element;
107         return this;    
108 }
109 /*
110  * Record a statement declaration 
111  */
112 public RecoveredElement add(Statement stmt, int bracketBalanceValue) {
113         return this.add(stmt, bracketBalanceValue, false);
114 }
115
116 /*
117  * Record a statement declaration 
118  */
119 public RecoveredElement add(Statement stmt, int bracketBalanceValue, boolean delegatedByParent) {
120
121         /* do not consider a nested block starting passed the block end (if set)
122                 it must be belonging to an enclosing block */
123         if (this.blockDeclaration.sourceEnd != 0 
124                         && stmt.sourceStart > this.blockDeclaration.sourceEnd){
125                 if (delegatedByParent) return this; //ignore
126                 return this.parent.add(stmt, bracketBalanceValue);
127         }
128                         
129         RecoveredStatement element = new RecoveredStatement(stmt, this, bracketBalanceValue);
130         this.attach(element);
131         if (stmt.sourceEnd == 0) return element;
132         return this;    
133 }
134 /*
135  * Addition of a type to an initializer (act like inside method body)
136  */
137 public RecoveredElement add(TypeDeclaration typeDeclaration, int bracketBalanceValue) {
138         return this.add(typeDeclaration, bracketBalanceValue, false);
139 }
140 /*
141  * Addition of a type to an initializer (act like inside method body)
142  */
143 public RecoveredElement add(TypeDeclaration typeDeclaration, int bracketBalanceValue, boolean delegatedByParent) {
144
145         /* do not consider a type starting passed the block end (if set)
146                 it must be belonging to an enclosing block */
147         if (this.blockDeclaration.sourceEnd != 0 
148                         && typeDeclaration.declarationSourceStart > this.blockDeclaration.sourceEnd){
149                 if (delegatedByParent) return this; //ignore
150                 return this.parent.add(typeDeclaration, bracketBalanceValue);
151         }
152                         
153         RecoveredStatement element = new RecoveredType(typeDeclaration, this, bracketBalanceValue);
154         this.attach(element);
155         if (typeDeclaration.declarationSourceEnd == 0) return element;
156         return this;
157 }
158 /*
159  * Attach a recovered statement
160  */
161 void attach(RecoveredStatement recoveredStatement) {
162
163         if (this.statements == null) {
164                 this.statements = new RecoveredStatement[5];
165                 this.statementCount = 0;
166         } else {
167                 if (this.statementCount == this.statements.length) {
168                         System.arraycopy(
169                                 this.statements, 
170                                 0, 
171                                 (this.statements = new RecoveredStatement[2 * this.statementCount]), 
172                                 0, 
173                                 this.statementCount); 
174                 }
175         }
176         this.statements[this.statementCount++] = recoveredStatement;
177 }
178 /* 
179  * Answer the associated parsed structure
180  */
181 public ASTNode parseTree(){
182         return this.blockDeclaration;
183 }
184 public String toString(int tab) {
185         StringBuffer result = new StringBuffer(tabString(tab));
186         result.append("Recovered block:\n"); //$NON-NLS-1$
187         this.blockDeclaration.print(tab + 1, result);
188         if (this.statements != null) {
189                 for (int i = 0; i < this.statementCount; i++) {
190                         result.append("\n"); //$NON-NLS-1$
191                         result.append(this.statements[i].toString(tab + 1));
192                 }
193         }
194         return result.toString();
195 }
196 /*
197  * Rebuild a block from the nested structure which is in scope
198  */
199 public Block updatedBlock(){
200
201         // if block was not marked to be preserved or empty, then ignore it
202         if (!this.preserveContent || this.statementCount == 0) return null;
203
204         Statement[] updatedStatements = new Statement[this.statementCount];
205         int updatedCount = 0;
206         
207         // only collect the non-null updated statements
208         for (int i = 0; i < this.statementCount; i++){
209                 Statement updatedStatement = this.statements[i].updatedStatement();
210                 if (updatedStatement != null){
211                         updatedStatements[updatedCount++] = updatedStatement;
212                 }
213         }
214         if (updatedCount == 0) return null; // not interesting block
215
216         // resize statement collection if necessary
217         if (updatedCount != this.statementCount){
218                 this.blockDeclaration.statements = new Statement[updatedCount];
219                 System.arraycopy(updatedStatements, 0, this.blockDeclaration.statements, 0, updatedCount);
220         } else {
221                 this.blockDeclaration.statements = updatedStatements;
222         }
223
224         return this.blockDeclaration;
225 }
226 /*
227  * Rebuild a statement from the nested structure which is in scope
228  */
229 public Statement updatedStatement(){
230
231         return this.updatedBlock();
232 }
233 /*
234  * A closing brace got consumed, might have closed the current element,
235  * in which case both the currentElement is exited
236  */
237 public RecoveredElement updateOnClosingBrace(int braceStart, int braceEnd){
238         if ((--this.bracketBalance <= 0) && (this.parent != null)){
239                 this.updateSourceEndIfNecessary(braceStart, braceEnd);
240
241                 /* if the block is the method body, then it closes the method too */
242                 RecoveredMethod method = enclosingMethod();
243                 if (method != null && method.methodBody == this){
244                         return this.parent.updateOnClosingBrace(braceStart, braceEnd);
245                 }
246                 RecoveredInitializer initializer = enclosingInitializer();
247                 if (initializer != null && initializer.initializerBody == this){
248                         return this.parent.updateOnClosingBrace(braceStart, braceEnd);
249                 }
250                 return this.parent;
251         }
252         return this;
253 }
254 /*
255  * An opening brace got consumed, might be the expected opening one of the current element,
256  * in which case the bodyStart is updated.
257  */
258 public RecoveredElement updateOnOpeningBrace(int braceStart, int braceEnd){
259
260         // create a nested block
261         Block block = new Block(0);
262         block.sourceStart = parser().scanner.startPosition;
263         return this.add(block, 1);
264 }
265 /*
266  * Final update the corresponding parse node
267  */
268 public void updateParseTree(){
269
270         this.updatedBlock();
271 }
272 /*
273  * Rebuild a flattened block from the nested structure which is in scope
274  */
275 public Statement updateStatement(){
276
277         // if block was closed or empty, then ignore it
278         if (this.blockDeclaration.sourceEnd != 0 || this.statementCount == 0) return null;
279
280         Statement[] updatedStatements = new Statement[this.statementCount];
281         int updatedCount = 0;
282         
283         // only collect the non-null updated statements
284         for (int i = 0; i < this.statementCount; i++){
285                 Statement updatedStatement = this.statements[i].updatedStatement();
286                 if (updatedStatement != null){
287                         updatedStatements[updatedCount++] = updatedStatement;
288                 }
289         }
290         if (updatedCount == 0) return null; // not interesting block
291
292         // resize statement collection if necessary
293         if (updatedCount != this.statementCount){
294                 this.blockDeclaration.statements = new Statement[updatedCount];
295                 System.arraycopy(updatedStatements, 0, this.blockDeclaration.statements, 0, updatedCount);
296         } else {
297                 this.blockDeclaration.statements = updatedStatements;
298         }
299
300         return this.blockDeclaration;
301 }
302
303 /*
304  * Record a field declaration 
305  */
306 public RecoveredElement add(FieldDeclaration fieldDeclaration, int bracketBalanceValue) {
307
308         /* local variables inside method can only be final and non void */
309         char[][] fieldTypeName; 
310         if ((fieldDeclaration.modifiers & ~AccFinal) != 0 // local var can only be final 
311                 || (fieldDeclaration.type == null) // initializer
312                 || ((fieldTypeName = fieldDeclaration.type.getTypeName()).length == 1 // non void
313                         && CharOperation.equals(fieldTypeName[0], VoidBinding.sourceName()))){ 
314                 this.updateSourceEndIfNecessary(this.previousAvailableLineEnd(fieldDeclaration.declarationSourceStart - 1));
315                 return this.parent.add(fieldDeclaration, bracketBalanceValue);
316         }
317         
318         /* do not consider a local variable starting passed the block end (if set)
319                 it must be belonging to an enclosing block */
320         if (this.blockDeclaration.sourceEnd != 0 
321                 && fieldDeclaration.declarationSourceStart > this.blockDeclaration.sourceEnd){
322                 return this.parent.add(fieldDeclaration, bracketBalanceValue);
323         }
324
325         // ignore the added field, since indicates a local variable behind recovery point
326         // which thus got parsed as a field reference. This can happen if restarting after
327         // having reduced an assistNode to get the following context (see 1GEK7SG)
328         return this;    
329 }
330 }