intial version
[phpeclipse.git] / net.sourceforge.phpeclipse / src / net / sourceforge / phpdt / internal / compiler / parser / RecoveredInitializer.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 initializer structure for parsing recovery 
15  */
16 import net.sourceforge.phpdt.core.compiler.ITerminalSymbols;
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.Initializer;
21 import net.sourceforge.phpdt.internal.compiler.ast.LocalDeclaration;
22 import net.sourceforge.phpdt.internal.compiler.ast.LocalTypeDeclaration;
23 import net.sourceforge.phpdt.internal.compiler.ast.Statement;
24 import net.sourceforge.phpdt.internal.compiler.ast.TypeDeclaration;
25 import net.sourceforge.phpdt.internal.compiler.lookup.BaseTypes;
26 import net.sourceforge.phpdt.internal.compiler.lookup.CompilerModifiers;
27 import net.sourceforge.phpdt.internal.compiler.util.CharOperation;
28
29 public class RecoveredInitializer extends RecoveredField implements CompilerModifiers, ITerminalSymbols, BaseTypes {
30
31         public RecoveredType[] localTypes;
32         public int localTypeCount;
33
34         public RecoveredBlock initializerBody;  
35 public RecoveredInitializer(FieldDeclaration fieldDeclaration, RecoveredElement parent, int bracketBalance){
36         this(fieldDeclaration, parent, bracketBalance, null);
37 }
38 public RecoveredInitializer(FieldDeclaration fieldDeclaration, RecoveredElement parent, int bracketBalance, Parser parser){
39         super(fieldDeclaration, parent, bracketBalance, parser);
40         this.foundOpeningBrace = true;
41 }
42 /*
43  * Record a nested block declaration
44  */
45 public RecoveredElement add(Block nestedBlockDeclaration, int bracketBalance) {
46
47         /* default behavior is to delegate recording to parent if any,
48         do not consider elements passed the known end (if set)
49         it must be belonging to an enclosing element 
50         */
51         if (fieldDeclaration.declarationSourceEnd > 0
52                 && nestedBlockDeclaration.sourceStart
53                         > fieldDeclaration.declarationSourceEnd){
54                 if (this.parent == null){
55                         return this; // ignore
56                 } else {
57                         return this.parent.add(nestedBlockDeclaration, bracketBalance);
58                 }
59         }
60         /* consider that if the opening brace was not found, it is there */
61         if (!foundOpeningBrace){
62                 foundOpeningBrace = true;
63                 this.bracketBalance++;
64         }
65
66         initializerBody = new RecoveredBlock(nestedBlockDeclaration, this, bracketBalance);
67         if (nestedBlockDeclaration.sourceEnd == 0) return initializerBody;
68         return this;
69 }
70 /*
71  * Record a field declaration (act like inside method body)
72  */
73 public RecoveredElement add(FieldDeclaration newFieldDeclaration, int bracketBalance) {
74
75         /* local variables inside initializer can only be final and non void */
76         char[][] fieldTypeName;
77         if ((newFieldDeclaration.modifiers & ~AccFinal) != 0 /* local var can only be final */
78                 || (newFieldDeclaration.type == null) // initializer
79                 || ((fieldTypeName = newFieldDeclaration.type.getTypeName()).length == 1 // non void
80                         && CharOperation.equals(fieldTypeName[0], VoidBinding.sourceName()))){ 
81                 if (this.parent == null) {
82                         return this; // ignore
83                 } else {
84                         this.updateSourceEndIfNecessary(this.previousAvailableLineEnd(newFieldDeclaration.declarationSourceStart - 1));
85                         return this.parent.add(newFieldDeclaration, bracketBalance);
86                 }
87         }
88
89         /* default behavior is to delegate recording to parent if any,
90         do not consider elements passed the known end (if set)
91         it must be belonging to an enclosing element 
92         */
93         if (this.fieldDeclaration.declarationSourceEnd > 0
94                 && newFieldDeclaration.declarationSourceStart
95                         > this.fieldDeclaration.declarationSourceEnd){
96                 if (this.parent == null) {
97                         return this; // ignore
98                 } else {
99                         return this.parent.add(newFieldDeclaration, bracketBalance);
100                 }
101         }
102         // still inside initializer, treat as local variable
103         return this; // ignore
104 }
105 /*
106  * Record a local declaration - regular method should have been created a block body
107  */
108 public RecoveredElement add(LocalDeclaration localDeclaration, int bracketBalance) {
109
110         /* do not consider a type starting passed the type end (if set)
111                 it must be belonging to an enclosing type */
112         if (fieldDeclaration.declarationSourceEnd != 0 
113                 && localDeclaration.declarationSourceStart > fieldDeclaration.declarationSourceEnd){
114                 if (parent == null) {
115                         return this; // ignore
116                 } else {
117                         return this.parent.add(localDeclaration, bracketBalance);
118                 }
119         }
120         /* method body should have been created */
121         Block block = new Block(0);
122         block.sourceStart = ((Initializer)fieldDeclaration).bodyStart;
123         RecoveredElement element = this.add(block, 1);
124         return element.add(localDeclaration, bracketBalance);   
125 }
126 /*
127  * Record a statement - regular method should have been created a block body
128  */
129 public RecoveredElement add(Statement statement, int bracketBalance) {
130
131         /* do not consider a statement starting passed the initializer end (if set)
132                 it must be belonging to an enclosing type */
133         if (fieldDeclaration.declarationSourceEnd != 0 
134                 && statement.sourceStart > fieldDeclaration.declarationSourceEnd){
135                 if (parent == null) {
136                         return this; // ignore
137                 } else {
138                         return this.parent.add(statement, bracketBalance);
139                 }
140         }
141         /* initializer body should have been created */
142         Block block = new Block(0);
143         block.sourceStart = ((Initializer)fieldDeclaration).bodyStart;
144         RecoveredElement element = this.add(block, 1);
145         return element.add(statement, bracketBalance);  
146 }
147 public RecoveredElement add(TypeDeclaration typeDeclaration, int bracketBalance) {
148
149         /* do not consider a type starting passed the type end (if set)
150                 it must be belonging to an enclosing type */
151         if (fieldDeclaration.declarationSourceEnd != 0 
152                 && typeDeclaration.declarationSourceStart > fieldDeclaration.declarationSourceEnd){
153                 if (parent == null) {
154                         return this; // ignore
155                 } else {
156                         return this.parent.add(typeDeclaration, bracketBalance);
157                 }
158         }
159         if (typeDeclaration instanceof LocalTypeDeclaration){
160                 /* method body should have been created */
161                 Block block = new Block(0);
162                 block.sourceStart = ((Initializer)fieldDeclaration).bodyStart;
163                 RecoveredElement element = this.add(block, 1);
164                 return element.add(typeDeclaration, bracketBalance);    
165         }       
166         if (localTypes == null) {
167                 localTypes = new RecoveredType[5];
168                 localTypeCount = 0;
169         } else {
170                 if (localTypeCount == localTypes.length) {
171                         System.arraycopy(
172                                 localTypes, 
173                                 0, 
174                                 (localTypes = new RecoveredType[2 * localTypeCount]), 
175                                 0, 
176                                 localTypeCount); 
177                 }
178         }
179         RecoveredType element = new RecoveredType(typeDeclaration, this, bracketBalance);
180         localTypes[localTypeCount++] = element;
181
182         /* consider that if the opening brace was not found, it is there */
183         if (!foundOpeningBrace){
184                 foundOpeningBrace = true;
185                 this.bracketBalance++;
186         }
187         return element;
188 }
189 public String toString(int tab) {
190         StringBuffer result = new StringBuffer(tabString(tab));
191         result.append("Recovered initializer:\n"); //$NON-NLS-1$
192         result.append(this.fieldDeclaration.toString(tab + 1));
193         if (this.initializerBody != null) {
194                 result.append("\n"); //$NON-NLS-1$
195                 result.append(this.initializerBody.toString(tab + 1));
196         }
197         return result.toString();
198 }
199 public FieldDeclaration updatedFieldDeclaration(){
200
201         if (initializerBody != null){
202                 Block block = initializerBody.updatedBlock();
203                 if (block != null){
204                         ((Initializer)fieldDeclaration).block = block;
205                 }
206                 if (this.localTypeCount > 0) fieldDeclaration.bits |= AstNode.HasLocalTypeMASK;
207
208         }       
209         if (fieldDeclaration.sourceEnd == 0){
210                 fieldDeclaration.sourceEnd = fieldDeclaration.declarationSourceEnd;
211         }
212         return fieldDeclaration;
213 }
214 /*
215  * A closing brace got consumed, might have closed the current element,
216  * in which case both the currentElement is exited
217  */
218 public RecoveredElement updateOnClosingBrace(int braceStart, int braceEnd){
219         if ((--bracketBalance <= 0) && (parent != null)){
220                 this.updateSourceEndIfNecessary(braceEnd);
221                 return parent;
222         }
223         return this;
224 }
225 /*
226  * An opening brace got consumed, might be the expected opening one of the current element,
227  * in which case the bodyStart is updated.
228  */
229 public RecoveredElement updateOnOpeningBrace(int currentPosition){
230         bracketBalance++;
231         return this; // request to restart
232 }
233 /*
234  * Update the declarationSourceEnd of the corresponding parse node
235  */
236 public void updateSourceEndIfNecessary(int sourceEnd){
237         if (this.fieldDeclaration.declarationSourceEnd == 0) {
238                 this.fieldDeclaration.sourceEnd = sourceEnd;
239                 this.fieldDeclaration.declarationSourceEnd = sourceEnd;
240                 this.fieldDeclaration.declarationEnd = sourceEnd;
241         }
242 }
243 }