improved PHP parser
[phpeclipse.git] / net.sourceforge.phpeclipse / src / net / sourceforge / phpeclipse / internal / compiler / ast / CompilationUnitDeclaration.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.phpeclipse.internal.compiler.ast;
12 import java.util.ArrayList;
13
14 import net.sourceforge.phpdt.core.compiler.CharOperation;
15 import net.sourceforge.phpdt.internal.compiler.ASTVisitor;
16 import net.sourceforge.phpdt.internal.compiler.CompilationResult;
17 import net.sourceforge.phpdt.internal.compiler.impl.ReferenceContext;
18 import net.sourceforge.phpdt.internal.compiler.lookup.CompilationUnitScope;
19 import net.sourceforge.phpdt.internal.compiler.lookup.LocalTypeBinding;
20 import net.sourceforge.phpdt.internal.compiler.problem.AbortCompilationUnit;
21 import net.sourceforge.phpdt.internal.compiler.problem.AbortMethod;
22 import net.sourceforge.phpdt.internal.compiler.problem.AbortType;
23 import net.sourceforge.phpdt.internal.compiler.problem.ProblemReporter;
24 import net.sourceforge.phpdt.internal.compiler.problem.ProblemSeverities;
25
26 public class CompilationUnitDeclaration extends ASTNode implements ProblemSeverities, ReferenceContext {
27
28   public ImportReference currentPackage;
29   public ImportReference[] imports;
30   //  public TypeDeclaration[] types;
31   public ArrayList types;
32   
33   //public char[][] name;
34   public int[][] comments;
35
36   public boolean ignoreFurtherInvestigation = false; // once pointless to investigate due to errors
37   public boolean ignoreMethodBodies = false;
38   public CompilationUnitScope scope;
39   public ProblemReporter problemReporter;
40   public CompilationResult compilationResult;
41
42   private LocalTypeBinding[] localTypes;
43   int localTypeCount = 0;
44
45   public boolean isPropagatingInnerClassEmulation;
46
47   public CompilationUnitDeclaration(ProblemReporter problemReporter, CompilationResult compilationResult, int sourceLength) {
48
49     this.problemReporter = problemReporter;
50     this.compilationResult = compilationResult;
51     this.types = new ArrayList();
52     //by definition of a compilation unit....
53     sourceStart = 0;
54     sourceEnd = sourceLength - 1;
55   }
56
57   /*
58    *    We cause the compilation task to abort to a given extent.
59    */
60   public void abort(int abortLevel) {
61
62     switch (abortLevel) {
63       case AbortType :
64         throw new AbortType(compilationResult);
65       case AbortMethod :
66         throw new AbortMethod(compilationResult);
67       default :
68         throw new AbortCompilationUnit(compilationResult);
69     }
70   }
71
72   /*
73    * Dispatch code analysis AND request saturation of inner emulation
74    */
75   public void analyseCode() {
76
77     if (ignoreFurtherInvestigation)
78       return;
79     try {
80       if (types != null) {
81         for (int i = 0, count = types.size(); i < count; i++) {
82           if (types.get(i) instanceof TypeDeclaration)
83              ((TypeDeclaration) types.get(i)).analyseCode(scope);
84         }
85       }
86       // request inner emulation propagation
87       propagateInnerEmulationForAllLocalTypes();
88     } catch (AbortCompilationUnit e) {
89       this.ignoreFurtherInvestigation = true;
90       return;
91     }
92   }
93
94   /*
95    * When unit result is about to be accepted, removed back pointers
96    * to compiler structures.
97    */
98   public void cleanUp() {
99     if (this.types != null) {
100       for (int i = 0, max = this.types.size(); i < max; i++) {
101         if (this.types.get(i) instanceof TypeDeclaration) {
102           cleanUp((TypeDeclaration) this.types.get(i));
103         }
104       }
105       for (int i = 0, max = this.localTypeCount; i < max; i++) {
106         // null out the type's scope backpointers
107         localTypes[i].scope = null; // local members are already in the list
108       }
109     }
110     //          ClassFile[] classFiles = compilationResult.getClassFiles();
111     //          for (int i = 0, max = classFiles.length; i < max; i++) {
112     //                  // clear the classFile back pointer to the bindings
113     //                  ClassFile classFile = classFiles[i];
114     //                  // null out the classfile backpointer to a type binding
115     //                  classFile.referenceBinding = null;
116     //                  classFile.codeStream = null; // codeStream holds onto ast and scopes
117     //                  classFile.innerClassesBindings = null;
118     //          }
119   }
120   private void cleanUp(TypeDeclaration type) {
121     if (type.memberTypes != null) {
122       for (int i = 0, max = type.memberTypes.length; i < max; i++) {
123         cleanUp(type.memberTypes[i]);
124       }
125     }
126     if (type.binding != null) {
127       // null out the type's scope backpointers
128       type.binding.scope = null;
129     }
130   }
131
132 //  public void checkUnusedImports() {
133 //
134 //    if (this.scope.imports != null) {
135 //      for (int i = 0, max = this.scope.imports.length; i < max; i++) {
136 //        ImportBinding importBinding = this.scope.imports[i];
137 //        ImportReference importReference = importBinding.reference;
138 //        if (importReference != null && !importReference.used) {
139 //          scope.problemReporter().unusedImport(importReference);
140 //        }
141 //      }
142 //    }
143 //  }
144
145   public CompilationResult compilationResult() {
146     return compilationResult;
147   }
148
149   /*
150    * Finds the matching type amoung this compilation unit types.
151    * Returns null if no type with this name is found.
152    * The type name is a compound name
153    * eg. if we're looking for X.A.B then a type name would be {X, A, B}
154    */
155   public TypeDeclaration declarationOfType(char[][] typeName) {
156
157     for (int i = 0; i < this.types.size(); i++) {
158       if (this.types.get(i) instanceof TypeDeclaration) {
159         TypeDeclaration typeDecl = ((TypeDeclaration) this.types.get(i)).declarationOfType(typeName);
160         if (typeDecl != null) {
161           return typeDecl;
162         }
163       }
164     }
165     return null;
166   }
167
168   /**
169    * Bytecode generation
170    */
171   //    public void generateCode() {
172   //
173   //            if (ignoreFurtherInvestigation) {
174   //                    if (types != null) {
175   //                            for (int i = 0, count = types.length; i < count; i++) {
176   //                                    types[i].ignoreFurtherInvestigation = true;
177   //                                    // propagate the flag to request problem type creation
178   //                                    types[i].generateCode(scope);
179   //                            }
180   //                    }
181   //                    return;
182   //            }
183   //            try {
184   //                    if (types != null) {
185   //                            for (int i = 0, count = types.length; i < count; i++)
186   //                                    types[i].generateCode(scope);
187   //                    }
188   //            } catch (AbortCompilationUnit e) {
189   //            }
190   //    }
191
192   public char[] getFileName() {
193
194     return compilationResult.getFileName();
195   }
196
197   public char[] getMainTypeName() {
198
199     if (compilationResult.compilationUnit == null) {
200       char[] fileName = compilationResult.getFileName();
201
202       int start = CharOperation.lastIndexOf('/', fileName) + 1;
203       if (start == 0 || start < CharOperation.lastIndexOf('\\', fileName))
204         start = CharOperation.lastIndexOf('\\', fileName) + 1;
205
206       int end = CharOperation.lastIndexOf('.', fileName);
207       if (end == -1)
208         end = fileName.length;
209
210       return CharOperation.subarray(fileName, start, end);
211     } else {
212       return compilationResult.compilationUnit.getMainTypeName();
213     }
214   }
215
216   public boolean isEmpty() {
217
218     return (currentPackage == null) && (imports == null) && (types == null);
219   }
220
221   public boolean hasErrors() {
222     return this.ignoreFurtherInvestigation;
223   }
224         public StringBuffer print(int indent, StringBuffer output) {
225
226                 if (currentPackage != null) {
227                         printIndent(indent, output).append("package "); //$NON-NLS-1$
228                         currentPackage.print(0, output, false).append(";\n"); //$NON-NLS-1$
229                 }
230                 if (imports != null)
231                         for (int i = 0; i < imports.length; i++) {
232                                 printIndent(indent, output).append("import "); //$NON-NLS-1$
233                                 imports[i].print(0, output).append(";\n"); //$NON-NLS-1$ 
234                         }
235
236                 if (types != null) {
237                         for (int i = 0; i < types.size(); i++) {
238                                 ((ASTNode)types.get(i)).print(indent, output).append("\n"); //$NON-NLS-1$
239                         }
240                 }
241                 return output;
242         }
243         
244   /*
245    * Force inner local types to update their innerclass emulation
246    */
247   public void propagateInnerEmulationForAllLocalTypes() {
248
249     isPropagatingInnerClassEmulation = true;
250     for (int i = 0, max = this.localTypeCount; i < max; i++) {
251
252       LocalTypeBinding localType = localTypes[i];
253       // only propagate for reachable local types
254       if ((localType.scope.referenceType().bits & IsReachableMASK) != 0) {
255         localType.updateInnerEmulationDependents();
256       }
257     }
258   }
259
260   /*
261    * Keep track of all local types, so as to update their innerclass
262    * emulation later on.
263    */
264   public void record(LocalTypeBinding localType) {
265
266     if (this.localTypeCount == 0) {
267       this.localTypes = new LocalTypeBinding[5];
268     } else if (this.localTypeCount == this.localTypes.length) {
269       System.arraycopy(
270         this.localTypes,
271         0,
272         (this.localTypes = new LocalTypeBinding[this.localTypeCount * 2]),
273         0,
274         this.localTypeCount);
275     }
276     this.localTypes[this.localTypeCount++] = localType;
277   }
278
279   public void resolve() {
280
281     try {
282       if (types != null) {
283         for (int i = 0, count = types.size(); i < count; i++) {
284           if (types.get(i) instanceof TypeDeclaration) {
285             ((TypeDeclaration) types.get(i)).resolve(scope);
286           }
287         }
288       }
289 //      if (!this.compilationResult.hasSyntaxError())
290 //        checkUnusedImports();
291     } catch (AbortCompilationUnit e) {
292       this.ignoreFurtherInvestigation = true;
293       return;
294     }
295   }
296
297   public void tagAsHavingErrors() {
298     ignoreFurtherInvestigation = true;
299   }
300
301   public String toString(int tab) {
302
303     String s = ""; //$NON-NLS-1$
304     if (currentPackage != null)
305       s = tabString(tab) + "package " + currentPackage.toString(0, false) + ";\n"; //$NON-NLS-1$ //$NON-NLS-2$
306
307     if (imports != null)
308       for (int i = 0; i < imports.length; i++) {
309         s += tabString(tab) + "include " + imports[i].toString() + ";\n"; //$NON-NLS-1$ //$NON-NLS-2$
310       };
311
312     if (types != null)
313       for (int i = 0; i < types.size(); i++) {
314         s += ((ASTNode) types.get(i)).toString(tab) + "\n"; //$NON-NLS-1$
315       }
316     return s;
317   }
318
319   public void traverse(ASTVisitor visitor, CompilationUnitScope scope) {
320
321     if (ignoreFurtherInvestigation)
322       return;
323     try {
324       if (visitor.visit(this, scope)) {
325         if (currentPackage != null) {
326           currentPackage.traverse(visitor, scope);
327         }
328         if (imports != null) {
329           int importLength = imports.length;
330           for (int i = 0; i < importLength; i++) {
331             imports[i].traverse(visitor, scope);
332           }
333         }
334         if (types != null) {
335           int typesLength = types.size();
336           for (int i = 0; i < typesLength; i++) {
337             if (types.get(i) instanceof TypeDeclaration) {
338               ((TypeDeclaration) types.get(i)).traverse(visitor, scope);
339             }
340           }
341         }
342       }
343       visitor.endVisit(this, scope);
344     } catch (AbortCompilationUnit e) {
345     }
346   }
347 }