Improved calculation of function/methods sourceEnd for code folding
[phpeclipse.git] / net.sourceforge.phpeclipse / src / net / sourceforge / phpdt / internal / compiler / parser / UnitParser.java
1 package net.sourceforge.phpdt.internal.compiler.parser;
2
3
4 import net.sourceforge.phpdt.core.IJavaModelMarker;
5 import net.sourceforge.phpdt.core.compiler.IProblem;
6 import net.sourceforge.phpdt.internal.compiler.CompilationResult;
7 import net.sourceforge.phpdt.internal.compiler.env.ICompilationUnit;
8 import net.sourceforge.phpdt.internal.compiler.problem.AbortCompilation;
9 import net.sourceforge.phpdt.internal.compiler.problem.ProblemReporter;
10 import net.sourceforge.phpdt.internal.core.BasicCompilationUnit;
11 import net.sourceforge.phpeclipse.internal.compiler.ast.ASTNode;
12 import net.sourceforge.phpeclipse.internal.compiler.ast.CompilationUnitDeclaration;
13 import net.sourceforge.phpeclipse.internal.compiler.ast.ConstructorDeclaration;
14 import net.sourceforge.phpeclipse.internal.compiler.ast.FieldDeclaration;
15 import net.sourceforge.phpeclipse.internal.compiler.ast.Initializer;
16 import net.sourceforge.phpeclipse.internal.compiler.ast.MethodDeclaration;
17 import net.sourceforge.phpeclipse.internal.compiler.ast.TypeDeclaration;
18
19 import org.eclipse.core.resources.IMarker;
20 import org.eclipse.core.resources.IResource;
21 import org.eclipse.core.runtime.CoreException;
22
23 /**
24  * 
25  * 
26  */
27 public class UnitParser extends Parser {
28
29   public UnitParser(ProblemReporter problemReporter) { //, boolean optimizeStringLiterals, boolean assertMode) {
30     super(problemReporter);
31     nestedMethod = new int[30];
32     
33     //          this.optimizeStringLiterals = optimizeStringLiterals;
34     //          this.assertMode = assertMode;
35     //          this.initializeScanner();
36     astLengthStack = new int[50];
37     //          expressionLengthStack = new int[30];
38     //          intStack = new int[50];
39     //          identifierStack = new char[30][];
40     //          identifierLengthStack = new int[30];
41     //          nestedMethod = new int[30];
42     //          realBlockStack = new int[30];
43     //          identifierPositionStack = new long[30];
44     //          variablesCounter = new int[30];
45   }
46
47   public void goForConstructorBody() {
48     //tells the scanner to go for compilation unit parsing
49
50     firstToken = TokenNameEQUAL_EQUAL;
51     scanner.recordLineSeparator = false;
52   }
53   public void goForExpression() {
54     //tells the scanner to go for an expression parsing
55
56     firstToken = TokenNameREMAINDER;
57     scanner.recordLineSeparator = false;
58   }
59   public void goForCompilationUnit() {
60     //tells the scanner to go for compilation unit parsing
61
62     firstToken = TokenNamePLUS_PLUS;
63     scanner.linePtr = -1;
64     scanner.foundTaskCount = 0;
65     scanner.recordLineSeparator = true;
66     //          scanner.currentLine= null;
67   }
68   public void goForInitializer() {
69     //tells the scanner to go for initializer parsing
70
71     firstToken = TokenNameRIGHT_SHIFT;
72     scanner.recordLineSeparator = false;
73   }
74   public void goForMethodBody() {
75     //tells the scanner to go for method body parsing
76
77     firstToken = TokenNameMINUS_MINUS;
78     scanner.recordLineSeparator = false;
79   }
80   public void initialize(boolean phpMode) {
81     super.initialize(phpMode);
82     //positionning the parser for a new compilation unit
83     //avoiding stack reallocation and all that....
84     //          astPtr = -1;
85     //          astLengthPtr = -1;
86     //          expressionPtr = -1;
87     //          expressionLengthPtr = -1;
88     //          identifierPtr = -1;     
89     //          identifierLengthPtr     = -1;
90     //          intPtr = -1;
91     //          nestedMethod[nestedType = 0] = 0; // need to reset for further reuse
92     //          variablesCounter[nestedType] = 0;
93     //          dimensions = 0 ;
94     //          realBlockPtr = -1;
95     //          endStatementPosition = 0;
96
97     //remove objects from stack too, while the same parser/compiler couple is
98     //re-used between two compilations ....
99
100     //          int astLength = astStack.length;
101     //          if (noAstNodes.length < astLength){
102     //                  noAstNodes = new ASTNode[astLength];
103     //                  //System.out.println("Resized AST stacks : "+ astLength);
104     //          
105     //          }
106     //          System.arraycopy(noAstNodes, 0, astStack, 0, astLength);
107     //
108     //          int expressionLength = expressionStack.length;
109     //          if (noExpressions.length < expressionLength){
110     //                  noExpressions = new Expression[expressionLength];
111     //                  //System.out.println("Resized EXPR stacks : "+ expressionLength);
112     //          }
113     //          System.arraycopy(noExpressions, 0, expressionStack, 0, expressionLength);
114
115     // reset scanner state
116     scanner.commentPtr = -1;
117     scanner.foundTaskCount = 0;
118     scanner.eofPosition = Integer.MAX_VALUE;
119
120     //          resetModifiers();
121     //
122     //          // recovery
123     //          lastCheckPoint = -1;
124     //          currentElement = null;
125     //          restartRecovery = false;
126     //          hasReportedError = false;
127     //          recoveredStaticInitializerStart = 0;
128     //          lastIgnoredToken = -1;
129     //          lastErrorEndPosition = -1;
130     //          listLength = 0;
131   }
132
133   // A P I
134
135   public CompilationUnitDeclaration parse(ICompilationUnit sourceUnit, CompilationResult compilationResult, boolean phpMode) {
136     // parses a compilation unit and manages error handling (even bugs....)
137
138     CompilationUnitDeclaration unit;
139     try {
140       /* automaton initialization */
141       initialize(phpMode);
142       goForCompilationUnit();
143
144       /* scanner initialization */
145       scanner.setSource(sourceUnit, sourceUnit.getContents());
146
147       /* unit creation */
148       referenceContext =
149         compilationUnit = new CompilationUnitDeclaration(problemReporter, compilationResult, scanner.source.length);
150       // TODO TypeDeclaration test
151       //      TypeDeclaration typeDecl = new TypeDeclaration(this.compilationUnit.compilationResult);
152       //      typeDecl.sourceStart = 0;
153       //      typeDecl.sourceEnd = 10;
154       //      typeDecl.name = new char[]{'t', 'e','s','t'};
155       //      this.compilationUnit.types = new ArrayList();
156       //      this.compilationUnit.types.add(typeDecl);
157       /* run automaton */
158       super.parse();
159 //      //              TODO jsurfer start 
160 //      if (sourceUnit instanceof BasicCompilationUnit) {
161 //        storeProblemsFor(((BasicCompilationUnit)sourceUnit).getResource(), compilationResult.getAllProblems());
162 //      }
163 //      // jsurfer end
164     
165     } finally {
166       unit = compilationUnit;
167       compilationUnit = null; // reset parser
168     }
169     return unit;
170   }
171   /**
172                  * Creates a marker from each problem and adds it to the resource.
173                  * The marker is as follows:
174                  *   - its type is T_PROBLEM
175                  *   - its plugin ID is the JavaBuilder's plugin ID
176                  *       - its message is the problem's message
177                  *       - its priority reflects the severity of the problem
178                  *       - its range is the problem's range
179                  *       - it has an extra attribute "ID" which holds the problem's id
180                  */
181   protected void storeProblemsFor(IResource resource, IProblem[] problems) throws CoreException {
182     if (resource == null || problems == null || problems.length == 0)
183       return;
184
185     for (int i = 0, l = problems.length; i < l; i++) {
186       IProblem problem = problems[i];
187       int id = problem.getID();
188       if (id != IProblem.Task) {
189         IMarker marker = resource.createMarker(IJavaModelMarker.JAVA_MODEL_PROBLEM_MARKER);
190         marker.setAttributes(
191           new String[] {
192             IMarker.MESSAGE,
193             IMarker.SEVERITY,
194             IJavaModelMarker.ID,
195             IMarker.CHAR_START,
196             IMarker.CHAR_END,
197             IMarker.LINE_NUMBER,
198             IJavaModelMarker.ARGUMENTS },
199           new Object[] {
200             problem.getMessage(),
201             new Integer(problem.isError() ? IMarker.SEVERITY_ERROR : IMarker.SEVERITY_WARNING),
202             new Integer(id),
203             new Integer(problem.getSourceStart()),
204             new Integer(problem.getSourceEnd() + 1),
205             new Integer(problem.getSourceLineNumber()),
206             net.sourceforge.phpdt.internal.core.util.Util.getProblemArgumentsForMarker(problem.getArguments())});
207       }
208
209     }
210   }
211
212
213   // A P I
214
215   public void parse(ConstructorDeclaration cd, CompilationUnitDeclaration unit) {
216     //only parse the method body of cd
217     //fill out its statements
218
219     //convert bugs into parse error
220
221     initialize(false);
222     goForConstructorBody();
223     nestedMethod[nestedType]++;
224
225     referenceContext = cd;
226     compilationUnit = unit;
227     
228     scanner.resetTo(cd.sourceEnd + 1, cd.declarationSourceEnd);
229     try {
230       parse();
231     } catch (AbortCompilation ex) {
232       lastAct = ERROR_ACTION;
233     
234     } finally {
235       nestedMethod[nestedType]--;
236     }
237
238     if (lastAct == ERROR_ACTION) {
239       initialize(false);
240       return;
241     }
242
243     //statements
244     //  cd.explicitDeclarations = realBlockStack[realBlockPtr--];
245     //  int length;
246     //  if ((length = astLengthStack[astLengthPtr--]) != 0) {
247     //          astPtr -= length;
248     //          if (astStack[astPtr + 1] instanceof ExplicitConstructorCall)
249     //                  //avoid a isSomeThing that would only be used here BUT what is faster between two alternatives ?
250     //                  {
251     //                  System.arraycopy(
252     //                          astStack, 
253     //                          astPtr + 2, 
254     //                          cd.statements = new Statement[length - 1], 
255     //                          0, 
256     //                          length - 1); 
257     //                  cd.constructorCall = (ExplicitConstructorCall) astStack[astPtr + 1];
258     //          } else { //need to add explicitly the super();
259     //                  System.arraycopy(
260     //                          astStack, 
261     //                          astPtr + 1, 
262     //                          cd.statements = new Statement[length], 
263     //                          0, 
264     //                          length); 
265     //                  cd.constructorCall = SuperReference.implicitSuperConstructorCall();
266     //          }
267     //  } else {
268     //          cd.constructorCall = SuperReference.implicitSuperConstructorCall();
269     //  }
270     //
271     //  if (cd.constructorCall.sourceEnd == 0) {
272     //          cd.constructorCall.sourceEnd = cd.sourceEnd;
273     //          cd.constructorCall.sourceStart = cd.sourceStart;
274     //  }
275   }
276   // A P I
277
278   public void parse(FieldDeclaration field, TypeDeclaration type, CompilationUnitDeclaration unit, char[] initializationSource) {
279     //only parse the initializationSource of the given field
280
281     //convert bugs into parse error
282
283     initialize(false);
284     goForExpression();
285     nestedMethod[nestedType]++;
286
287     referenceContext = type;
288     compilationUnit = unit;
289     
290     scanner.setSource(initializationSource);
291     scanner.resetTo(0, initializationSource.length - 1);
292     try {
293       parse();
294     } catch (AbortCompilation ex) {
295       lastAct = ERROR_ACTION;
296     } finally {
297       nestedMethod[nestedType]--;
298     }
299
300     //  if (lastAct == ERROR_ACTION) {
301     //          return;
302     //  }
303     //
304     //  field.initialization = expressionStack[expressionPtr];
305     //  
306     //  // mark field with local type if one was found during parsing
307     //  if ((type.bits & ASTNode.HasLocalTypeMASK) != 0) {
308     //          field.bits |= ASTNode.HasLocalTypeMASK;
309     //  }       
310   }
311   // A P I
312
313   public void parse(Initializer ini, TypeDeclaration type, CompilationUnitDeclaration unit) {
314     //only parse the method body of md
315     //fill out method statements
316
317     //convert bugs into parse error
318
319     initialize(false);
320     goForInitializer();
321     nestedMethod[nestedType]++;
322
323     referenceContext = type;
324     compilationUnit = unit;
325     
326     scanner.resetTo(ini.sourceStart, ini.sourceEnd); // just on the beginning {
327     try {
328       parse();
329     } catch (AbortCompilation ex) {
330       lastAct = ERROR_ACTION;
331     } finally {
332       nestedMethod[nestedType]--;
333     }
334
335     //  if (lastAct == ERROR_ACTION) {
336     //          return;
337     //  }
338     //
339     //  ini.block = ((Initializer) astStack[astPtr]).block;
340     //  
341     //  // mark initializer with local type if one was found during parsing
342     //  if ((type.bits & ASTNode.HasLocalTypeMASK) != 0) {
343     //          ini.bits |= ASTNode.HasLocalTypeMASK;
344     //  }       
345   }
346   // A P I
347
348   public void parse(MethodDeclaration md, CompilationUnitDeclaration unit) {
349 //  TODO jsurfer - make the parse process work on methods ?
350     return; 
351     
352 //    //only parse the method body of md
353 //    //fill out method statements
354 //
355 //    //convert bugs into parse error
356 //
357 //    if (md.isAbstract())
358 //      return;
359 //    //        if (md.isNative())
360 //    //                return;
361 //    //        if ((md.modifiers & AccSemicolonBody) != 0)
362 //    //                return;
363 //
364 //    initialize(false);
365 //    goForMethodBody();
366 //    nestedMethod[nestedType]++;
367 //
368 //    referenceContext = md;
369 //    compilationUnit = unit;
370 //
371 //    scanner.resetTo(md.sourceEnd + 1, md.declarationSourceEnd);
372 //   
373 //    // reset the scanner to parser from { down to }
374 //    try {
375 //      parse();
376 //    } catch (AbortCompilation ex) {
377 //      lastAct = ERROR_ACTION;
378 //    } finally {
379 //      nestedMethod[nestedType]--;
380 //    }
381 //
382 //    //        if (lastAct == ERROR_ACTION) {
383 //    //                return;
384 //    //        }
385 //    //
386 //    //        //refill statements
387 //    //        md.explicitDeclarations = realBlockStack[realBlockPtr--];
388 //    //        int length;
389 //    //        if ((length = astLengthStack[astLengthPtr--]) != 0)
390 //    //                System.arraycopy(
391 //    //                        astStack, 
392 //    //                        (astPtr -= length) + 1, 
393 //    //                        md.statements = new Statement[length], 
394 //    //                        0, 
395 //    //                        length); 
396   }
397
398   // A P I
399
400   public CompilationUnitDeclaration parse(ICompilationUnit sourceUnit, CompilationResult compilationResult, int start, int end) {
401     // parses a compilation unit and manages error handling (even bugs....)
402
403     CompilationUnitDeclaration unit;
404     try {
405       /* automaton initialization */
406       initialize(false);
407       goForCompilationUnit();
408
409       /* scanner initialization */
410       scanner.setSource(sourceUnit, sourceUnit.getContents());
411       scanner.resetTo(start, end);
412       /* unit creation */
413       referenceContext =
414         compilationUnit = new CompilationUnitDeclaration(problemReporter, compilationResult, scanner.source.length);
415       
416       /* run automaton */
417       parse();
418     } catch (SyntaxError syntaxError) {
419       // 
420     } finally {
421       unit = compilationUnit;
422       compilationUnit = null; // reset parser
423     }
424     return unit;
425   }
426
427   public CompilationUnitDeclaration dietParse(ICompilationUnit sourceUnit, CompilationResult compilationResult) {
428         return dietParse(sourceUnit, compilationResult, false);
429   }
430   public CompilationUnitDeclaration dietParse(ICompilationUnit sourceUnit, CompilationResult compilationResult, boolean phpMode) {
431
432     CompilationUnitDeclaration parsedUnit;
433     boolean old = diet;
434     try {
435       diet = true;
436       parsedUnit = parse(sourceUnit, compilationResult, phpMode);
437     } finally {
438       diet = old;
439     }
440     return parsedUnit;
441   }
442   
443   public void getMethodBodies(CompilationUnitDeclaration unit) {
444         //fill the methods bodies in order for the code to be generated
445
446         if (unit == null) return;
447         
448         if (unit.ignoreMethodBodies) {
449                 unit.ignoreFurtherInvestigation = true;
450                 return;
451                 // if initial diet parse did not work, no need to dig into method bodies.
452         }
453
454         if ((unit.bits & ASTNode.HasAllMethodBodies) != 0)
455                 return; //work already done ...
456
457         //real parse of the method....
458         char[] contents = unit.compilationResult.compilationUnit.getContents();
459         this.scanner.setSource(contents);
460         
461         // save existing values to restore them at the end of the parsing process
462         // see bug 47079 for more details
463         int[] oldLineEnds = this.scanner.lineEnds;
464         int oldLinePtr = this.scanner.linePtr;
465
466         final int[] lineSeparatorPositions = unit.compilationResult.lineSeparatorPositions;
467         this.scanner.lineEnds = lineSeparatorPositions;
468         this.scanner.linePtr = lineSeparatorPositions.length - 1;
469
470 //      if (this.javadocParser != null && this.javadocParser.checkDocComment) {
471 //              this.javadocParser.scanner.setSource(contents);
472 //      }
473         if (unit.types != null) {
474                 for (int i = unit.types.size(); --i >= 0;)
475                         ((TypeDeclaration)unit.types.get(i)).parseMethod(this, unit);
476         }
477         
478         // tag unit has having read bodies
479         unit.bits |= ASTNode.HasAllMethodBodies;
480
481         // this is done to prevent any side effects on the compilation unit result
482         // line separator positions array.
483         this.scanner.lineEnds = oldLineEnds;
484         this.scanner.linePtr = oldLinePtr;
485 }
486 }