misc parser bugfixes; still very ugly state
[phpeclipse.git] / net.sourceforge.phpeclipse / src / net / sourceforge / phpdt / internal / compiler / parser / Parser.java
1 /**********************************************************************
2 Copyright (c) 2002 Klaus Hartlage - www.eclipseproject.de
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     Klaus Hartlage - www.eclipseproject.de
10 **********************************************************************/
11 package net.sourceforge.phpdt.internal.compiler.parser;
12
13 import java.util.ArrayList;
14
15 import net.sourceforge.phpdt.core.compiler.CharOperation;
16 import net.sourceforge.phpdt.core.compiler.ITerminalSymbols;
17 import net.sourceforge.phpdt.core.compiler.InvalidInputException;
18 import net.sourceforge.phpdt.internal.compiler.impl.ReferenceContext;
19 import net.sourceforge.phpdt.internal.compiler.lookup.TypeConstants;
20 import net.sourceforge.phpdt.internal.compiler.problem.ProblemReporter;
21 import net.sourceforge.phpeclipse.PHPeclipsePlugin;
22 import net.sourceforge.phpeclipse.internal.compiler.ast.AbstractMethodDeclaration;
23 import net.sourceforge.phpeclipse.internal.compiler.ast.AstNode;
24 import net.sourceforge.phpeclipse.internal.compiler.ast.CompilationUnitDeclaration;
25 import net.sourceforge.phpeclipse.internal.compiler.ast.MethodDeclaration;
26 import net.sourceforge.phpeclipse.internal.compiler.ast.SingleTypeReference;
27 import net.sourceforge.phpeclipse.internal.compiler.ast.TypeDeclaration;
28 import net.sourceforge.phpeclipse.phpeditor.PHPString;
29
30 import org.eclipse.core.resources.IFile;
31 import org.eclipse.core.runtime.CoreException;
32 import org.eclipse.jface.preference.IPreferenceStore;
33
34 import test.PHPParserSuperclass;
35
36 public class Parser extends PHPParserSuperclass implements ITerminalSymbols, ParserBasicInformation {
37   //internal data for the automat 
38   protected final static int StackIncrement = 255;
39   protected int stateStackTop;
40   protected int[] stack = new int[StackIncrement];
41   public int firstToken; // handle for multiple parsing goals
42   public int lastAct; //handle for multiple parsing goals
43   protected RecoveredElement currentElement;
44
45   public static boolean VERBOSE_RECOVERY = false;
46   protected boolean diet = false; //tells the scanner to jump over some parts of the code/expressions like method bodies
47
48   //scanner token
49   public Scanner scanner;
50
51   private ArrayList phpList;
52
53   private int currentPHPString;
54   private boolean phpEnd;
55
56   // private static HashMap keywordMap = null;
57   private String str;
58
59   // current character
60   //  char ch;
61   // current token
62   int token;
63
64   // row counter for syntax errors:
65   //int rowCount;
66   // column counter for syntax errors:
67   //int columnCount;
68
69   //int chIndx;
70   //
71   //    // current identifier
72   //    String identifier;
73
74   Long longNumber;
75   Double doubleNumber;
76
77   private String stringValue;
78
79   /** Contains the current expression. */
80   // private StringBuffer expression;
81
82   private boolean phpMode;
83
84   //    final static int TokenNameEOF = 0;
85   //    final static int TokenNameERROR = 1;
86   //    final static int TokenNameHTML = 2;
87   //
88   //    final static int TokenNameREMAINDER = 30;
89   //    final static int TokenNameNOT = 31;
90   //    final static int TokenNameDOT = 32;
91   //    final static int TokenNameXOR = 33;
92   //    final static int TokenNameDIVIDE = 34;
93   //    final static int TokenNameMULTIPLY = 35;
94   //    final static int TokenNameMINUS = 36;
95   //    final static int TokenNamePLUS = 37;
96   //    final static int TokenNameEQUAL_EQUAL = 38;
97   //    final static int TokenNameNOT_EQUAL = 39;
98   //    final static int TokenNameGREATER = 40;
99   //    final static int TokenNameGREATER_EQUAL = 41;
100   //    final static int TokenNameLESS = 42;
101   //    final static int TokenNameLESS_EQUAL = 43;
102   //    final static int TokenNameAND_AND = 44;
103   //    final static int TokenNameOR_OR = 45;
104   //    // final static int TokenNameHASH = 46; 
105   //    final static int TokenNameCOLON = 47;
106   //    final static int TokenNameDOT_EQUAL = 48;
107   //
108   //    final static int TokenNameEQUAL = 49;
109   //    final static int TokenNameMINUS_GREATER = 50; // ->
110   //    final static int TokenNameFOREACH = 51;
111   //    final static int TokenNameAND = 52;
112   //    //final static int TokenNameDOLLARLISTOPEN = 53;
113   //    final static int TokenNameTWIDDLE = 54;
114   //    final static int TokenNameTWIDDLE_EQUAL = 55;
115   //    final static int TokenNameREMAINDER_EQUAL = 56;
116   //    final static int TokenNameXOR_EQUAL = 57;
117   //    final static int TokenNameRIGHT_SHIFT_EQUAL = 58;
118   //    final static int TokenNameLEFT_SHIFT_EQUAL = 59;
119   //    final static int TokenNameAND_EQUAL = 60;
120   //    final static int TokenNameOR_EQUAL = 61;
121   //    final static int TokenNameQUESTION = 62;
122   //    final static int TokenNameCOLON_COLON = 63;
123   //    final static int TokenNameAT = 63;
124   //    // final static int TokenNameHEREDOC = 64;
125   //
126   //    final static int TokenNameDOLLAROPEN = 127;
127   //    final static int TokenNameLPAREN = 128;
128   //    final static int TokenNameRPAREN = 129;
129   //    final static int TokenNameLBRACE = 130;
130   //    final static int TokenNameRBRACE = 131;
131   //    final static int TokenNameLBRACKET = 132;
132   //    final static int TokenNameRBRACKET = 133;
133   //    final static int TokenNameCOMMA = 134;
134   //
135   //    final static int TokenNameStringLiteral = 136;
136   //    final static int TokenNameIdentifier = 138;
137   //    // final static int TokenNameDIGIT = 139;
138   //    final static int TokenNameSEMICOLON = 140;
139   //    // final static int TokenNameSLOT = 141;
140   //    // final static int TokenNameSLOTSEQUENCE = 142;
141   //    final static int TokenNameMINUS_MINUS = 144;
142   //    final static int TokenNamePLUS_PLUS = 145;
143   //    final static int TokenNamePLUS_EQUAL = 146;
144   //    final static int TokenNameDIVIDE_EQUAL = 147;
145   //    final static int TokenNameMINUS_EQUAL = 148;
146   //    final static int TokenNameMULTIPLY_EQUAL = 149;
147   //    final static int TokenNameVariable = 150;
148   //    final static int TokenNameIntegerLiteral = 151;
149   //    final static int TokenNameDoubleLiteral = 152;
150   //    final static int TokenNameStringInterpolated = 153;
151   //    final static int TokenNameStringConstant = 154;
152   //
153   //    final static int TokenNameLEFT_SHIFT = 155;
154   //    final static int TokenNameRIGHT_SHIFT = 156;
155   //    final static int TokenNameEQUAL_EQUAL_EQUAL = 157;
156   //    final static int TokenNameNOT_EQUAL_EQUAL = 158;
157   //    final static int TokenNameOR = 159;
158   //  final static int TokenNameAT = 153; // @
159
160   protected Parser() {
161     this.currentPHPString = 0;
162     //          PHPParserSuperclass.fileToParse = fileToParse;
163     this.phpList = null;
164     this.str = "";
165     this.token = TokenNameEOF;
166     //    this.chIndx = 0;
167     //    this.rowCount = 1;
168     //    this.columnCount = 0;
169     this.phpEnd = false;
170     //   getNextToken();
171
172     this.initializeScanner();
173   }
174
175   
176   public void setFileToParse(IFile fileToParse) {
177     this.currentPHPString = 0;
178     PHPParserSuperclass.fileToParse = fileToParse;
179     this.phpList = null;
180     this.str = "";
181     this.token = TokenNameEOF;
182     this.phpEnd = false;
183     this.initializeScanner();
184   }
185   /**
186    *  ClassDeclaration Constructor.
187    *
188    *@param  s
189    *@param  sess  Description of Parameter
190    *@see
191    */
192   public Parser(IFile fileToParse) {
193     //    if (keywordMap == null) {
194     //      keywordMap = new HashMap();
195     //      for (int i = 0; i < PHP_KEYWORS.length; i++) {
196     //        keywordMap.put(PHP_KEYWORS[i], new Integer(PHP_KEYWORD_TOKEN[i]));
197     //      }
198     //    }
199     this.currentPHPString = 0;
200     PHPParserSuperclass.fileToParse = fileToParse;
201     this.phpList = null;
202     this.str = "";
203     this.token = TokenNameEOF;
204     //    this.chIndx = 0;
205     //    this.rowCount = 1;
206     //    this.columnCount = 0;
207     this.phpEnd = false;
208     //   getNextToken();
209
210     this.initializeScanner();
211   }
212
213   public void initializeScanner() {
214     this.scanner = new Scanner(false, false, false, false);
215   }
216   /**
217    * Create marker for the parse error
218    */
219 //  private void setMarker(String message, int charStart, int charEnd, int errorLevel) throws CoreException {
220 //    setMarker(fileToParse, message, charStart, charEnd, errorLevel);
221 //  }
222
223   /**
224    * This method will throw the SyntaxError.
225    * It will add the good lines and columns to the Error
226    * @param error the error message
227    * @throws SyntaxError the error raised
228    */
229   private void throwSyntaxError(String error) {
230         int problemStartPosition = scanner.getCurrentTokenStartPosition();
231         int problemEndPosition = scanner.getCurrentTokenEndPosition();
232         reportSyntaxError(error,problemStartPosition,problemEndPosition);
233   }
234
235   /**
236    * This method will throw the SyntaxError.
237    * It will add the good lines and columns to the Error
238    * @param error the error message
239    * @throws SyntaxError the error raised
240    */
241 //  private void throwSyntaxError(String error, int startRow) {
242 //    throw new SyntaxError(startRow, 0, " ", error);
243 //  }
244
245   private void reportSyntaxError(String error, int problemStartPosition, int problemEndPosition) {
246     problemReporter.phpParsingError(new String[] { error }, problemStartPosition, problemEndPosition, referenceContext, compilationUnit.compilationResult);
247     throw new SyntaxError(1, 0, " ", error);
248   }
249   /**
250    *  Method Declaration.
251    *
252    *@see
253    */
254   //  private void getChar() {
255   //    if (str.length() > chIndx) {
256   //      ch = str.charAt(chIndx++);
257   //
258   //      return;
259   //    }
260   //
261   //    chIndx = str.length() + 1;
262   //    ch = ' ';
263   //    //  token = TokenNameEOF;
264   //    phpEnd = true;
265   //  }
266
267   /**
268    * gets the next token from input
269    */
270   private void getNextToken() throws CoreException {
271     try {
272       token = scanner.getNextToken();
273       if (Scanner.DEBUG) {
274         int currentEndPosition = scanner.getCurrentTokenEndPosition();
275         int currentStartPosition = scanner.getCurrentTokenStartPosition();
276
277         System.out.print(currentStartPosition + "," + currentEndPosition + ": ");
278         System.out.println(scanner.toStringAction(token));
279       }
280     } catch (InvalidInputException e) {
281       token = TokenNameERROR;
282     }
283     return;
284
285   }
286
287   /**
288    * Get a number.
289    * if it's a <code>double</code> the number will be stored in <code>doubleNumber</code> and the token will have the
290    * value {@link Parser#TokenNameDOUBLE_NUMBER}<br />
291    * if it's a <code>double</code> the number will be stored in <code>longNumber</code> and the token will have the
292    * value {@link Parser#TokenNameINT_NUMBER}
293    */
294   //  private void getNumber() {
295   //    StringBuffer inum = new StringBuffer();
296   //    char dFlag = ' ';
297   //    int numFormat = 10;
298   //
299   //    // save first digit
300   //    char firstCh = ch;
301   //    inum.append(ch);
302   //
303   //    getChar();
304   //    // determine number conversions:
305   //    if (firstCh == '0') {
306   //      switch (ch) {
307   //        case 'b' :
308   //          numFormat = 2;
309   //          getChar();
310   //          break;
311   //        case 'B' :
312   //          numFormat = 2;
313   //          getChar();
314   //          break;
315   //        case 'o' :
316   //          numFormat = 8;
317   //          getChar();
318   //          break;
319   //        case 'O' :
320   //          numFormat = 8;
321   //          getChar();
322   //          break;
323   //        case 'x' :
324   //          numFormat = 16;
325   //          getChar();
326   //          break;
327   //        case 'X' :
328   //          numFormat = 16;
329   //          getChar();
330   //          break;
331   //      }
332   //    }
333   //
334   //    if (numFormat == 16) {
335   //      while ((ch >= '0' && ch <= '9')
336   //        || (ch >= 'a' && ch <= 'f')
337   //        || (ch >= 'A' && ch <= 'F')) {
338   //        inum.append(ch);
339   //        getChar();
340   //      }
341   //    } else {
342   //      while ((ch >= '0' && ch <= '9')
343   //        || (ch == '.')
344   //        || (ch == 'E')
345   //        || (ch == 'e')) {
346   //        if ((ch == '.') || (ch == 'E') || (ch == 'e')) {
347   //          if (ch == '.' && dFlag != ' ') {
348   //            break;
349   //          }
350   //          if ((dFlag == 'E') || (dFlag == 'e')) {
351   //            break;
352   //          }
353   //          dFlag = ch;
354   //          inum.append(ch);
355   //          getChar();
356   //          if ((ch == '-') || (ch == '+')) {
357   //            inum.append(ch);
358   //            getChar();
359   //          }
360   //        } else {
361   //          inum.append(ch);
362   //          getChar();
363   //        }
364   //      }
365   //    }
366   //    chIndx--;
367   //
368   //    try {
369   //      if (dFlag != ' ') {
370   //        doubleNumber = new Double(inum.toString());
371   //        token = TokenNameDoubleLiteral;
372   //        return;
373   //      } else {
374   //        longNumber = Long.valueOf(inum.toString(), numFormat);
375   //        token = TokenNameIntegerLiteral;
376   //        return;
377   //      }
378   //
379   //    } catch (Throwable e) {
380   //      throwSyntaxError("Number format error: " + inum.toString());
381   //    }
382   //  }
383   //
384   //  /**
385   //   * Get a String.
386   //   * @param openChar the opening char ('\'', '"', '`')
387   //   * @param typeString the type of string {@link #TokenNameSTRING_CONSTANT},{@link #TokenNameINTERPOLATED_STRING}
388   //   * @param errorMsg the error message in case of parse error in the string
389   //   */
390   //  private void getString(
391   //    final char openChar,
392   //    final int typeString,
393   //    final String errorMsg) {
394   //    StringBuffer sBuffer = new StringBuffer();
395   //    boolean openString = true;
396   //    int startRow = rowCount;
397   //    while (str.length() > chIndx) {
398   //      ch = str.charAt(chIndx++);
399   //      if (ch == '\\') {
400   //        sBuffer.append(ch);
401   //        if (str.length() > chIndx) {
402   //          ch = str.charAt(chIndx++);
403   //          sBuffer.append(ch);
404   //        }
405   //      } else if (ch == openChar) {
406   //        openString = false;
407   //        break;
408   //      } else if (ch == '\n') {
409   //        rowCount++;
410   //        columnCount = chIndx;
411   //      } else {
412   //        sBuffer.append(ch);
413   //      }
414   //    }
415   //    if (openString) {
416   //      if (typeString == TokenNameStringConstant) {
417   //        throwSyntaxError(errorMsg, startRow);
418   //      } else {
419   //        throwSyntaxError(errorMsg);
420   //      }
421   //    }
422   //    token = typeString;
423   //    stringValue = sBuffer.toString();
424   //  }
425
426   //    public void htmlParserTester(String input) {
427   //            int lineNumber = 1;
428   //            int startLineNumber = 1;
429   //            int startIndex = 0;
430   //            char ch;
431   //            char ch2;
432   //            boolean phpMode = false;
433   //            boolean phpFound = false;
434   //
435   //            phpList = new ArrayList();
436   //            currentPHPString = 0;
437   //
438   //            try {
439   //                    int i = 0;
440   //                    while (i < input.length()) {
441   //                            ch = input.charAt(i++);
442   //                            if (ch == '\n') {
443   //                                    lineNumber++;
444   //                            }
445   //                            if ((!phpMode) && ch == '<') {
446   //                                    ch2 = input.charAt(i++);
447   //                                    if (ch2 == '?') {
448   //                                            ch2 = input.charAt(i++);
449   //                                            if (Character.isWhitespace(ch2)) {
450   //                                                    // php start
451   //                                                    phpMode = true;
452   //                                                    phpFound = true;
453   //                                                    startIndex = i;
454   //                                                    startLineNumber = lineNumber;
455   //                                                    continue;
456   //                                            } else if (ch2 == 'p') {
457   //                                                    ch2 = input.charAt(i++);
458   //                                                    if (ch2 == 'h') {
459   //                                                            ch2 = input.charAt(i++);
460   //                                                            if (ch2 == 'p') {
461   //                                                                    phpMode = true;
462   //                                                                    phpFound = true;
463   //                                                                    startIndex = i;
464   //                                                                    startLineNumber = lineNumber;
465   //                                                                    continue;
466   //                                                            }
467   //                                                            i--;
468   //                                                    }
469   //                                                    i--;
470   //                                            } else if (ch2 == 'P') {
471   //                                                    ch2 = input.charAt(i++);
472   //                                                    if (ch2 == 'H') {
473   //                                                            ch2 = input.charAt(i++);
474   //                                                            if (ch2 == 'P') {
475   //                                                                    phpMode = true;
476   //                                                                    phpFound = true;
477   //                                                                    startIndex = i;
478   //                                                                    startLineNumber = lineNumber;
479   //                                                                    continue;
480   //                                                            }
481   //                                                            i--;
482   //                                                    }
483   //                                                    i--;
484   //                                            }
485   //                                            i--;
486   //                                    }
487   //                                    i--;
488   //                            }
489   //
490   //                            if (phpMode) {
491   //                                    if (ch == '/' && i < input.length()) {
492   //                                            ch2 = input.charAt(i++);
493   //                                            if (ch2 == '/') {
494   //                                                    while (i < input.length()) {
495   //                                                            ch = input.charAt(i++);
496   //                                                            if (ch == '?' && i < input.length()) {
497   //                                                                    ch2 = input.charAt(i++);
498   //                                                                    if (ch2 == '>') {
499   //                                                                            // php end
500   //                                                                            phpMode = false;
501   //                                                                            phpList.add(
502   //                                                                                    new PHPString(
503   //                                                                                            input.substring(
504   //                                                                                                    startIndex,
505   //                                                                                                    i - 2),
506   //                                                                                            startLineNumber));
507   //                                                                            continue;
508   //                                                                    }
509   //                                                                    i--;
510   //                                                            } else if (ch == '\n') {
511   //                                                                    lineNumber++;
512   //                                                                    break;
513   //                                                            }
514   //                                                    }
515   //                                                    continue;
516   //                                            } else if (ch2 == '*') {
517   //                                                    // multi-line comment
518   //                                                    while (i < input.length()) {
519   //                                                            ch = input.charAt(i++);
520   //                                                            if (ch == '\n') {
521   //                                                                    lineNumber++;
522   //                                                            } else if (ch == '*' && i < input.length()) {
523   //                                                                    ch2 = input.charAt(i++);
524   //                                                                    if (ch2 == '/') {
525   //                                                                            break;
526   //                                                                    }
527   //                                                                    i--;
528   //                                                            }
529   //                                                    }
530   //                                                    continue;
531   //                                            } else {
532   //                                                    i--;
533   //                                            }
534   //                                    } else if (ch == '#') {
535   //                                            while (i < input.length()) {
536   //                                                    ch = input.charAt(i++);
537   //                                                    if (ch == '?' && i < input.length()) {
538   //                                                            ch2 = input.charAt(i++);
539   //                                                            if (ch2 == '>') {
540   //                                                                    // php end
541   //                                                                    phpMode = false;
542   //                                                                    phpList.add(
543   //                                                                            new PHPString(
544   //                                                                                    input.substring(startIndex, i - 2),
545   //                                                                                    startLineNumber));
546   //                                                                    continue;
547   //                                                            }
548   //                                                            i--;
549   //                                                    } else if (ch == '\n') {
550   //                                                            lineNumber++;
551   //                                                            break;
552   //                                                    }
553   //                                            }
554   //                                            continue;
555   //                                    } else if (ch == '"') {
556   //                                            ch = ' ';
557   //                                            while (i < input.length()) {
558   //                                                    ch = input.charAt(i++);
559   //                                                    if (ch == '\n') {
560   //                                                            lineNumber++;
561   //                                                    } else if (
562   //                                                            ch == '\\' && i < input.length()) { // escape
563   //                                                            i++;
564   //                                                    } else if (ch == '"') {
565   //                                                            break;
566   //                                                    }
567   //                                            }
568   //                                            continue;
569   //                                    } else if (ch == '\'') {
570   //                                            ch = ' ';
571   //                                            while (i < input.length()) {
572   //                                                    ch = input.charAt(i++);
573   //                                                    if (ch == '\n') {
574   //                                                            lineNumber++;
575   //                                                    } else if (
576   //                                                            ch == '\\' && i < input.length()) { // escape
577   //                                                            i++;
578   //                                                    } else if (ch == '\'') {
579   //                                                            break;
580   //                                                    }
581   //                                            }
582   //                                            continue;
583   //                                    }
584   //
585   //                                    if (ch == '?' && i < input.length()) {
586   //                                            ch2 = input.charAt(i++);
587   //                                            if (ch2 == '>') {
588   //                                                    // php end
589   //                                                    phpMode = false;
590   //                                                    phpList.add(
591   //                                                            new PHPString(
592   //                                                                    input.substring(startIndex, i - 2),
593   //                                                                    startLineNumber));
594   //                                                    continue;
595   //                                            }
596   //                                            i--;
597   //                                    }
598   //                            }
599   //                    }
600   //
601   //                    if (!phpFound) {
602   //                            setMarker(
603   //                                    "No PHP source code found.",
604   //                                    lineNumber,
605   //                                    PHPParser.INFO);
606   //                    } else {
607   //                            if (phpMode) {
608   //                                    setMarker(
609   //                                            "Open PHP tag at end of file.",
610   //                                            lineNumber,
611   //                                            PHPParser.INFO);
612   //                                    phpList.add(
613   //                                            new PHPString(
614   //                                                    input.substring(startIndex, i - 2),
615   //                                                    startLineNumber));
616   //                            }
617   //                            //        for (int j=0;j<phpList.size();j++) {
618   //                            //          String temp = ((PHPString)phpList.get(j)).getPHPString();
619   //                            //          int startIndx = temp.length()-10;
620   //                            //          if (startIndx<0) {
621   //                            //            startIndx = 0;
622   //                            //          }
623   //                            //          System.out.println(temp.substring(startIndx)+"?>");
624   //                            //        }
625   //                            phpParserTester(null, 1);
626   //                            //        PHPString temp;
627   //                            //        for(int j=0;j<phpList.size();j++) {
628   //                            //          temp = (PHPString) phpList.get(j);
629   //                            //          parser.start(temp.getPHPString(), temp.getLineNumber());
630   //                            //        }
631   //                    }
632   //            } catch (CoreException e) {
633   //            }
634   //    }
635
636   public void phpParserTester(String s, int rowCount) throws CoreException {
637     this.str = s;
638     if (s == null) {
639       if (phpList.size() != 0) {
640         this.str = ((PHPString) phpList.get(currentPHPString++)).getPHPString();
641       }
642     }
643     this.token = TokenNameEOF;
644     //    this.chIndx = 0;
645     //    this.rowCount = rowCount;
646     //    this.columnCount = 0;
647     this.phpEnd = false;
648     this.phpMode = true;
649     scanner.setSource(s.toCharArray());
650     scanner.setPHPMode(true);
651     getNextToken();
652     do {
653       try {
654         if (token != TokenNameEOF && token != TokenNameERROR) {
655           statementList();
656         }
657         if (token != TokenNameEOF) {
658           if (token == TokenNameERROR) {
659             throwSyntaxError("Scanner error (Found unknown token: " + scanner.toStringAction(token) + ")");
660           }
661           if (token == TokenNameRPAREN) {
662             throwSyntaxError("Too many closing ')'; end-of-file not reached.");
663           }
664           if (token == TokenNameRBRACE) {
665             throwSyntaxError("Too many closing '}'; end-of-file not reached.");
666           }
667           if (token == TokenNameRBRACKET) {
668             throwSyntaxError("Too many closing ']'; end-of-file not reached.");
669           }
670
671           if (token == TokenNameLPAREN) {
672             throwSyntaxError("Read character '('; end-of-file not reached.");
673           }
674           if (token == TokenNameLBRACE) {
675             throwSyntaxError("Read character '{';  end-of-file not reached.");
676           }
677           if (token == TokenNameLBRACKET) {
678             throwSyntaxError("Read character '[';  end-of-file not reached.");
679           }
680
681           throwSyntaxError("End-of-file not reached.");
682         }
683         return;
684       } catch (SyntaxError err) {
685         if (s != null) {
686           throw err;
687         } else {
688           //   setMarker(err.getMessage(), err.getLine(), ERROR);
689 //          setMarker(err.getMessage(), scanner.getCurrentTokenStartPosition(), scanner.getCurrentTokenEndPosition(), ERROR);
690         }
691         // if an error occured,
692         // try to find keywords 'class' or 'function'
693         // to parse the rest of the string
694         while (token != TokenNameEOF && token != TokenNameERROR) {
695           if (token == TokenNameclass || token == TokenNamefunction) {
696             break;
697           }
698           getNextToken();
699         }
700         if (token == TokenNameEOF || token == TokenNameERROR) {
701           return;
702         }
703       }
704     }
705     while (true);
706   }
707   public void init(String s) {
708     this.str = s;
709     this.token = TokenNameEOF;
710     //    this.chIndx = 0;
711     //    this.rowCount = 1;
712     //    this.columnCount = 0;
713     this.phpEnd = false;
714     this.phpMode = false;
715     /* scanner initialization */
716     scanner.setSource(s.toCharArray());
717     scanner.setPHPMode(false);
718   }
719
720   protected void initialize(boolean phpMode) {
721     compilationUnit = null;
722     referenceContext = null;
723     this.str = "";
724     this.token = TokenNameEOF;
725     //    this.chIndx = 0;
726     //    this.rowCount = 1;
727     //    this.columnCount = 0;
728     this.phpEnd = false;
729     this.phpMode = phpMode;
730     scanner.setPHPMode(phpMode);
731   }
732   /**
733    * Parses a string with php tags
734    * i.e. '&lt;body&gt; &lt;?php phpinfo() ?&gt; &lt;/body&gt;'
735    */
736   public void parse(String s) throws CoreException {
737     init(s);
738     parse();
739   }
740
741   /**
742          * Parses a string with php tags
743          * i.e. '&lt;body&gt; &lt;?php phpinfo() ?&gt; &lt;/body&gt;'
744          */
745   protected void parse() throws CoreException {
746     getNextToken();
747     do {
748       try {
749         if (token != TokenNameEOF && token != TokenNameERROR) {
750           statementList();
751         }
752         if (token != TokenNameEOF) {
753           if (token == TokenNameERROR) {
754             throwSyntaxError("Scanner error (Found unknown token: " + scanner.toStringAction(token) + ")");
755           }
756           if (token == TokenNameRPAREN) {
757             throwSyntaxError("Too many closing ')'; end-of-file not reached.");
758           }
759           if (token == TokenNameRBRACE) {
760             throwSyntaxError("Too many closing '}'; end-of-file not reached.");
761           }
762           if (token == TokenNameRBRACKET) {
763             throwSyntaxError("Too many closing ']'; end-of-file not reached.");
764           }
765
766           if (token == TokenNameLPAREN) {
767             throwSyntaxError("Read character '('; end-of-file not reached.");
768           }
769           if (token == TokenNameLBRACE) {
770             throwSyntaxError("Read character '{';  end-of-file not reached.");
771           }
772           if (token == TokenNameLBRACKET) {
773             throwSyntaxError("Read character '[';  end-of-file not reached.");
774           }
775
776           throwSyntaxError("End-of-file not reached.");
777         }
778         return;
779       } catch (SyntaxError sytaxErr1) {
780         // setMarker(sytaxErr1.getMessage(), sytaxErr1.getLine(), ERROR);
781 //        setMarker(sytaxErr1.getMessage(), scanner.getCurrentTokenStartPosition(), scanner.getCurrentTokenEndPosition(), ERROR);
782         try {
783           // if an error occured,
784           // try to find keywords 'class' or 'function'
785           // to parse the rest of the string
786           while (token != TokenNameEOF && token != TokenNameERROR) {
787             if (token == TokenNameclass || token == TokenNamefunction) {
788               break;
789             }
790             getNextToken();
791           }
792           if (token == TokenNameEOF || token == TokenNameERROR) {
793             return;
794           }
795         } catch (SyntaxError sytaxErr2) {
796           //    setMarker(sytaxErr2.getMessage(), sytaxErr2.getLine(), ERROR);
797 //          setMarker(sytaxErr2.getMessage(), scanner.getCurrentTokenStartPosition(), scanner.getCurrentTokenEndPosition(), ERROR);
798           return;
799         }
800       }
801     }
802     while (true);
803   }
804
805   public PHPOutlineInfo parseInfo(Object parent, String s) {
806     PHPOutlineInfo outlineInfo = new PHPOutlineInfo(parent);
807     //    Stack stack = new Stack();
808     //    stack.push(outlineInfo.getDeclarations());
809
810     this.str = s;
811     this.token = TokenNameEOF;
812     //    this.chIndx = 0;
813     //    this.rowCount = 1;
814     //    this.columnCount = 0;
815     this.phpEnd = false;
816     this.phpMode = false;
817     scanner.setSource(s.toCharArray());
818     scanner.setPHPMode(false);
819
820     try {
821       getNextToken();
822       parseDeclarations(outlineInfo, outlineInfo.getDeclarations(), false);
823     } catch (CoreException e) {
824     }
825     return outlineInfo;
826   }
827
828   private boolean isVariable() {
829     return token == TokenNameVariable || token == TokenNamethis;
830   }
831
832   private void parseDeclarations(PHPOutlineInfo outlineInfo, OutlineableWithChildren current, boolean goBack) {
833     char[] ident;
834     //   PHPClassDeclaration current = (PHPClassDeclaration) stack.peek();
835     PHPSegmentWithChildren temp;
836     int counter = 0;
837
838     IPreferenceStore store = PHPeclipsePlugin.getDefault().getPreferenceStore();
839     try {
840       while (token != TokenNameEOF && token != TokenNameERROR) {
841         if (token == TokenNameVariable) {
842           ident = scanner.getCurrentIdentifierSource();
843           outlineInfo.addVariable(new String(ident));
844           getNextToken();
845         } else if (token == TokenNamevar) {
846           getNextToken();
847           if (token == TokenNameVariable && store.getBoolean(PHPeclipsePlugin.PHP_OUTLINE_VAR)) {
848             ident = scanner.getCurrentIdentifierSource();
849             //substring(1) added because PHPVarDeclaration doesn't need the $ anymore
850             String variableName = new String(ident).substring(1);
851             outlineInfo.addVariable(variableName);
852             getNextToken();
853             if (token != TokenNameSEMICOLON) {
854
855               getNextToken();
856               ident = scanner.getCurrentTokenSource();
857               if (token > TokenNameKEYWORD) {
858                 current.add(new PHPVarDeclaration(current, variableName,
859                 //                      chIndx - ident.length,
860                 scanner.getCurrentTokenStartPosition(), new String(ident)));
861               } else {
862                 switch (token) {
863                   case TokenNameVariable :
864                   case TokenNamethis :
865                     current.add(new PHPVarDeclaration(current, variableName,
866                     //                      chIndx - ident.length,
867                     scanner.getCurrentTokenStartPosition(), new String(ident)));
868                     break;
869                   case TokenNameIdentifier :
870                     current.add(new PHPVarDeclaration(current, variableName,
871                     //                    chIndx - ident.length,
872                     scanner.getCurrentTokenStartPosition(), new String(ident)));
873                     break;
874                   case TokenNameDoubleLiteral :
875                     current.add(new PHPVarDeclaration(current, variableName + doubleNumber,
876                     //   chIndx - ident.length,
877                     scanner.getCurrentTokenStartPosition(), new String(ident)));
878                     break;
879                   case TokenNameIntegerLiteral :
880                     current.add(new PHPVarDeclaration(current, variableName,
881                     //                 chIndx - ident.length,
882                     scanner.getCurrentTokenStartPosition(), new String(ident)));
883                     break;
884                   case TokenNameStringInterpolated :
885                   case TokenNameStringLiteral :
886                     current.add(new PHPVarDeclaration(current, variableName,
887                     //              chIndx - ident.length,
888                     scanner.getCurrentTokenStartPosition(), new String(ident)));
889                     break;
890                   case TokenNameStringConstant :
891                     current.add(new PHPVarDeclaration(current, variableName,
892                     //   chIndx - ident.length,
893                     scanner.getCurrentTokenStartPosition(), new String(ident)));
894                     break;
895                   default :
896                     current.add(new PHPVarDeclaration(current, variableName,
897                     //               chIndx - ident.length
898                     scanner.getCurrentTokenStartPosition()));
899                     break;
900                 }
901               }
902
903             } else {
904               ident = scanner.getCurrentIdentifierSource();
905
906               current.add(new PHPVarDeclaration(current, variableName,
907               //          chIndx - ident.length
908               scanner.getCurrentTokenStartPosition()));
909             }
910           }
911         } else if (token == TokenNamefunction) {
912           getNextToken();
913           if (token == TokenNameAND) {
914             getNextToken();
915           }
916           if (token == TokenNameIdentifier && store.getBoolean(PHPeclipsePlugin.PHP_OUTLINE_FUNC)) {
917             ident = scanner.getCurrentIdentifierSource();
918             outlineInfo.addVariable(new String(ident));
919             temp = new PHPFunctionDeclaration(current, new String(ident),
920               // chIndx - ident.length
921   scanner.getCurrentTokenStartPosition());
922             current.add(temp);
923             getNextToken();
924             parseDeclarations(outlineInfo, temp, true);
925           }
926         } else if (token == TokenNameclass) {
927           getNextToken();
928           if (token == TokenNameIdentifier && store.getBoolean(PHPeclipsePlugin.PHP_OUTLINE_CLASS)) {
929             ident = scanner.getCurrentIdentifierSource();
930             outlineInfo.addVariable(new String(ident));
931             temp = new PHPClassDeclaration(current, new String(ident),
932               //      chIndx - ident.len
933   scanner.getCurrentTokenStartPosition());
934             current.add(temp);
935             //        stack.push(temp);
936             getNextToken();
937
938             //skip tokens for classname, extends and others until we have the opening '{'
939             while (token != TokenNameLBRACE && token != TokenNameEOF && token != TokenNameERROR) {
940               getNextToken();
941             }
942             parseDeclarations(outlineInfo, temp, true);
943             //        stack.pop();
944           }
945         } else if ((token == TokenNameLBRACE) || (token == TokenNameDOLLAR_LBRACE)) {
946           getNextToken();
947           counter++;
948         } else if (token == TokenNameRBRACE) {
949           getNextToken();
950           --counter;
951           if (counter == 0 && goBack) {
952             return;
953           }
954         } else if (token == TokenNamerequire || token == TokenNamerequire_once || token == TokenNameinclude || token == TokenNameinclude_once) {
955           ident = scanner.getCurrentTokenSource();
956
957           getNextToken();
958           int startPosition = scanner.getCurrentTokenStartPosition();
959           expression();
960           char[] expr = scanner.getCurrentTokenSource(startPosition);
961           outlineInfo.addVariable(new String(ident));
962           current.add(new PHPReqIncDeclaration(current, new String(ident),
963           //    chIndx - ident.length,
964           startPosition, new String(expr)));
965           getNextToken();
966         } else {
967           getNextToken();
968         }
969       }
970     } catch (CoreException e) {
971     } catch (SyntaxError sytaxErr) {
972 //      try {
973 //        //  setMarker(sytaxErr.getMessage(), sytaxErr.getLine(), ERROR);
974 //        setMarker(sytaxErr.getMessage(), scanner.getCurrentTokenStartPosition(), scanner.getCurrentTokenEndPosition(), ERROR);
975 //      } catch (CoreException e) {
976 //      }
977     }
978   }
979
980   private void statementList() throws CoreException {
981     do {
982       statement(TokenNameEOF);
983       if ((token == TokenNameRBRACE)
984         || (token == TokenNamecase)
985         || (token == TokenNamedefault)
986         || (token == TokenNameelse)
987         || (token == TokenNameelseif)
988         || (token == TokenNameendif)
989         || (token == TokenNameendfor)
990         || (token == TokenNameendforeach)
991         || (token == TokenNameendwhile)
992         || (token == TokenNameendswitch)
993         || (token == TokenNameEOF)
994         || (token == TokenNameERROR)) {
995         return;
996       }
997     } while (true);
998   }
999
1000   private void functionBody(MethodDeclaration methodDecl) throws CoreException {
1001     // '{' [statement-list] '}'
1002     if (token == TokenNameLBRACE) {
1003       getNextToken();
1004     } else {
1005       throwSyntaxError("'{' expected in compound-statement.");
1006     }
1007     if (token != TokenNameRBRACE) {
1008       statementList();
1009     }
1010     if (token == TokenNameRBRACE) {
1011       methodDecl.declarationSourceEnd = scanner.getCurrentTokenEndPosition();
1012       getNextToken();
1013     } else {
1014       throwSyntaxError("'}' expected in compound-statement.");
1015     }
1016   }
1017
1018   private void statement(int previousToken) throws CoreException {
1019     //   if (token > TokenNameKEYWORD && token != TokenNamelist && token != TokenNamenew) {
1020     //  char[] ident = scanner.getCurrentIdentifierSource();
1021     //  String keyword = new String(ident);
1022         if (token == TokenNameAT) {
1023                 getNextToken();
1024                 if (token != TokenNamerequire
1025                                 && token != TokenNamerequire_once
1026                                 && token != TokenNameinclude
1027                                 && token != TokenNameinclude_once
1028                                 && token != TokenNameIdentifier
1029                                 && token != TokenNameVariable
1030                                 && token != TokenNamethis
1031                                 && token != TokenNameStringInterpolated) {
1032                         throwSyntaxError("identifier expected after '@'.");
1033                 }
1034         }
1035     if (token == TokenNameinclude || token == TokenNameinclude_once) {
1036       getNextToken();
1037       if (token == TokenNameLPAREN) {
1038         expression();
1039         if (token == TokenNameSEMICOLON) {
1040           getNextToken();
1041         } else {
1042           if (previousToken != TokenNameAT && token != TokenNameStopPHP) {
1043             throwSyntaxError("';' expected after 'include' or 'include_once'.");
1044           }
1045           //        getNextToken();
1046         }
1047       } else {
1048         concatenationExpression();
1049       }
1050
1051       return;
1052     } else if (token == TokenNamerequire || token == TokenNamerequire_once) {
1053       getNextToken();
1054       //constant();
1055       if (token == TokenNameLPAREN) {
1056         expression();
1057         if (token == TokenNameSEMICOLON) {
1058           getNextToken();
1059         } else {
1060           if (previousToken != TokenNameAT && token != TokenNameStopPHP) {
1061             throwSyntaxError("';' expected after 'require' or 'require_once'.");
1062           }
1063           //        getNextToken();
1064         }
1065       } else {
1066         concatenationExpression();
1067       }
1068       return;
1069     } else if (token == TokenNameif) {
1070       getNextToken();
1071       if (token == TokenNameLPAREN) {
1072         getNextToken();
1073       } else {
1074         throwSyntaxError("'(' expected after 'if' keyword.");
1075       }
1076       expression();
1077       if (token == TokenNameRPAREN) {
1078         getNextToken();
1079       } else {
1080         throwSyntaxError("')' expected after 'if' condition.");
1081       }
1082       ifStatement();
1083       return;
1084
1085     } else if (token == TokenNameswitch) {
1086       getNextToken();
1087       if (token == TokenNameLPAREN) {
1088         getNextToken();
1089       } else {
1090         throwSyntaxError("'(' expected after 'switch' keyword.");
1091       }
1092       expression();
1093       if (token == TokenNameRPAREN) {
1094         getNextToken();
1095       } else {
1096         throwSyntaxError("')' expected after 'switch' condition.");
1097       }
1098       switchStatement();
1099       return;
1100     } else if (token == TokenNamefor) {
1101       getNextToken();
1102       if (token == TokenNameLPAREN) {
1103         getNextToken();
1104       } else {
1105         throwSyntaxError("'(' expected after 'for' keyword.");
1106       }
1107       if (token == TokenNameSEMICOLON) {
1108         getNextToken();
1109       } else {
1110         expressionList();
1111         if (token == TokenNameSEMICOLON) {
1112           getNextToken();
1113         } else {
1114           throwSyntaxError("';' expected after 'for'.");
1115         }
1116       }
1117       if (token == TokenNameSEMICOLON) {
1118         getNextToken();
1119       } else {
1120         expressionList();
1121         if (token == TokenNameSEMICOLON) {
1122           getNextToken();
1123         } else {
1124           throwSyntaxError("';' expected after 'for'.");
1125         }
1126       }
1127       if (token == TokenNameRPAREN) {
1128         getNextToken();
1129       } else {
1130         expressionList();
1131         if (token == TokenNameRPAREN) {
1132           getNextToken();
1133         } else {
1134           throwSyntaxError("')' expected after 'for'.");
1135         }
1136       }
1137       forStatement();
1138       return;
1139     } else if (token == TokenNamewhile) {
1140       getNextToken();
1141       if (token == TokenNameLPAREN) {
1142         getNextToken();
1143       } else {
1144         throwSyntaxError("'(' expected after 'while' keyword.");
1145       }
1146       expression();
1147       if (token == TokenNameRPAREN) {
1148         getNextToken();
1149       } else {
1150         throwSyntaxError("')' expected after 'while' condition.");
1151       }
1152       whileStatement();
1153       return;
1154     } else if (token == TokenNamedo) {
1155       getNextToken();
1156       if (token == TokenNameLBRACE) {
1157         getNextToken();
1158       } else {
1159         throwSyntaxError("'{' expected after 'do' keyword.");
1160       }
1161       if (token != TokenNameRBRACE) {
1162         statementList();
1163       }
1164       if (token == TokenNameRBRACE) {
1165         getNextToken();
1166       } else {
1167         throwSyntaxError("'}' expected after 'do' keyword.");
1168       }
1169       if (token == TokenNamewhile) {
1170         getNextToken();
1171         if (token == TokenNameLPAREN) {
1172           getNextToken();
1173         } else {
1174           throwSyntaxError("'(' expected after 'while' keyword.");
1175         }
1176         expression();
1177         if (token == TokenNameRPAREN) {
1178           getNextToken();
1179         } else {
1180           throwSyntaxError("')' expected after 'while' condition.");
1181         }
1182       } else {
1183         throwSyntaxError("'while' expected after 'do' keyword.");
1184       }
1185       if (token == TokenNameSEMICOLON) {
1186         getNextToken();
1187       } else {
1188         if (token != TokenNameStopPHP) {
1189           throwSyntaxError("';' expected after do-while statement.");
1190         }
1191         getNextToken();
1192       }
1193       return;
1194     } else if (token == TokenNameforeach) {
1195       getNextToken();
1196       if (token == TokenNameLPAREN) {
1197         getNextToken();
1198       } else {
1199         throwSyntaxError("'(' expected after 'foreach' keyword.");
1200       }
1201       expression();
1202       if (token == TokenNameas) {
1203         getNextToken();
1204       } else {
1205         throwSyntaxError("'as' expected after 'foreach' exxpression.");
1206       }
1207       variable();
1208       if (token == TokenNameEQUAL_GREATER) {
1209         getNextToken();
1210         variable();
1211       }
1212       if (token == TokenNameRPAREN) {
1213         getNextToken();
1214       } else {
1215         throwSyntaxError("')' expected after 'foreach' expression.");
1216       }
1217       foreachStatement();
1218       return;
1219
1220     } else if (token == TokenNamecontinue || token == TokenNamebreak || token == TokenNamereturn) {
1221       getNextToken();
1222       if (token != TokenNameSEMICOLON) {
1223         expression();
1224       }
1225       if (token == TokenNameSEMICOLON) {
1226         getNextToken();
1227       } else {
1228         if (token != TokenNameStopPHP) {
1229           throwSyntaxError("';' expected after 'continue', 'break' or 'return'.");
1230         }
1231         getNextToken();
1232       }
1233       return;
1234
1235     } else if (token == TokenNameecho) {
1236       getNextToken();
1237       expressionList();
1238       if (token == TokenNameSEMICOLON) {
1239         getNextToken();
1240       } else {
1241         if (token != TokenNameStopPHP) {
1242           throwSyntaxError("';' expected after 'echo' statement.");
1243         }
1244         getNextToken();
1245       }
1246       return;
1247       //    } else if (token == TokenNameprint) {
1248       //      getNextToken();
1249       //      expression();
1250       //      if (token == TokenNameSEMICOLON) {
1251       //        getNextToken();
1252       //      } else {
1253       //        if (token != TokenNameStopPHP) {
1254       //          throwSyntaxError("';' expected after 'print' statement.");
1255       //        }
1256       //        getNextToken();
1257       //      }
1258       //      return;
1259
1260     } else if (token == TokenNameglobal || token == TokenNamestatic) {
1261       getNextToken();
1262       variableList();
1263       if (token == TokenNameSEMICOLON) {
1264         getNextToken();
1265       } else {
1266         if (token != TokenNameStopPHP) {
1267           throwSyntaxError("';' expected after 'global' or 'static' statement.");
1268         }
1269         getNextToken();
1270       }
1271       return;
1272
1273       //      } else if (token == TokenNameunset) {
1274       //        getNextToken();
1275       //        if (token == TokenNameARGOPEN) {
1276       //          getNextToken();
1277       //        } else {
1278       //          throwSyntaxError("'(' expected after 'unset' keyword.");
1279       //        }
1280       //        variableList();
1281       //        if (token == TokenNameARGCLOSE) {
1282       //          getNextToken();
1283       //        } else {
1284       //          throwSyntaxError("')' expected after 'unset' statement.");
1285       //        }
1286       //        if (token == TokenNameSEMICOLON) {
1287       //          getNextToken();
1288       //        } else {
1289       //          if (token != TokenNameStopPHP) {
1290       //            throwSyntaxError("';' expected after 'unset' statement.");
1291       //          }
1292       //          getNextToken();
1293       //        }
1294       //        return;
1295
1296       //      } else if (token == TokenNameexit || token == TokenNamedie) {
1297       //        getNextToken();
1298       //        if (token != TokenNameSEMICOLON) {
1299       //          exitStatus();
1300       //        }
1301       //        if (token == TokenNameSEMICOLON) {
1302       //          getNextToken();
1303       //        } else {
1304       //          if (token != TokenNameStopPHP) {
1305       //            throwSyntaxError("';' expected after 'exit' or 'die' statement.");
1306       //          }
1307       //          getNextToken();
1308       //        }
1309       //        return;
1310
1311     } else if (token == TokenNamedefine) {
1312       getNextToken();
1313       if (token == TokenNameLPAREN) {
1314         getNextToken();
1315       } else {
1316         throwSyntaxError("'(' expected after 'define' keyword.");
1317       }
1318       expression();
1319       if (token == TokenNameCOMMA) {
1320         getNextToken();
1321       } else {
1322         throwSyntaxError("',' expected after first 'define' constant.");
1323       }
1324       expression();
1325       if (token == TokenNameCOMMA) {
1326         getNextToken();
1327         expression();
1328       }
1329       if (token == TokenNameRPAREN) {
1330         getNextToken();
1331       } else {
1332         throwSyntaxError("')' expected after 'define' statement.");
1333       }
1334       if (token == TokenNameSEMICOLON) {
1335         getNextToken();
1336       } else {
1337         if (token != TokenNameStopPHP) {
1338           throwSyntaxError("';' expected after 'define' statement.");
1339         }
1340         getNextToken();
1341       }
1342       return;
1343     } else if (token == TokenNamefunction) {
1344       MethodDeclaration methodDecl = new MethodDeclaration(this.compilationUnit.compilationResult);
1345       methodDecl.declarationSourceStart = scanner.getCurrentTokenStartPosition();
1346       getNextToken();
1347       functionDefinition(methodDecl);
1348       return;
1349     } else if (token == TokenNameclass) {
1350       TypeDeclaration typeDecl = new TypeDeclaration(this.compilationUnit.compilationResult);
1351       typeDecl.declarationSourceStart = scanner.getCurrentTokenStartPosition();
1352       // default super class
1353       typeDecl.superclass = new SingleTypeReference(TypeConstants.OBJECT, 0);
1354       compilationUnit.types.add(typeDecl);
1355       try {
1356         pushOnAstStack(typeDecl);
1357         getNextToken();
1358         classDeclarator(typeDecl);
1359         classBody(typeDecl);
1360       } finally {
1361         astPtr--;
1362         astLengthPtr--;
1363       }
1364       return;
1365       //      } else {
1366       //        throwSyntaxError("Unexpected keyword '" + keyword + "'");
1367     } else if (token == TokenNameLBRACE) {
1368       getNextToken();
1369       if (token != TokenNameRBRACE) {
1370         statementList();
1371       }
1372       if (token == TokenNameRBRACE) {
1373         getNextToken();
1374         return;
1375       } else {
1376         throwSyntaxError("'}' expected.");
1377       }
1378     } else {
1379       if (token != TokenNameSEMICOLON) {
1380         expression();
1381       }
1382       if (token == TokenNameSEMICOLON) {
1383         getNextToken();
1384         return;
1385       } else {
1386         if (token != TokenNameStopPHP && token != TokenNameEOF) {
1387           throwSyntaxError("';' expected after expression (Found token: " + scanner.toStringAction(token) + ")");
1388         }
1389         getNextToken();
1390       }
1391     }
1392   }
1393
1394   private void classDeclarator(TypeDeclaration typeDecl) throws CoreException {
1395     //identifier
1396     //identifier 'extends' identifier
1397
1398         
1399     if (token == TokenNameIdentifier || token > TokenNameKEYWORD) {
1400       typeDecl.sourceStart = scanner.getCurrentTokenStartPosition();
1401       typeDecl.sourceEnd = scanner.getCurrentTokenEndPosition();
1402       typeDecl.name = scanner.getCurrentIdentifierSource();
1403       if (token > TokenNameKEYWORD) {
1404         reportSyntaxError(
1405           "Don't use keyword for class declaration [" + scanner.toStringAction(token) + "].",
1406                                   typeDecl.sourceStart,
1407                                   typeDecl.sourceEnd);
1408       }
1409       getNextToken();
1410       if (token == TokenNameextends) {
1411         do {
1412           getNextToken();
1413           if (token == TokenNameIdentifier) {
1414             getNextToken();
1415           } else {
1416             reportSyntaxError("Class name expected after keyword 'extends'.", scanner.getCurrentTokenStartPosition(), scanner.getCurrentTokenEndPosition());
1417           }
1418         } while (token == TokenNameCOMMA);
1419       } 
1420     } else {
1421       typeDecl.sourceStart = scanner.getCurrentTokenStartPosition();
1422       typeDecl.sourceEnd = scanner.getCurrentTokenEndPosition();
1423
1424       typeDecl.name = new char[] { ' ' };
1425       reportSyntaxError("Class name expected after keyword 'class'.", typeDecl.sourceStart, typeDecl.sourceEnd);
1426       //      throwSyntaxError("ClassDeclaration name expected after keyword 'class'.");
1427     }
1428   }
1429
1430   private void classBody(TypeDeclaration typeDecl) throws CoreException {
1431     //'{' [class-element-list] '}'
1432     if (token == TokenNameLBRACE) {
1433       getNextToken();
1434       if (token != TokenNameRBRACE) {
1435         classElementList();
1436       }
1437       if (token == TokenNameRBRACE) {
1438         typeDecl.declarationSourceEnd = scanner.getCurrentTokenEndPosition();
1439         getNextToken();
1440       } else {
1441         throwSyntaxError("'}' expected at end of class body.");
1442       }
1443     } else {
1444       throwSyntaxError("'{' expected at start of class body.");
1445     }
1446   }
1447
1448   private void classElementList() throws CoreException {
1449     do {
1450       classElement();
1451     } while (token == TokenNamefunction || token == TokenNamevar);
1452   }
1453
1454   private void classElement() throws CoreException {
1455     //class-property
1456     //function-definition
1457     if (token == TokenNamefunction) {
1458       MethodDeclaration methodDecl = new MethodDeclaration(this.compilationUnit.compilationResult);
1459       methodDecl.declarationSourceStart = scanner.getCurrentTokenStartPosition();
1460       getNextToken();
1461       functionDefinition(methodDecl);
1462     } else if (token == TokenNamevar) {
1463       getNextToken();
1464       classProperty();
1465     } else {
1466       throwSyntaxError("'function' or 'var' expected.");
1467     }
1468   }
1469
1470   private void classProperty() throws CoreException {
1471     //'var' variable ';'
1472     //'var' variable '=' constant ';'
1473     do {
1474       if (token == TokenNameVariable) {
1475         getNextToken();
1476         if (token == TokenNameEQUAL) {
1477           getNextToken();
1478           constant();
1479         }
1480       } else {
1481         if (token == TokenNamethis) {
1482           throwSyntaxError("Reserved word '$this' not allowed after keyword 'var'.");
1483         }
1484         throwSyntaxError("Variable expected after keyword 'var'.");
1485       }
1486       if (token != TokenNameCOMMA) {
1487         break;
1488       }
1489       getNextToken();
1490     } while (true);
1491     if (token == TokenNameSEMICOLON) {
1492       getNextToken();
1493     } else {
1494       throwSyntaxError("';' expected after variable declaration.");
1495     }
1496   }
1497
1498   private void functionDefinition(MethodDeclaration methodDecl) throws CoreException {
1499     if (astPtr == 0) {
1500       compilationUnit.types.add(methodDecl);
1501     } else {
1502       AstNode node = astStack[astPtr];
1503       if (node instanceof TypeDeclaration) {
1504         TypeDeclaration typeDecl = ((TypeDeclaration) node);
1505         if (typeDecl.methods == null) {
1506           typeDecl.methods = new AbstractMethodDeclaration[] { methodDecl };
1507         } else {
1508           AbstractMethodDeclaration[] newMethods;
1509           System.arraycopy(typeDecl.methods, 0, newMethods = new AbstractMethodDeclaration[typeDecl.methods.length + 1], 1, typeDecl.methods.length);
1510           newMethods[0] = methodDecl;
1511           typeDecl.methods = newMethods;
1512         }
1513       }
1514     }
1515     functionDeclarator(methodDecl);
1516     functionBody(methodDecl);
1517   }
1518
1519   private void functionDeclarator(MethodDeclaration methodDecl) throws CoreException {
1520     //identifier '(' [parameter-list] ')'
1521     if (token == TokenNameAND) {
1522       getNextToken();
1523     }
1524     if (token == TokenNameIdentifier) {
1525       methodDecl.sourceStart = scanner.getCurrentTokenStartPosition();
1526       methodDecl.sourceEnd = scanner.getCurrentTokenEndPosition();
1527       methodDecl.selector = scanner.getCurrentIdentifierSource();
1528       getNextToken();
1529       if (token == TokenNameLPAREN) {
1530         getNextToken();
1531       } else {
1532         throwSyntaxError("'(' expected in function declaration.");
1533       }
1534       if (token != TokenNameRPAREN) {
1535         parameterList();
1536       }
1537       if (token != TokenNameRPAREN) {
1538         throwSyntaxError("')' expected in function declaration.");
1539       } else {
1540         methodDecl.bodyStart = scanner.getCurrentTokenEndPosition() + 1;
1541         getNextToken();
1542       }
1543     } else {
1544       if (token > TokenNameKEYWORD) {
1545         throwSyntaxError("Don't use keyword for function declaration [" + token + "].");
1546       }
1547       throwSyntaxError("Function name expected after keyword 'function'.");
1548     }
1549   }
1550   //
1551   private void parameterList() throws CoreException {
1552     //parameter-declaration
1553     //parameter-list ',' parameter-declaration
1554     do {
1555       parameterDeclaration();
1556       if (token != TokenNameCOMMA) {
1557         break;
1558       }
1559       getNextToken();
1560     } while (true);
1561   }
1562
1563   private void parameterDeclaration() throws CoreException {
1564     //variable
1565     //variable-reference
1566     if (token == TokenNameAND) {
1567       getNextToken();
1568       if (isVariable()) {
1569         getNextToken();
1570       } else {
1571         throwSyntaxError("Variable expected after reference operator '&'.");
1572       }
1573     }
1574     //variable '=' constant
1575     if (token == TokenNameVariable) {
1576       getNextToken();
1577       if (token == TokenNameEQUAL) {
1578         getNextToken();
1579         constant();
1580       }
1581       return;
1582     }
1583     if (token == TokenNamethis) {
1584       throwSyntaxError("Reserved word '$this' not allowed in parameter declaration.");
1585     }
1586   }
1587
1588   private void labeledStatementList() throws CoreException {
1589     if (token != TokenNamecase && token != TokenNamedefault) {
1590       throwSyntaxError("'case' or 'default' expected.");
1591     }
1592     do {
1593       if (token == TokenNamecase) {
1594         getNextToken();
1595         expression(); //constant();
1596         if (token == TokenNameCOLON || token == TokenNameSEMICOLON) {
1597           getNextToken();
1598           if (token == TokenNamecase || token == TokenNamedefault) { // empty case statement ?
1599             continue;
1600           }
1601           statementList();
1602         } 
1603 //        else if (token == TokenNameSEMICOLON) {
1604 //          setMarker(
1605 //            "':' expected after 'case' keyword (Found token: " + scanner.toStringAction(token) + ")",
1606 //            scanner.getCurrentTokenStartPosition(),
1607 //            scanner.getCurrentTokenEndPosition(),
1608 //            INFO);
1609 //          getNextToken();
1610 //          if (token == TokenNamecase) { // empty case statement ?
1611 //            continue;
1612 //          }
1613 //          statementList();
1614 //        } 
1615       else {
1616           throwSyntaxError("':' character after 'case' constant expected (Found token: " + scanner.toStringAction(token) + ")");
1617         }
1618       } else { // TokenNamedefault
1619         getNextToken();
1620         if (token == TokenNameCOLON) {
1621           getNextToken();
1622           statementList();
1623         } else {
1624           throwSyntaxError("':' character after 'default' expected.");
1625         }
1626       }
1627     } while (token == TokenNamecase || token == TokenNamedefault);
1628   }
1629
1630   //  public void labeledStatement() {
1631   //    if (token == TokenNamecase) {
1632   //      getNextToken();
1633   //      constant();
1634   //      if (token == TokenNameDDOT) {
1635   //        getNextToken();
1636   //        statement();
1637   //      } else {
1638   //        throwSyntaxError("':' character after 'case' constant expected.");
1639   //      }
1640   //      return;
1641   //    } else if (token == TokenNamedefault) {
1642   //      getNextToken();
1643   //      if (token == TokenNameDDOT) {
1644   //        getNextToken();
1645   //        statement();
1646   //      } else {
1647   //        throwSyntaxError("':' character after 'default' expected.");
1648   //      }
1649   //      return;
1650   //    }
1651   //  }
1652
1653   //  public void expressionStatement() {
1654   //  }
1655
1656   //  private void inclusionStatement() {
1657   //  }
1658
1659   //  public void compoundStatement() {
1660   //  }
1661
1662   //  public void selectionStatement() {
1663   //  }
1664   //
1665   //  public void iterationStatement() {
1666   //  }
1667   //
1668   //  public void jumpStatement() {
1669   //  }
1670   //
1671   //  public void outputStatement() {
1672   //  }
1673   //
1674   //  public void scopeStatement() {
1675   //  }
1676   //
1677   //  public void flowStatement() {
1678   //  }
1679   //
1680   //  public void definitionStatement() {
1681   //  }
1682
1683   private void ifStatement() throws CoreException {
1684     // ':' statement-list [elseif-list] [else-colon-statement] 'endif' ';'
1685     if (token == TokenNameCOLON) {
1686       getNextToken();
1687       if (token != TokenNameendif) {
1688         statementList();
1689         switch (token) {
1690           case TokenNameelse :
1691             getNextToken();
1692             if (token == TokenNameCOLON) {
1693               getNextToken();
1694               if (token != TokenNameendif) {
1695                 statementList();
1696               }
1697             } else {
1698               if (token == TokenNameif) { //'else if'
1699                 getNextToken();
1700                 elseifStatementList();
1701               } else {
1702                 throwSyntaxError("':' expected after 'else'.");
1703               }
1704             }
1705             break;
1706           case TokenNameelseif :
1707             getNextToken();
1708             elseifStatementList();
1709             break;
1710         }
1711       }
1712
1713       if (token != TokenNameendif) {
1714         throwSyntaxError("'endif' expected.");
1715       }
1716       getNextToken();
1717       if (token != TokenNameSEMICOLON) {
1718         throwSyntaxError("';' expected after if-statement.");
1719       }
1720       getNextToken();
1721     } else {
1722       // statement [else-statement]
1723       statement(TokenNameEOF);
1724       if (token == TokenNameelseif) {
1725         getNextToken();
1726         if (token == TokenNameLPAREN) {
1727           getNextToken();
1728         } else {
1729           throwSyntaxError("'(' expected after 'elseif' keyword.");
1730         }
1731         expression();
1732         if (token == TokenNameRPAREN) {
1733           getNextToken();
1734         } else {
1735           throwSyntaxError("')' expected after 'elseif' condition.");
1736         }
1737         ifStatement();
1738       } else if (token == TokenNameelse) {
1739         getNextToken();
1740         statement(TokenNameEOF);
1741       }
1742     }
1743   }
1744
1745   private void elseifStatementList() throws CoreException {
1746     do {
1747       elseifStatement();
1748       switch (token) {
1749         case TokenNameelse :
1750           getNextToken();
1751           if (token == TokenNameCOLON) {
1752             getNextToken();
1753             if (token != TokenNameendif) {
1754               statementList();
1755             }
1756             return;
1757           } else {
1758             if (token == TokenNameif) { //'else if'
1759               getNextToken();
1760             } else {
1761               throwSyntaxError("':' expected after 'else'.");
1762             }
1763           }
1764           break;
1765         case TokenNameelseif :
1766           getNextToken();
1767           break;
1768         default :
1769           return;
1770       }
1771     } while (true);
1772   }
1773
1774   private void elseifStatement() throws CoreException {
1775     if (token == TokenNameLPAREN) {
1776       getNextToken();
1777       expression();
1778       if (token != TokenNameRPAREN) {
1779         throwSyntaxError("')' expected in else-if-statement.");
1780       }
1781       getNextToken();
1782       if (token != TokenNameCOLON) {
1783         throwSyntaxError("':' expected in else-if-statement.");
1784       }
1785       getNextToken();
1786       if (token != TokenNameendif) {
1787         statementList();
1788       }
1789     }
1790   }
1791
1792   private void switchStatement() throws CoreException {
1793     if (token == TokenNameCOLON) {
1794       // ':' [labeled-statement-list] 'endswitch' ';'
1795       getNextToken();
1796       labeledStatementList();
1797       if (token != TokenNameendswitch) {
1798         throwSyntaxError("'endswitch' expected.");
1799       }
1800       getNextToken();
1801       if (token != TokenNameSEMICOLON) {
1802         throwSyntaxError("';' expected after switch-statement.");
1803       }
1804       getNextToken();
1805     } else {
1806       // '{' [labeled-statement-list] '}'
1807       if (token != TokenNameLBRACE) {
1808         throwSyntaxError("'{' expected in switch statement.");
1809       }
1810       getNextToken();
1811       if (token != TokenNameRBRACE) {
1812         labeledStatementList();
1813       }
1814       if (token != TokenNameRBRACE) {
1815         throwSyntaxError("'}' expected in switch statement.");
1816       }
1817       getNextToken();
1818
1819     }
1820   }
1821
1822   private void forStatement() throws CoreException {
1823     if (token == TokenNameCOLON) {
1824       getNextToken();
1825       statementList();
1826       if (token != TokenNameendfor) {
1827         throwSyntaxError("'endfor' expected.");
1828       }
1829       getNextToken();
1830       if (token != TokenNameSEMICOLON) {
1831         throwSyntaxError("';' expected after for-statement.");
1832       }
1833       getNextToken();
1834     } else {
1835       statement(TokenNameEOF);
1836     }
1837   }
1838
1839   private void whileStatement() throws CoreException {
1840     // ':' statement-list 'endwhile' ';'
1841     if (token == TokenNameCOLON) {
1842       getNextToken();
1843       statementList();
1844       if (token != TokenNameendwhile) {
1845         throwSyntaxError("'endwhile' expected.");
1846       }
1847       getNextToken();
1848       if (token != TokenNameSEMICOLON) {
1849         throwSyntaxError("';' expected after while-statement.");
1850       }
1851       getNextToken();
1852     } else {
1853       statement(TokenNameEOF);
1854     }
1855   }
1856
1857   private void foreachStatement() throws CoreException {
1858     if (token == TokenNameCOLON) {
1859       getNextToken();
1860       statementList();
1861       if (token != TokenNameendforeach) {
1862         throwSyntaxError("'endforeach' expected.");
1863       }
1864       getNextToken();
1865       if (token != TokenNameSEMICOLON) {
1866         throwSyntaxError("';' expected after foreach-statement.");
1867       }
1868       getNextToken();
1869     } else {
1870       statement(TokenNameEOF);
1871     }
1872   }
1873
1874   private void exitStatus() throws CoreException {
1875     if (token == TokenNameLPAREN) {
1876       getNextToken();
1877     } else {
1878       throwSyntaxError("'(' expected in 'exit-status'.");
1879     }
1880     if (token != TokenNameRPAREN) {
1881       expression();
1882     }
1883     if (token == TokenNameRPAREN) {
1884       getNextToken();
1885     } else {
1886       throwSyntaxError("')' expected after 'exit-status'.");
1887     }
1888   }
1889
1890   private void expressionList() throws CoreException {
1891     do {
1892       expression();
1893       if (token == TokenNameCOMMA) {
1894         getNextToken();
1895       } else {
1896         break;
1897       }
1898     } while (true);
1899   }
1900
1901   private void expression() throws CoreException {
1902     //todo: find a better way to get the expression
1903     //    expression = new StringBuffer();
1904     //    for (int i = chIndx; i < str.length(); i++) {
1905     //      if (str.charAt(i) == ';') {
1906     //        break;
1907     //      }
1908     //      expression.append(str.charAt(i));
1909     //    }
1910
1911     //    if (token == TokenNameSTRING_CONSTANT || token == TokenNameINTERPOLATED_STRING) {
1912     //      getNextToken();
1913     //    } else {
1914     logicalinclusiveorExpression();
1915     //      while (token != TokenNameSEMICOLON) {
1916     //        getNextToken();
1917     //      //      }
1918     //    }
1919   }
1920
1921   private void postfixExpression() throws CoreException {
1922     //  String ident;
1923     char[] ident;
1924     boolean castFlag = false;
1925     boolean arrayFlag = false;
1926     switch (token) {
1927       case TokenNamenew :
1928         getNextToken();
1929         expression();
1930         break;
1931       case TokenNamenull :
1932         getNextToken();
1933         break;
1934       case TokenNamefalse :
1935         getNextToken();
1936         break;
1937       case TokenNametrue :
1938         getNextToken();
1939         break;
1940       case TokenNameStringConstant :
1941         getNextToken();
1942         break;
1943       case TokenNameHEREDOC :
1944       case TokenNameStringInterpolated :
1945       case TokenNameStringLiteral :
1946         getNextToken();
1947         break;
1948       case TokenNameLPAREN :
1949         getNextToken();
1950
1951         if (token == TokenNameIdentifier) {
1952           // check if identifier is a type:
1953           //    ident = identifier;
1954           ident = scanner.getCurrentIdentifierSource();
1955           String str = new String(ident).toLowerCase();
1956           for (int i = 0; i < PHP_TYPES.length; i++) {
1957             if (PHP_TYPES[i].equals(str)) {
1958               castFlag = true;
1959               if (PHP_TYPES[i].equals("array")) {
1960                 arrayFlag = true;
1961               }
1962               break;
1963             }
1964           }
1965         }
1966
1967         if (castFlag) {
1968           getNextToken();
1969           if (arrayFlag && token == TokenNameLPAREN) {
1970             getNextToken();
1971             if (token == TokenNameRPAREN) {
1972               getNextToken();
1973             } else {
1974               expression();
1975               if (token != TokenNameRPAREN) {
1976                 throwSyntaxError(") expected after 'array('.");
1977               }
1978             }
1979           }
1980           if (token != TokenNameRPAREN) {
1981             throwSyntaxError(") expected after cast-type '" + str + "'.");
1982           }
1983           getNextToken();
1984           expression();
1985           break;
1986         } else {
1987           expression();
1988         }
1989         if (token != TokenNameRPAREN) {
1990           throwSyntaxError(") expected in postfix-expression.");
1991         }
1992         getNextToken();
1993         break;
1994       case TokenNameDoubleLiteral :
1995         getNextToken();
1996         break;
1997       case TokenNameIntegerLiteral :
1998         getNextToken();
1999         break;
2000       case TokenNameDOLLAR_LBRACE :
2001         getNextToken();
2002         expression();
2003         if (token != TokenNameRBRACE) {
2004           throwSyntaxError("'}' expected after indirect variable token '${'.");
2005         }
2006         getNextToken();
2007         break;
2008       case TokenNameVariable :
2009       case TokenNamethis :
2010         ident = scanner.getCurrentIdentifierSource();
2011         getNextToken();
2012         if (token == TokenNameLBRACE) {
2013           getNextToken();
2014           expression();
2015           if (token != TokenNameRBRACE) {
2016             throwSyntaxError("'}' expected after variable '" + new String(ident) + "' in variable-expression.");
2017           }
2018           getNextToken();
2019         } else if (token == TokenNameLPAREN) {
2020           getNextToken();
2021           if (token != TokenNameRPAREN) {
2022             expressionList();
2023             if (token != TokenNameRPAREN) {
2024               throwSyntaxError("')' expected after variable '" + new String(ident) + "' in postfix-expression.");
2025             }
2026           }
2027           getNextToken();
2028         }
2029         break;
2030       case TokenNameIdentifier :
2031         ident = scanner.getCurrentIdentifierSource();
2032         getNextToken();
2033         if (token == TokenNameLPAREN) {
2034           getNextToken();
2035           if (token != TokenNameRPAREN) {
2036             expressionList();
2037             if (token != TokenNameRPAREN) {
2038               throwSyntaxError(
2039                 "')' expected after identifier '" + new String(ident) + "' in postfix-expression." + "(Found token: " + scanner.toStringAction(token) + ")");
2040             }
2041           }
2042           getNextToken();
2043         }
2044         break;
2045       case TokenNameprint :
2046         getNextToken();
2047         expression();
2048         //        if (token == TokenNameSEMICOLON) {
2049         //          getNextToken();
2050         //        } else {
2051         //          if (token != TokenNameStopPHP) {
2052         //            throwSyntaxError("';' expected after 'print' statement.");
2053         //          }
2054         //          getNextToken();
2055         //        }
2056         break;
2057       case TokenNamelist :
2058         getNextToken();
2059         if (token == TokenNameLPAREN) {
2060           getNextToken();
2061           if (token == TokenNameCOMMA) {
2062             getNextToken();
2063           }
2064           expressionList();
2065           if (token != TokenNameRPAREN) {
2066             throwSyntaxError("')' expected after 'list' keyword.");
2067           }
2068           getNextToken();
2069           //          if (token == TokenNameSET) {
2070           //            getNextToken();
2071           //            logicalinclusiveorExpression();
2072           //          }
2073         } else {
2074           throwSyntaxError("'(' expected after 'list' keyword.");
2075         }
2076         break;
2077         //      case TokenNameexit :
2078         //        getNextToken();
2079         //        if (token != TokenNameSEMICOLON) {
2080         //          exitStatus();
2081         //        }
2082         //        if (token == TokenNameSEMICOLON) {
2083         //          getNextToken();
2084         //        } else {
2085         //          if (token != TokenNameStopPHP) {
2086         //            throwSyntaxError("';' expected after 'exit' expression.");
2087         //          }
2088         //          getNextToken();
2089         //        }
2090         //        break;
2091         //      case TokenNamedie :
2092         //        getNextToken();
2093         //        if (token != TokenNameSEMICOLON) {
2094         //          exitStatus();
2095         //        }
2096         //        if (token == TokenNameSEMICOLON) {
2097         //          getNextToken();
2098         //        } else {
2099         //          if (token != TokenNameStopPHP) {
2100         //            throwSyntaxError("';' expected after 'die' expression.");
2101         //          }
2102         //        }
2103         //        break;
2104
2105         //      case TokenNamearray :
2106         //        getNextToken();
2107         //        if (token == TokenNameARGOPEN) {
2108         //          getNextToken();
2109         //          if (token == TokenNameCOMMA) {
2110         //            getNextToken();
2111         //          }
2112         //          expressionList();
2113         //          if (token != TokenNameARGCLOSE) {
2114         //            throwSyntaxError("')' expected after 'list' keyword.");
2115         //          }
2116         //          getNextToken();
2117         //          if (token == TokenNameSET) {
2118         //            getNextToken();
2119         //            logicalinclusiveorExpression();
2120         //          }
2121         //        } else {
2122         //          throwSyntaxError("'(' expected after 'list' keyword.");
2123         //        }
2124         //        break;
2125     }
2126     boolean while_flag = true;
2127     do {
2128       switch (token) {
2129         case TokenNameLBRACKET :
2130           getNextToken();
2131           expression();
2132           if (token != TokenNameRBRACKET) {
2133             throwSyntaxError("] expected in postfix-expression.");
2134           }
2135           getNextToken();
2136           break;
2137         case TokenNameCOLON_COLON : // ::
2138         case TokenNameMINUS_GREATER : // ->
2139           getNextToken();
2140           if (token > TokenNameKEYWORD) {
2141             ident = scanner.getCurrentIdentifierSource();
2142             //            setMarker(
2143             //              "Avoid using keyword '"
2144             //                + new String(ident)
2145             //                + "' as variable name.",
2146             //              rowCount,
2147             //              PHPParser.INFO);
2148 //            setMarker(
2149 //              "Avoid using keyword '" + new String(ident) + "' as variable name.",
2150 //              scanner.getCurrentTokenStartPosition(),
2151 //              scanner.getCurrentTokenEndPosition(),
2152 //              INFO);
2153           }
2154           switch (token) {
2155             case TokenNameVariable :
2156               ident = scanner.getCurrentIdentifierSource();
2157               getNextToken();
2158               //              if (token == TokenNameARGOPEN) {
2159               //                getNextToken();
2160               //                expressionList();
2161               //                if (token != TokenNameARGCLOSE) {
2162               //                  throwSyntaxError(") expected after variable '" + ident + "'.");
2163               //                }
2164               //                getNextToken();
2165               //              }
2166               break;
2167             case TokenNameIdentifier :
2168               //ident = scanner.getCurrentIdentifierSource();
2169               getNextToken();
2170               break;
2171             case TokenNameLBRACE :
2172               getNextToken();
2173               expression();
2174               if (token != TokenNameRBRACE) {
2175                 throwSyntaxError("} expected in postfix-expression.");
2176               }
2177               getNextToken();
2178               break;
2179             default :
2180               throwSyntaxError("Syntax error after '->' token.");
2181           } while (token == TokenNameLBRACKET || token == TokenNameLPAREN || token == TokenNameLBRACE) {
2182               if (token == TokenNameLBRACKET) {
2183                 getNextToken();
2184                 expressionList();
2185                 if (token != TokenNameRBRACKET) {
2186                   throwSyntaxError("] expected after '->'.");
2187                 }
2188                 getNextToken();
2189               } else if (token == TokenNameLPAREN) {
2190                 getNextToken();
2191                 expressionList();
2192                 if (token != TokenNameRPAREN) {
2193                   throwSyntaxError(") expected after '->'.");
2194                 }
2195                 getNextToken();
2196               } else if (token == TokenNameLBRACE) {
2197                 getNextToken();
2198                 expression();
2199                 if (token != TokenNameRBRACE) {
2200                   throwSyntaxError("} expected after '->'.");
2201                 }
2202                 getNextToken();
2203               }
2204             }
2205           break;
2206         case TokenNamePLUS_PLUS :
2207           getNextToken();
2208           break;
2209         case TokenNameMINUS_MINUS :
2210           getNextToken();
2211           break;
2212         default :
2213           while_flag = false;
2214       }
2215
2216     }
2217     while (while_flag);
2218   }
2219
2220   private void unaryExpression() throws CoreException {
2221     switch (token) {
2222       case TokenNamePLUS_PLUS :
2223         getNextToken();
2224         unaryExpression();
2225         break;
2226       case TokenNameMINUS_MINUS :
2227         getNextToken();
2228         unaryExpression();
2229         break;
2230         // '@' '&' '*' '+' '-' '~' '!'
2231       case TokenNameAT :
2232         getNextToken();
2233         if (token == TokenNameinclude || token == TokenNameinclude_once || token == TokenNamerequire || token == TokenNamerequire_once) {
2234           statement(TokenNameAT);
2235         } else {
2236           postfixExpression(); //  castExpression();
2237         }
2238         break;
2239       case TokenNameAND :
2240         getNextToken();
2241         castExpression();
2242         break;
2243       case TokenNameMULTIPLY :
2244         getNextToken();
2245         castExpression();
2246         break;
2247       case TokenNamePLUS :
2248         getNextToken();
2249         castExpression();
2250         break;
2251       case TokenNameMINUS :
2252         getNextToken();
2253         castExpression();
2254         break;
2255       case TokenNameTWIDDLE :
2256         getNextToken();
2257         castExpression();
2258         break;
2259       case TokenNameNOT :
2260         getNextToken();
2261         castExpression();
2262         break;
2263       default :
2264         postfixExpression();
2265     }
2266   }
2267
2268   private void castExpression() throws CoreException {
2269     //    if (token == TokenNameARGOPEN) {
2270     //      getNextToken();
2271     //      typeName();
2272     //      if (token != TokenNameARGCLOSE) {
2273     //        throwSyntaxError(") expected after cast-expression.");
2274     //      }
2275     //      getNextToken();
2276     //    }
2277     unaryExpression();
2278   }
2279
2280   private void assignExpression() throws CoreException {
2281     castExpression();
2282     if (token == TokenNameEQUAL) { // =
2283       getNextToken();
2284       logicalinclusiveorExpression();
2285     } else if (token == TokenNameDOT_EQUAL) { // .=
2286       getNextToken();
2287       logicalinclusiveorExpression();
2288     } else if (token == TokenNameEQUAL_GREATER) { // =>
2289       getNextToken();
2290       logicalinclusiveorExpression();
2291     } else if (token == TokenNamePLUS_EQUAL) { // +=
2292       getNextToken();
2293       logicalinclusiveorExpression();
2294     } else if (token == TokenNameMINUS_EQUAL) { // -=
2295       getNextToken();
2296       logicalinclusiveorExpression();
2297     } else if (token == TokenNameMULTIPLY_EQUAL) { // *=
2298       getNextToken();
2299       logicalinclusiveorExpression();
2300     } else if (token == TokenNameDIVIDE_EQUAL) { // *=
2301       getNextToken();
2302       logicalinclusiveorExpression();
2303     } else if (token == TokenNameREMAINDER_EQUAL) { // %=
2304       getNextToken();
2305       logicalinclusiveorExpression();
2306     } else if (token == TokenNameAND_EQUAL) { // &=
2307       getNextToken();
2308       logicalinclusiveorExpression();
2309     } else if (token == TokenNameOR_EQUAL) { // |=
2310       getNextToken();
2311       logicalinclusiveorExpression();
2312     } else if (token == TokenNameXOR_EQUAL) { // ^=
2313       getNextToken();
2314       logicalinclusiveorExpression();
2315     } else if (token == TokenNameLEFT_SHIFT_EQUAL) { // <<=
2316       getNextToken();
2317       logicalinclusiveorExpression();
2318     } else if (token == TokenNameRIGHT_SHIFT_EQUAL) { // >>=
2319       getNextToken();
2320       logicalinclusiveorExpression();
2321     } else if (token == TokenNameTWIDDLE_EQUAL) { // ~=
2322       getNextToken();
2323       logicalinclusiveorExpression();
2324     }
2325   }
2326
2327   private void multiplicativeExpression() throws CoreException {
2328     do {
2329       assignExpression();
2330       if (token != TokenNameMULTIPLY && token != TokenNameDIVIDE && token != TokenNameREMAINDER) {
2331         return;
2332       }
2333       getNextToken();
2334     } while (true);
2335   }
2336
2337   private void concatenationExpression() throws CoreException {
2338     do {
2339       multiplicativeExpression();
2340       if (token != TokenNameDOT) {
2341         return;
2342       }
2343       getNextToken();
2344     } while (true);
2345   }
2346
2347   private void additiveExpression() throws CoreException {
2348     do {
2349       concatenationExpression();
2350       if (token != TokenNamePLUS && token != TokenNameMINUS) {
2351         return;
2352       }
2353       getNextToken();
2354     } while (true);
2355   }
2356
2357   private void shiftExpression() throws CoreException {
2358     do {
2359       additiveExpression();
2360       if (token != TokenNameLEFT_SHIFT && token != TokenNameRIGHT_SHIFT) {
2361         return;
2362       }
2363       getNextToken();
2364     } while (true);
2365   }
2366
2367   private void relationalExpression() throws CoreException {
2368     do {
2369       shiftExpression();
2370       if (token != TokenNameLESS && token != TokenNameGREATER && token != TokenNameLESS_EQUAL && token != TokenNameGREATER_EQUAL) {
2371         return;
2372       }
2373       getNextToken();
2374     } while (true);
2375   }
2376
2377   private void identicalExpression() throws CoreException {
2378     do {
2379       relationalExpression();
2380       if (token != TokenNameEQUAL_EQUAL_EQUAL && token != TokenNameNOT_EQUAL_EQUAL) {
2381         return;
2382       }
2383       getNextToken();
2384     } while (true);
2385   }
2386
2387   private void equalityExpression() throws CoreException {
2388     do {
2389       identicalExpression();
2390       if (token != TokenNameEQUAL_EQUAL && token != TokenNameNOT_EQUAL) {
2391         return;
2392       }
2393       getNextToken();
2394     } while (true);
2395   }
2396
2397   private void ternaryExpression() throws CoreException {
2398     equalityExpression();
2399     if (token == TokenNameQUESTION) {
2400       getNextToken();
2401       expression();
2402       if (token == TokenNameCOLON) {
2403         getNextToken();
2404         expression();
2405       } else {
2406         throwSyntaxError("':' expected in ternary operator '? :'.");
2407       }
2408     }
2409   }
2410
2411   private void andExpression() throws CoreException {
2412     do {
2413       ternaryExpression();
2414       if (token != TokenNameAND) {
2415         return;
2416       }
2417       getNextToken();
2418     } while (true);
2419   }
2420
2421   private void exclusiveorExpression() throws CoreException {
2422     do {
2423       andExpression();
2424       if (token != TokenNameXOR) {
2425         return;
2426       }
2427       getNextToken();
2428     } while (true);
2429   }
2430
2431   private void inclusiveorExpression() throws CoreException {
2432     do {
2433       exclusiveorExpression();
2434       if (token != TokenNameOR) {
2435         return;
2436       }
2437       getNextToken();
2438     } while (true);
2439   }
2440
2441   private void booleanandExpression() throws CoreException {
2442     do {
2443       inclusiveorExpression();
2444       if (token != TokenNameAND_AND) {
2445         return;
2446       }
2447       getNextToken();
2448     } while (true);
2449   }
2450
2451   private void booleanorExpression() throws CoreException {
2452     do {
2453       booleanandExpression();
2454       if (token != TokenNameOR_OR) {
2455         return;
2456       }
2457       getNextToken();
2458     } while (true);
2459   }
2460
2461   private void logicalandExpression() throws CoreException {
2462     do {
2463       booleanorExpression();
2464       if (token != TokenNameAND) {
2465         return;
2466       }
2467       getNextToken();
2468     } while (true);
2469   }
2470
2471   private void logicalexclusiveorExpression() throws CoreException {
2472     do {
2473       logicalandExpression();
2474       if (token != TokenNameXOR) {
2475         return;
2476       }
2477       getNextToken();
2478     } while (true);
2479   }
2480
2481   private void logicalinclusiveorExpression() throws CoreException {
2482     do {
2483       logicalexclusiveorExpression();
2484       if (token != TokenNameOR) {
2485         return;
2486       }
2487       getNextToken();
2488     } while (true);
2489   }
2490
2491   //  public void assignmentExpression() {
2492   //    if (token == TokenNameVARIABLE) {
2493   //      getNextToken();
2494   //      if (token == TokenNameSET) {
2495   //        getNextToken();
2496   //        logicalinclusiveorExpression();
2497   //      }
2498   //    } else {
2499   //      logicalinclusiveorExpression();
2500   //    }
2501   //  }
2502
2503   private void variableList() throws CoreException {
2504     do {
2505       variable();
2506       if (token == TokenNameCOMMA) {
2507         getNextToken();
2508       } else {
2509         break;
2510       }
2511     } while (true);
2512   }
2513
2514   private void variable() throws CoreException {
2515     if (token == TokenNameDOLLAR_LBRACE) {
2516       getNextToken();
2517       expression();
2518       ;
2519       if (token != TokenNameRBRACE) {
2520         throwSyntaxError("'}' expected after indirect variable token '${'.");
2521       }
2522       getNextToken();
2523     } else {
2524       if (token == TokenNameVariable) {
2525         getNextToken();
2526         if (token == TokenNameLBRACKET) {
2527           getNextToken();
2528           expression();
2529           if (token != TokenNameRBRACKET) {
2530             throwSyntaxError("']' expected in variable-list.");
2531           }
2532           getNextToken();
2533         } else if (token == TokenNameEQUAL) {
2534           getNextToken();
2535           constant();
2536         }
2537       } else {
2538         throwSyntaxError("$-variable expected in variable-list.");
2539       }
2540     }
2541   }
2542
2543   /**
2544    * It will look for a value (after a '=' for example)
2545    * @throws CoreException
2546    */
2547   private void constant() throws CoreException {
2548     //   String ident;
2549     switch (token) {
2550       case TokenNamePLUS :
2551         getNextToken();
2552         switch (token) {
2553           case TokenNameDoubleLiteral :
2554             getNextToken();
2555             break;
2556           case TokenNameIntegerLiteral :
2557             getNextToken();
2558             break;
2559           default :
2560             throwSyntaxError("Constant expected after '+' presign.");
2561         }
2562         break;
2563       case TokenNameMINUS :
2564         getNextToken();
2565         switch (token) {
2566           case TokenNameDoubleLiteral :
2567             getNextToken();
2568             break;
2569           case TokenNameIntegerLiteral :
2570             getNextToken();
2571             break;
2572           default :
2573             throwSyntaxError("Constant expected after '-' presign.");
2574         }
2575         break;
2576       case TokenNamenull :
2577         getNextToken();
2578         break;
2579       case TokenNamefalse :
2580         getNextToken();
2581         break;
2582       case TokenNametrue :
2583         getNextToken();
2584         break;
2585       case TokenNameIdentifier :
2586         //   ident = identifier;
2587         char[] ident = scanner.getCurrentIdentifierSource();
2588         getNextToken();
2589         if (token == TokenNameLPAREN) {
2590           getNextToken();
2591           if (token != TokenNameRPAREN) {
2592             expressionList();
2593             if (token != TokenNameRPAREN) {
2594               throwSyntaxError("')' expected after identifier '" + new String(ident) + "' in postfix-expression.");
2595             }
2596           }
2597           getNextToken();
2598         }
2599         break;
2600       case TokenNameStringLiteral :
2601         getNextToken();
2602         break;
2603       case TokenNameStringConstant :
2604         getNextToken();
2605         break;
2606       case TokenNameStringInterpolated :
2607         getNextToken();
2608         break;
2609       case TokenNameDoubleLiteral :
2610         getNextToken();
2611         break;
2612       case TokenNameIntegerLiteral :
2613         getNextToken();
2614         break;
2615       default :
2616         throwSyntaxError("Constant expected.");
2617     }
2618   }
2619
2620   public void reportSyntaxError() { //int act, int currentKind, int stateStackTop) {
2621
2622     /* remember current scanner position */
2623     int startPos = scanner.startPosition;
2624     int currentPos = scanner.currentPosition;
2625
2626     //          String[] expectings;
2627     //          String tokenName = name[symbol_index[currentKind]];
2628
2629     //fetch all "accurate" possible terminals that could recover the error
2630     //          int start, end = start = asi(stack[stateStackTop]);
2631     //          while (asr[end] != 0)
2632     //                  end++;
2633     //          int length = end - start;
2634     //          expectings = new String[length];
2635     //          if (length != 0) {
2636     //                  char[] indexes = new char[length];
2637     //                  System.arraycopy(asr, start, indexes, 0, length);
2638     //                  for (int i = 0; i < length; i++) {
2639     //                          expectings[i] = name[symbol_index[indexes[i]]];
2640     //                  }
2641     //          }
2642
2643     //if the pb is an EOF, try to tell the user that they are some 
2644     //          if (tokenName.equals(UNEXPECTED_EOF)) {
2645     //                  if (!this.checkAndReportBracketAnomalies(problemReporter())) {
2646     //                          char[] tokenSource;
2647     //                          try {
2648     //                                  tokenSource = this.scanner.getCurrentTokenSource();
2649     //                          } catch (Exception e) {
2650     //                                  tokenSource = new char[] {};
2651     //                          }
2652     //                          problemReporter().parseError(
2653     //                                  this.scanner.startPosition, 
2654     //                                  this.scanner.currentPosition - 1, 
2655     //                                  tokenSource, 
2656     //                                  tokenName, 
2657     //                                  expectings); 
2658     //                  }
2659     //          } else { //the next test is HEAVILY grammar DEPENDENT.
2660     //                  if ((length == 14)
2661     //                          && (expectings[0] == "=") //$NON-NLS-1$
2662     //                          && (expectings[1] == "*=") //$NON-NLS-1$
2663     //                          && (expressionPtr > -1)) {
2664     //                                  switch(currentKind) {
2665     //                                          case TokenNameSEMICOLON:
2666     //                                          case TokenNamePLUS:
2667     //                                          case TokenNameMINUS:
2668     //                                          case TokenNameDIVIDE:
2669     //                                          case TokenNameREMAINDER:
2670     //                                          case TokenNameMULTIPLY:
2671     //                                          case TokenNameLEFT_SHIFT:
2672     //                                          case TokenNameRIGHT_SHIFT:
2673     ////                                                case TokenNameUNSIGNED_RIGHT_SHIFT:
2674     //                                          case TokenNameLESS:
2675     //                                          case TokenNameGREATER:
2676     //                                          case TokenNameLESS_EQUAL:
2677     //                                          case TokenNameGREATER_EQUAL:
2678     //                                          case TokenNameEQUAL_EQUAL:
2679     //                                          case TokenNameNOT_EQUAL:
2680     //                                          case TokenNameXOR:
2681     //                                          case TokenNameAND:
2682     //                                          case TokenNameOR:
2683     //                                          case TokenNameOR_OR:
2684     //                                          case TokenNameAND_AND:
2685     //                                                  // the ; is not the expected token ==> it ends a statement when an expression is not ended
2686     //                                                  problemReporter().invalidExpressionAsStatement(expressionStack[expressionPtr]);
2687     //                                                  break;
2688     //                                          case TokenNameRBRACE :
2689     //                                                  problemReporter().missingSemiColon(expressionStack[expressionPtr]);
2690     //                                                  break;
2691     //                                          default:
2692     //                                                  char[] tokenSource;
2693     //                                                  try {
2694     //                                                          tokenSource = this.scanner.getCurrentTokenSource();
2695     //                                                  } catch (Exception e) {
2696     //                                                          tokenSource = new char[] {};
2697     //                                                  }
2698     //                                                  problemReporter().parseError(
2699     //                                                          this.scanner.startPosition, 
2700     //                                                          this.scanner.currentPosition - 1, 
2701     //                                                          tokenSource, 
2702     //                                                          tokenName, 
2703     //                                                          expectings); 
2704     //                                                  this.checkAndReportBracketAnomalies(problemReporter());
2705     //                                  }
2706     //                  } else {
2707     char[] tokenSource;
2708     try {
2709       tokenSource = this.scanner.getCurrentTokenSource();
2710     } catch (Exception e) {
2711       tokenSource = new char[] {
2712       };
2713     }
2714     //                          problemReporter().parseError(
2715     //                                  this.scanner.startPosition, 
2716     //                                  this.scanner.currentPosition - 1, 
2717     //                                  tokenSource, 
2718     //                                  tokenName, 
2719     //                                  expectings); 
2720     this.checkAndReportBracketAnomalies(problemReporter());
2721     //                  }
2722     //          }
2723     /* reset scanner where it was */
2724     scanner.startPosition = startPos;
2725     scanner.currentPosition = currentPos;
2726   }
2727   public static final int RoundBracket = 0;
2728   public static final int SquareBracket = 1;
2729   public static final int CurlyBracket = 2;
2730   public static final int BracketKinds = 3;
2731
2732   protected int[] nestedMethod; //the ptr is nestedType
2733   protected int nestedType, dimensions;
2734   //ast stack
2735   final static int AstStackIncrement = 100;
2736   protected int astPtr;
2737   protected AstNode[] astStack = new AstNode[AstStackIncrement];
2738   protected int astLengthPtr;
2739   protected int[] astLengthStack;
2740   AstNode[] noAstNodes = new AstNode[AstStackIncrement];
2741
2742   public CompilationUnitDeclaration compilationUnit; /*the result from parse()*/
2743   protected ReferenceContext referenceContext;
2744   protected ProblemReporter problemReporter;
2745   //  protected CompilationResult compilationResult;
2746
2747   /**
2748    * Returns this parser's problem reporter initialized with its reference context.
2749    * Also it is assumed that a problem is going to be reported, so initializes
2750    * the compilation result's line positions.
2751    */
2752   public ProblemReporter problemReporter() {
2753     if (scanner.recordLineSeparator) {
2754       compilationUnit.compilationResult.lineSeparatorPositions = scanner.getLineEnds();
2755     }
2756     problemReporter.referenceContext = referenceContext;
2757     return problemReporter;
2758   }
2759   /*
2760    * Reconsider the entire source looking for inconsistencies in {} () []
2761    */
2762   public boolean checkAndReportBracketAnomalies(ProblemReporter problemReporter) {
2763
2764     scanner.wasAcr = false;
2765     boolean anomaliesDetected = false;
2766     try {
2767       char[] source = scanner.source;
2768       int[] leftCount = { 0, 0, 0 };
2769       int[] rightCount = { 0, 0, 0 };
2770       int[] depths = { 0, 0, 0 };
2771       int[][] leftPositions = new int[][] { new int[10], new int[10], new int[10] };
2772       int[][] leftDepths = new int[][] { new int[10], new int[10], new int[10] };
2773       int[][] rightPositions = new int[][] { new int[10], new int[10], new int[10] };
2774       int[][] rightDepths = new int[][] { new int[10], new int[10], new int[10] };
2775       scanner.currentPosition = scanner.initialPosition; //starting point (first-zero-based char)
2776       while (scanner.currentPosition < scanner.eofPosition) { //loop for jumping over comments
2777         try {
2778           // ---------Consume white space and handles startPosition---------
2779           boolean isWhiteSpace;
2780           do {
2781             scanner.startPosition = scanner.currentPosition;
2782             //                                          if (((scanner.currentCharacter = source[scanner.currentPosition++]) == '\\') && (source[scanner.currentPosition] == 'u')) {
2783             //                                                  isWhiteSpace = scanner.jumpOverUnicodeWhiteSpace();
2784             //                                          } else {
2785             if (scanner.recordLineSeparator && ((scanner.currentCharacter == '\r') || (scanner.currentCharacter == '\n'))) {
2786               if (scanner.lineEnds[scanner.linePtr] < scanner.startPosition) {
2787                 // only record line positions we have not recorded yet
2788                 scanner.pushLineSeparator();
2789               }
2790             }
2791             isWhiteSpace = CharOperation.isWhitespace(scanner.currentCharacter);
2792             //                                          }
2793           } while (isWhiteSpace && (scanner.currentPosition < scanner.eofPosition));
2794
2795           // -------consume token until } is found---------
2796
2797           switch (scanner.currentCharacter) {
2798             case '{' :
2799               {
2800                 int index = leftCount[CurlyBracket]++;
2801                 if (index == leftPositions[CurlyBracket].length) {
2802                   System.arraycopy(leftPositions[CurlyBracket], 0, (leftPositions[CurlyBracket] = new int[index * 2]), 0, index);
2803                   System.arraycopy(leftDepths[CurlyBracket], 0, (leftDepths[CurlyBracket] = new int[index * 2]), 0, index);
2804                 }
2805                 leftPositions[CurlyBracket][index] = scanner.startPosition;
2806                 leftDepths[CurlyBracket][index] = depths[CurlyBracket]++;
2807               }
2808               break;
2809             case '}' :
2810               {
2811                 int index = rightCount[CurlyBracket]++;
2812                 if (index == rightPositions[CurlyBracket].length) {
2813                   System.arraycopy(rightPositions[CurlyBracket], 0, (rightPositions[CurlyBracket] = new int[index * 2]), 0, index);
2814                   System.arraycopy(rightDepths[CurlyBracket], 0, (rightDepths[CurlyBracket] = new int[index * 2]), 0, index);
2815                 }
2816                 rightPositions[CurlyBracket][index] = scanner.startPosition;
2817                 rightDepths[CurlyBracket][index] = --depths[CurlyBracket];
2818               }
2819               break;
2820             case '(' :
2821               {
2822                 int index = leftCount[RoundBracket]++;
2823                 if (index == leftPositions[RoundBracket].length) {
2824                   System.arraycopy(leftPositions[RoundBracket], 0, (leftPositions[RoundBracket] = new int[index * 2]), 0, index);
2825                   System.arraycopy(leftDepths[RoundBracket], 0, (leftDepths[RoundBracket] = new int[index * 2]), 0, index);
2826                 }
2827                 leftPositions[RoundBracket][index] = scanner.startPosition;
2828                 leftDepths[RoundBracket][index] = depths[RoundBracket]++;
2829               }
2830               break;
2831             case ')' :
2832               {
2833                 int index = rightCount[RoundBracket]++;
2834                 if (index == rightPositions[RoundBracket].length) {
2835                   System.arraycopy(rightPositions[RoundBracket], 0, (rightPositions[RoundBracket] = new int[index * 2]), 0, index);
2836                   System.arraycopy(rightDepths[RoundBracket], 0, (rightDepths[RoundBracket] = new int[index * 2]), 0, index);
2837                 }
2838                 rightPositions[RoundBracket][index] = scanner.startPosition;
2839                 rightDepths[RoundBracket][index] = --depths[RoundBracket];
2840               }
2841               break;
2842             case '[' :
2843               {
2844                 int index = leftCount[SquareBracket]++;
2845                 if (index == leftPositions[SquareBracket].length) {
2846                   System.arraycopy(leftPositions[SquareBracket], 0, (leftPositions[SquareBracket] = new int[index * 2]), 0, index);
2847                   System.arraycopy(leftDepths[SquareBracket], 0, (leftDepths[SquareBracket] = new int[index * 2]), 0, index);
2848                 }
2849                 leftPositions[SquareBracket][index] = scanner.startPosition;
2850                 leftDepths[SquareBracket][index] = depths[SquareBracket]++;
2851               }
2852               break;
2853             case ']' :
2854               {
2855                 int index = rightCount[SquareBracket]++;
2856                 if (index == rightPositions[SquareBracket].length) {
2857                   System.arraycopy(rightPositions[SquareBracket], 0, (rightPositions[SquareBracket] = new int[index * 2]), 0, index);
2858                   System.arraycopy(rightDepths[SquareBracket], 0, (rightDepths[SquareBracket] = new int[index * 2]), 0, index);
2859                 }
2860                 rightPositions[SquareBracket][index] = scanner.startPosition;
2861                 rightDepths[SquareBracket][index] = --depths[SquareBracket];
2862               }
2863               break;
2864             case '\'' :
2865               {
2866                 if (scanner.getNextChar('\\')) {
2867                   scanner.scanEscapeCharacter();
2868                 } else { // consume next character
2869                   scanner.unicodeAsBackSlash = false;
2870                   //                                                                    if (((scanner.currentCharacter = source[scanner.currentPosition++]) == '\\') && (source[scanner.currentPosition] == 'u')) {
2871                   //                                                                            scanner.getNextUnicodeChar();
2872                   //                                                                    } else {
2873                   if (scanner.withoutUnicodePtr != 0) {
2874                     scanner.withoutUnicodeBuffer[++scanner.withoutUnicodePtr] = scanner.currentCharacter;
2875                   }
2876                   //                                                                    }
2877                 }
2878                 scanner.getNextChar('\'');
2879                 break;
2880               }
2881             case '"' : // consume next character
2882               scanner.unicodeAsBackSlash = false;
2883               //                                                        if (((scanner.currentCharacter = source[scanner.currentPosition++]) == '\\') && (source[scanner.currentPosition] == 'u')) {
2884               //                                                                scanner.getNextUnicodeChar();
2885               //                                                        } else {
2886               if (scanner.withoutUnicodePtr != 0) {
2887                 scanner.withoutUnicodeBuffer[++scanner.withoutUnicodePtr] = scanner.currentCharacter;
2888               }
2889               //                                                        }
2890               while (scanner.currentCharacter != '"') {
2891                 if (scanner.currentCharacter == '\r') {
2892                   if (source[scanner.currentPosition] == '\n')
2893                     scanner.currentPosition++;
2894                   break; // the string cannot go further that the line
2895                 }
2896                 if (scanner.currentCharacter == '\n') {
2897                   break; // the string cannot go further that the line
2898                 }
2899                 if (scanner.currentCharacter == '\\') {
2900                   scanner.scanEscapeCharacter();
2901                 }
2902                 // consume next character
2903                 scanner.unicodeAsBackSlash = false;
2904                 //                                                              if (((scanner.currentCharacter = source[scanner.currentPosition++]) == '\\') && (source[scanner.currentPosition] == 'u')) {
2905                 //                                                                      scanner.getNextUnicodeChar();
2906                 //                                                              } else {
2907                 if (scanner.withoutUnicodePtr != 0) {
2908                   scanner.withoutUnicodeBuffer[++scanner.withoutUnicodePtr] = scanner.currentCharacter;
2909                 }
2910                 //                                                              }
2911               }
2912               break;
2913             case '/' :
2914               {
2915                 int test;
2916                 if ((test = scanner.getNextChar('/', '*')) == 0) { //line comment 
2917                   //get the next char 
2918                   if (((scanner.currentCharacter = source[scanner.currentPosition++]) == '\\') && (source[scanner.currentPosition] == 'u')) {
2919                     //-------------unicode traitement ------------
2920                     int c1 = 0, c2 = 0, c3 = 0, c4 = 0;
2921                     scanner.currentPosition++;
2922                     while (source[scanner.currentPosition] == 'u') {
2923                       scanner.currentPosition++;
2924                     }
2925                     if ((c1 = Character.getNumericValue(source[scanner.currentPosition++])) > 15
2926                       || c1 < 0
2927                       || (c2 = Character.getNumericValue(source[scanner.currentPosition++])) > 15
2928                       || c2 < 0
2929                       || (c3 = Character.getNumericValue(source[scanner.currentPosition++])) > 15
2930                       || c3 < 0
2931                       || (c4 = Character.getNumericValue(source[scanner.currentPosition++])) > 15
2932                       || c4 < 0) { //error don't care of the value
2933                       scanner.currentCharacter = 'A';
2934                     } //something different from \n and \r
2935                     else {
2936                       scanner.currentCharacter = (char) (((c1 * 16 + c2) * 16 + c3) * 16 + c4);
2937                     }
2938                   }
2939                   while (scanner.currentCharacter != '\r' && scanner.currentCharacter != '\n') {
2940                     //get the next char
2941                     scanner.startPosition = scanner.currentPosition;
2942                     if (((scanner.currentCharacter = source[scanner.currentPosition++]) == '\\') && (source[scanner.currentPosition] == 'u')) {
2943                       //-------------unicode traitement ------------
2944                       int c1 = 0, c2 = 0, c3 = 0, c4 = 0;
2945                       scanner.currentPosition++;
2946                       while (source[scanner.currentPosition] == 'u') {
2947                         scanner.currentPosition++;
2948                       }
2949                       if ((c1 = Character.getNumericValue(source[scanner.currentPosition++])) > 15
2950                         || c1 < 0
2951                         || (c2 = Character.getNumericValue(source[scanner.currentPosition++])) > 15
2952                         || c2 < 0
2953                         || (c3 = Character.getNumericValue(source[scanner.currentPosition++])) > 15
2954                         || c3 < 0
2955                         || (c4 = Character.getNumericValue(source[scanner.currentPosition++])) > 15
2956                         || c4 < 0) { //error don't care of the value
2957                         scanner.currentCharacter = 'A';
2958                       } //something different from \n and \r
2959                       else {
2960                         scanner.currentCharacter = (char) (((c1 * 16 + c2) * 16 + c3) * 16 + c4);
2961                       }
2962                     }
2963                   }
2964                   if (scanner.recordLineSeparator && ((scanner.currentCharacter == '\r') || (scanner.currentCharacter == '\n'))) {
2965                     if (scanner.lineEnds[scanner.linePtr] < scanner.startPosition) {
2966                       // only record line positions we have not recorded yet
2967                       scanner.pushLineSeparator();
2968                       if (this.scanner.taskTags != null) {
2969                         this.scanner.checkTaskTag(this.scanner.getCurrentTokenStartPosition(), this.scanner.getCurrentTokenEndPosition());
2970                       }
2971                     }
2972                   }
2973                   break;
2974                 }
2975                 if (test > 0) { //traditional and annotation comment
2976                   boolean star = false;
2977                   // consume next character
2978                   scanner.unicodeAsBackSlash = false;
2979                   //                                                                    if (((scanner.currentCharacter = source[scanner.currentPosition++]) == '\\') && (source[scanner.currentPosition] == 'u')) {
2980                   //                                                                            scanner.getNextUnicodeChar();
2981                   //                                                                    } else {
2982                   if (scanner.withoutUnicodePtr != 0) {
2983                     scanner.withoutUnicodeBuffer[++scanner.withoutUnicodePtr] = scanner.currentCharacter;
2984                   }
2985                   //                                                                    }
2986                   if (scanner.currentCharacter == '*') {
2987                     star = true;
2988                   }
2989                   //get the next char 
2990                   if (((scanner.currentCharacter = source[scanner.currentPosition++]) == '\\') && (source[scanner.currentPosition] == 'u')) {
2991                     //-------------unicode traitement ------------
2992                     int c1 = 0, c2 = 0, c3 = 0, c4 = 0;
2993                     scanner.currentPosition++;
2994                     while (source[scanner.currentPosition] == 'u') {
2995                       scanner.currentPosition++;
2996                     }
2997                     if ((c1 = Character.getNumericValue(source[scanner.currentPosition++])) > 15
2998                       || c1 < 0
2999                       || (c2 = Character.getNumericValue(source[scanner.currentPosition++])) > 15
3000                       || c2 < 0
3001                       || (c3 = Character.getNumericValue(source[scanner.currentPosition++])) > 15
3002                       || c3 < 0
3003                       || (c4 = Character.getNumericValue(source[scanner.currentPosition++])) > 15
3004                       || c4 < 0) { //error don't care of the value
3005                       scanner.currentCharacter = 'A';
3006                     } //something different from * and /
3007                     else {
3008                       scanner.currentCharacter = (char) (((c1 * 16 + c2) * 16 + c3) * 16 + c4);
3009                     }
3010                   }
3011                   //loop until end of comment */ 
3012                   while ((scanner.currentCharacter != '/') || (!star)) {
3013                     star = scanner.currentCharacter == '*';
3014                     //get next char
3015                     if (((scanner.currentCharacter = source[scanner.currentPosition++]) == '\\') && (source[scanner.currentPosition] == 'u')) {
3016                       //-------------unicode traitement ------------
3017                       int c1 = 0, c2 = 0, c3 = 0, c4 = 0;
3018                       scanner.currentPosition++;
3019                       while (source[scanner.currentPosition] == 'u') {
3020                         scanner.currentPosition++;
3021                       }
3022                       if ((c1 = Character.getNumericValue(source[scanner.currentPosition++])) > 15
3023                         || c1 < 0
3024                         || (c2 = Character.getNumericValue(source[scanner.currentPosition++])) > 15
3025                         || c2 < 0
3026                         || (c3 = Character.getNumericValue(source[scanner.currentPosition++])) > 15
3027                         || c3 < 0
3028                         || (c4 = Character.getNumericValue(source[scanner.currentPosition++])) > 15
3029                         || c4 < 0) { //error don't care of the value
3030                         scanner.currentCharacter = 'A';
3031                       } //something different from * and /
3032                       else {
3033                         scanner.currentCharacter = (char) (((c1 * 16 + c2) * 16 + c3) * 16 + c4);
3034                       }
3035                     }
3036                   }
3037                   if (this.scanner.taskTags != null) {
3038                     this.scanner.checkTaskTag(this.scanner.getCurrentTokenStartPosition(), this.scanner.getCurrentTokenEndPosition());
3039                   }
3040                   break;
3041                 }
3042                 break;
3043               }
3044             default :
3045               if (Scanner.isPHPIdentifierStart(scanner.currentCharacter)) {
3046                 scanner.scanIdentifierOrKeyword(false);
3047                 break;
3048               }
3049               if (Character.isDigit(scanner.currentCharacter)) {
3050                 scanner.scanNumber(false);
3051                 break;
3052               }
3053           }
3054           //-----------------end switch while try--------------------
3055         } catch (IndexOutOfBoundsException e) {
3056           break; // read until EOF
3057         } catch (InvalidInputException e) {
3058           return false; // no clue
3059         }
3060       }
3061       if (scanner.recordLineSeparator) {
3062         //                              compilationUnit.compilationResult.lineSeparatorPositions = scanner.getLineEnds();
3063       }
3064
3065       // check placement anomalies against other kinds of brackets
3066       for (int kind = 0; kind < BracketKinds; kind++) {
3067         for (int leftIndex = leftCount[kind] - 1; leftIndex >= 0; leftIndex--) {
3068           int start = leftPositions[kind][leftIndex]; // deepest first
3069           // find matching closing bracket
3070           int depth = leftDepths[kind][leftIndex];
3071           int end = -1;
3072           for (int i = 0; i < rightCount[kind]; i++) {
3073             int pos = rightPositions[kind][i];
3074             // want matching bracket further in source with same depth
3075             if ((pos > start) && (depth == rightDepths[kind][i])) {
3076               end = pos;
3077               break;
3078             }
3079           }
3080           if (end < 0) { // did not find a good closing match
3081             problemReporter.unmatchedBracket(start, referenceContext, compilationUnit.compilationResult);
3082             return true;
3083           }
3084           // check if even number of opening/closing other brackets in between this pair of brackets
3085           int balance = 0;
3086           for (int otherKind = 0;(balance == 0) && (otherKind < BracketKinds); otherKind++) {
3087             for (int i = 0; i < leftCount[otherKind]; i++) {
3088               int pos = leftPositions[otherKind][i];
3089               if ((pos > start) && (pos < end))
3090                 balance++;
3091             }
3092             for (int i = 0; i < rightCount[otherKind]; i++) {
3093               int pos = rightPositions[otherKind][i];
3094               if ((pos > start) && (pos < end))
3095                 balance--;
3096             }
3097             if (balance != 0) {
3098               problemReporter.unmatchedBracket(start, referenceContext, compilationUnit.compilationResult); //bracket anomaly
3099               return true;
3100             }
3101           }
3102         }
3103         // too many opening brackets ?
3104         for (int i = rightCount[kind]; i < leftCount[kind]; i++) {
3105           anomaliesDetected = true;
3106           problemReporter.unmatchedBracket(leftPositions[kind][leftCount[kind] - i - 1], referenceContext, compilationUnit.compilationResult);
3107         }
3108         // too many closing brackets ?
3109         for (int i = leftCount[kind]; i < rightCount[kind]; i++) {
3110           anomaliesDetected = true;
3111           problemReporter.unmatchedBracket(rightPositions[kind][i], referenceContext, compilationUnit.compilationResult);
3112         }
3113         if (anomaliesDetected)
3114           return true;
3115       }
3116
3117       return anomaliesDetected;
3118     } catch (ArrayStoreException e) { // jdk1.2.2 jit bug
3119       return anomaliesDetected;
3120     } catch (NullPointerException e) { // jdk1.2.2 jit bug
3121       return anomaliesDetected;
3122     }
3123   }
3124
3125   protected void pushOnAstLengthStack(int pos) {
3126     try {
3127       astLengthStack[++astLengthPtr] = pos;
3128     } catch (IndexOutOfBoundsException e) {
3129       int oldStackLength = astLengthStack.length;
3130       int[] oldPos = astLengthStack;
3131       astLengthStack = new int[oldStackLength + StackIncrement];
3132       System.arraycopy(oldPos, 0, astLengthStack, 0, oldStackLength);
3133       astLengthStack[astLengthPtr] = pos;
3134     }
3135   }
3136
3137   protected void pushOnAstStack(AstNode node) {
3138     /*add a new obj on top of the ast stack
3139     astPtr points on the top*/
3140
3141     try {
3142       astStack[++astPtr] = node;
3143     } catch (IndexOutOfBoundsException e) {
3144       int oldStackLength = astStack.length;
3145       AstNode[] oldStack = astStack;
3146       astStack = new AstNode[oldStackLength + AstStackIncrement];
3147       System.arraycopy(oldStack, 0, astStack, 0, oldStackLength);
3148       astPtr = oldStackLength;
3149       astStack[astPtr] = node;
3150     }
3151
3152     try {
3153       astLengthStack[++astLengthPtr] = 1;
3154     } catch (IndexOutOfBoundsException e) {
3155       int oldStackLength = astLengthStack.length;
3156       int[] oldPos = astLengthStack;
3157       astLengthStack = new int[oldStackLength + AstStackIncrement];
3158       System.arraycopy(oldPos, 0, astLengthStack, 0, oldStackLength);
3159       astLengthStack[astLengthPtr] = 1;
3160     }
3161   }
3162 }