misc changes
[phpeclipse.git] / net.sourceforge.phpeclipse / src / net / sourceforge / phpdt / internal / compiler / parser / Scanner.java
1 /*******************************************************************************
2  * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others.
3  * All rights reserved. This program and the accompanying materials 
4  * are made available under the terms of the Common Public License v0.5 
5  * which accompanies this distribution, and is available at
6  * http://www.eclipse.org/legal/cpl-v05.html
7  * 
8  * Contributors:
9  *     IBM Corporation - initial API and implementation
10  ******************************************************************************/
11 package net.sourceforge.phpdt.internal.compiler.parser;
12 import java.util.ArrayList;
13 import java.util.Iterator;
14 import java.util.List;
15 import java.util.Stack;
16 import net.sourceforge.phpdt.core.compiler.CharOperation;
17 import net.sourceforge.phpdt.core.compiler.IScanner;
18 import net.sourceforge.phpdt.core.compiler.ITerminalSymbols;
19 import net.sourceforge.phpdt.core.compiler.InvalidInputException;
20 import net.sourceforge.phpdt.internal.compiler.ast.StringLiteral;
21 public class Scanner implements IScanner, ITerminalSymbols {
22   /*
23    * APIs ares - getNextToken() which return the current type of the token
24    * (this value is not memorized by the scanner) - getCurrentTokenSource()
25    * which provides with the token "REAL" source (aka all unicode have been
26    * transformed into a correct char) - sourceStart gives the position into the
27    * stream - currentPosition-1 gives the sourceEnd position into the stream
28    */
29   // 1.4 feature
30   private boolean assertMode;
31   public boolean useAssertAsAnIndentifier = false;
32   //flag indicating if processed source contains occurrences of keyword assert
33   public boolean containsAssertKeyword = false;
34   public boolean recordLineSeparator;
35   public boolean phpMode = false;
36   public Stack encapsedStringStack = null;
37   public char currentCharacter;
38   public int startPosition;
39   public int currentPosition;
40   public int initialPosition, eofPosition;
41   // after this position eof are generated instead of real token from the
42   // source
43   public boolean tokenizeComments;
44   public boolean tokenizeWhiteSpace;
45   public boolean tokenizeStrings;
46   //source should be viewed as a window (aka a part)
47   //of a entire very large stream
48   public char source[];
49   //unicode support
50   public char[] withoutUnicodeBuffer;
51   public int withoutUnicodePtr;
52   //when == 0 ==> no unicode in the current token
53   public boolean unicodeAsBackSlash = false;
54   public boolean scanningFloatLiteral = false;
55   //support for /** comments
56   //public char[][] comments = new char[10][];
57   public int[] commentStops = new int[10];
58   public int[] commentStarts = new int[10];
59   public int commentPtr = -1; // no comment test with commentPtr value -1
60   //diet parsing support - jump over some method body when requested
61   public boolean diet = false;
62   //support for the poor-line-debuggers ....
63   //remember the position of the cr/lf
64   public int[] lineEnds = new int[250];
65   public int linePtr = -1;
66   public boolean wasAcr = false;
67   public static final String END_OF_SOURCE = "End_Of_Source"; //$NON-NLS-1$
68   public static final String INVALID_HEXA = "Invalid_Hexa_Literal"; //$NON-NLS-1$
69   public static final String INVALID_OCTAL = "Invalid_Octal_Literal"; //$NON-NLS-1$
70   public static final String INVALID_CHARACTER_CONSTANT = "Invalid_Character_Constant"; //$NON-NLS-1$
71   public static final String INVALID_ESCAPE = "Invalid_Escape"; //$NON-NLS-1$
72   public static final String INVALID_INPUT = "Invalid_Input"; //$NON-NLS-1$
73   public static final String INVALID_UNICODE_ESCAPE = "Invalid_Unicode_Escape"; //$NON-NLS-1$
74   public static final String INVALID_FLOAT = "Invalid_Float_Literal"; //$NON-NLS-1$
75   public static final String NULL_SOURCE_STRING = "Null_Source_String"; //$NON-NLS-1$
76   public static final String UNTERMINATED_STRING = "Unterminated_String"; //$NON-NLS-1$
77   public static final String UNTERMINATED_COMMENT = "Unterminated_Comment"; //$NON-NLS-1$
78   public static final String INVALID_CHAR_IN_STRING = "Invalid_Char_In_String"; //$NON-NLS-1$
79   //----------------optimized identifier managment------------------
80   static final char[] charArray_a = new char[]{'a'},
81       charArray_b = new char[]{'b'}, charArray_c = new char[]{'c'},
82       charArray_d = new char[]{'d'}, charArray_e = new char[]{'e'},
83       charArray_f = new char[]{'f'}, charArray_g = new char[]{'g'},
84       charArray_h = new char[]{'h'}, charArray_i = new char[]{'i'},
85       charArray_j = new char[]{'j'}, charArray_k = new char[]{'k'},
86       charArray_l = new char[]{'l'}, charArray_m = new char[]{'m'},
87       charArray_n = new char[]{'n'}, charArray_o = new char[]{'o'},
88       charArray_p = new char[]{'p'}, charArray_q = new char[]{'q'},
89       charArray_r = new char[]{'r'}, charArray_s = new char[]{'s'},
90       charArray_t = new char[]{'t'}, charArray_u = new char[]{'u'},
91       charArray_v = new char[]{'v'}, charArray_w = new char[]{'w'},
92       charArray_x = new char[]{'x'}, charArray_y = new char[]{'y'},
93       charArray_z = new char[]{'z'};
94   static final char[] initCharArray = new char[]{'\u0000', '\u0000', '\u0000',
95       '\u0000', '\u0000', '\u0000'};
96   static final int TableSize = 30, InternalTableSize = 6;
97   //30*6 = 180 entries
98   public static final int OptimizedLength = 6;
99   public/* static */
100   final char[][][][] charArray_length = new char[OptimizedLength][TableSize][InternalTableSize][];
101   // support for detecting non-externalized string literals
102   int currentLineNr = -1;
103   int previousLineNr = -1;
104   NLSLine currentLine = null;
105   List lines = new ArrayList();
106   public static final String TAG_PREFIX = "//$NON-NLS-"; //$NON-NLS-1$
107   public static final int TAG_PREFIX_LENGTH = TAG_PREFIX.length();
108   public static final String TAG_POSTFIX = "$"; //$NON-NLS-1$
109   public static final int TAG_POSTFIX_LENGTH = TAG_POSTFIX.length();
110   public StringLiteral[] nonNLSStrings = null;
111   public boolean checkNonExternalizedStringLiterals = true;
112   public boolean wasNonExternalizedStringLiteral = false;
113   /* static */{
114     for (int i = 0; i < 6; i++) {
115       for (int j = 0; j < TableSize; j++) {
116         for (int k = 0; k < InternalTableSize; k++) {
117           charArray_length[i][j][k] = initCharArray;
118         }
119       }
120     }
121   }
122   static int newEntry2 = 0, newEntry3 = 0, newEntry4 = 0, newEntry5 = 0,
123       newEntry6 = 0;
124   public static final int RoundBracket = 0;
125   public static final int SquareBracket = 1;
126   public static final int CurlyBracket = 2;
127   public static final int BracketKinds = 3;
128   // task tag support
129   public char[][] foundTaskTags = null;
130   public char[][] foundTaskMessages;
131   public char[][] foundTaskPriorities = null;
132   public int[][] foundTaskPositions;
133   public int foundTaskCount = 0;
134   public char[][] taskTags = null;
135   public char[][] taskPriorities = null;
136   public static final boolean DEBUG = false;
137   public static final boolean TRACE = false;
138   public Scanner() {
139     this(false, false);
140   }
141   public Scanner(boolean tokenizeComments, boolean tokenizeWhiteSpace) {
142     this(tokenizeComments, tokenizeWhiteSpace, false);
143   }
144   /**
145    * Determines if the specified character is permissible as the first
146    * character in a PHP identifier
147    */
148   public static boolean isPHPIdentifierStart(char ch) {
149     return Character.isLetter(ch) || (ch == '_') || (0x7F <= ch && ch <= 0xFF);
150   }
151   /**
152    * Determines if the specified character may be part of a PHP identifier as
153    * other than the first character
154    */
155   public static boolean isPHPIdentifierPart(char ch) {
156     return Character.isLetterOrDigit(ch) || (ch == '_')
157         || (0x7F <= ch && ch <= 0xFF);
158   }
159   public final boolean atEnd() {
160     // This code is not relevant if source is
161     // Only a part of the real stream input
162     return source.length == currentPosition;
163   }
164   public char[] getCurrentIdentifierSource() {
165     //return the token REAL source (aka unicodes are precomputed)
166     char[] result;
167     //    if (withoutUnicodePtr != 0)
168     //      //0 is used as a fast test flag so the real first char is in position 1
169     //      System.arraycopy(
170     //        withoutUnicodeBuffer,
171     //        1,
172     //        result = new char[withoutUnicodePtr],
173     //        0,
174     //        withoutUnicodePtr);
175     //    else {
176     int length = currentPosition - startPosition;
177     switch (length) { // see OptimizedLength
178       case 1 :
179         return optimizedCurrentTokenSource1();
180       case 2 :
181         return optimizedCurrentTokenSource2();
182       case 3 :
183         return optimizedCurrentTokenSource3();
184       case 4 :
185         return optimizedCurrentTokenSource4();
186       case 5 :
187         return optimizedCurrentTokenSource5();
188       case 6 :
189         return optimizedCurrentTokenSource6();
190     }
191     //no optimization
192     System.arraycopy(source, startPosition, result = new char[length], 0,
193         length);
194     //   }
195     return result;
196   }
197   public int getCurrentTokenEndPosition() {
198     return this.currentPosition - 1;
199   }
200   public final char[] getCurrentTokenSource() {
201     // Return the token REAL source (aka unicodes are precomputed)
202     char[] result;
203     //    if (withoutUnicodePtr != 0)
204     //      // 0 is used as a fast test flag so the real first char is in position 1
205     //      System.arraycopy(
206     //        withoutUnicodeBuffer,
207     //        1,
208     //        result = new char[withoutUnicodePtr],
209     //        0,
210     //        withoutUnicodePtr);
211     //    else {
212     int length;
213     System.arraycopy(source, startPosition,
214         result = new char[length = currentPosition - startPosition], 0, length);
215     //    }
216     return result;
217   }
218   public final char[] getCurrentTokenSource(int startPos) {
219     // Return the token REAL source (aka unicodes are precomputed)
220     char[] result;
221     //    if (withoutUnicodePtr != 0)
222     //      // 0 is used as a fast test flag so the real first char is in position 1
223     //      System.arraycopy(
224     //        withoutUnicodeBuffer,
225     //        1,
226     //        result = new char[withoutUnicodePtr],
227     //        0,
228     //        withoutUnicodePtr);
229     //    else {
230     int length;
231     System.arraycopy(source, startPos,
232         result = new char[length = currentPosition - startPos], 0, length);
233     //  }
234     return result;
235   }
236   public final char[] getCurrentTokenSourceString() {
237     //return the token REAL source (aka unicodes are precomputed).
238     //REMOVE the two " that are at the beginning and the end.
239     char[] result;
240     if (withoutUnicodePtr != 0)
241       //0 is used as a fast test flag so the real first char is in position 1
242       System.arraycopy(withoutUnicodeBuffer, 2, 
243       //2 is 1 (real start) + 1 (to jump over the ")
244           result = new char[withoutUnicodePtr - 2], 0, withoutUnicodePtr - 2);
245     else {
246       int length;
247       System.arraycopy(source, startPosition + 1,
248           result = new char[length = currentPosition - startPosition - 2], 0,
249           length);
250     }
251     return result;
252   }
253   public int getCurrentTokenStartPosition() {
254     return this.startPosition;
255   }
256   public final char[] getCurrentStringLiteralSource() {
257     // Return the token REAL source (aka unicodes are precomputed)
258     char[] result;
259     int length;
260     System.arraycopy(source, startPosition + 1,
261         result = new char[length = currentPosition - startPosition - 2], 0,
262         length);
263     //    }
264     return result;
265   }
266   /*
267    * Search the source position corresponding to the end of a given line number
268    * 
269    * Line numbers are 1-based, and relative to the scanner initialPosition.
270    * Character positions are 0-based.
271    * 
272    * In case the given line number is inconsistent, answers -1.
273    */
274   public final int getLineEnd(int lineNumber) {
275     if (lineEnds == null)
276       return -1;
277     if (lineNumber >= lineEnds.length)
278       return -1;
279     if (lineNumber <= 0)
280       return -1;
281     if (lineNumber == lineEnds.length - 1)
282       return eofPosition;
283     return lineEnds[lineNumber - 1];
284     // next line start one character behind the lineEnd of the previous line
285   }
286   /**
287    * Search the source position corresponding to the beginning of a given line
288    * number
289    * 
290    * Line numbers are 1-based, and relative to the scanner initialPosition.
291    * Character positions are 0-based.
292    * 
293    * e.g. getLineStart(1) --> 0 i.e. first line starts at character 0.
294    * 
295    * In case the given line number is inconsistent, answers -1.
296    */
297   public final int getLineStart(int lineNumber) {
298     if (lineEnds == null)
299       return -1;
300     if (lineNumber >= lineEnds.length)
301       return -1;
302     if (lineNumber <= 0)
303       return -1;
304     if (lineNumber == 1)
305       return initialPosition;
306     return lineEnds[lineNumber - 2] + 1;
307     // next line start one character behind the lineEnd of the previous line
308   }
309   public final boolean getNextChar(char testedChar) {
310     //BOOLEAN
311     //handle the case of unicode.
312     //when a unicode appears then we must use a buffer that holds char
313     // internal values
314     //At the end of this method currentCharacter holds the new visited char
315     //and currentPosition points right next after it
316     //Both previous lines are true if the currentCharacter is == to the
317     // testedChar
318     //On false, no side effect has occured.
319     //ALL getNextChar.... ARE OPTIMIZED COPIES
320     int temp = currentPosition;
321     try {
322       currentCharacter = source[currentPosition++];
323       //      if (((currentCharacter = source[currentPosition++]) == '\\')
324       //        && (source[currentPosition] == 'u')) {
325       //        //-------------unicode traitement ------------
326       //        int c1, c2, c3, c4;
327       //        int unicodeSize = 6;
328       //        currentPosition++;
329       //        while (source[currentPosition] == 'u') {
330       //          currentPosition++;
331       //          unicodeSize++;
332       //        }
333       //
334       //        if (((c1 = Character.getNumericValue(source[currentPosition++])) > 15
335       //          || c1 < 0)
336       //          || ((c2 = Character.getNumericValue(source[currentPosition++])) > 15
337       //            || c2 < 0)
338       //          || ((c3 = Character.getNumericValue(source[currentPosition++])) > 15
339       //            || c3 < 0)
340       //          || ((c4 = Character.getNumericValue(source[currentPosition++])) > 15
341       //            || c4 < 0)) {
342       //          currentPosition = temp;
343       //          return false;
344       //        }
345       //
346       //        currentCharacter = (char) (((c1 * 16 + c2) * 16 + c3) * 16 + c4);
347       //        if (currentCharacter != testedChar) {
348       //          currentPosition = temp;
349       //          return false;
350       //        }
351       //        unicodeAsBackSlash = currentCharacter == '\\';
352       //
353       //        //need the unicode buffer
354       //        if (withoutUnicodePtr == 0) {
355       //          //buffer all the entries that have been left aside....
356       //          withoutUnicodePtr = currentPosition - unicodeSize - startPosition;
357       //          System.arraycopy(
358       //            source,
359       //            startPosition,
360       //            withoutUnicodeBuffer,
361       //            1,
362       //            withoutUnicodePtr);
363       //        }
364       //        //fill the buffer with the char
365       //        withoutUnicodeBuffer[++withoutUnicodePtr] = currentCharacter;
366       //        return true;
367       //
368       //      } //-------------end unicode traitement--------------
369       //      else {
370       if (currentCharacter != testedChar) {
371         currentPosition = temp;
372         return false;
373       }
374       unicodeAsBackSlash = false;
375       //        if (withoutUnicodePtr != 0)
376       //          withoutUnicodeBuffer[++withoutUnicodePtr] = currentCharacter;
377       return true;
378       //      }
379     } catch (IndexOutOfBoundsException e) {
380       unicodeAsBackSlash = false;
381       currentPosition = temp;
382       return false;
383     }
384   }
385   public final int getNextChar(char testedChar1, char testedChar2) {
386     //INT 0 : testChar1 \\\\///\\\\ 1 : testedChar2 \\\\///\\\\ -1 : others
387     //test can be done with (x==0) for the first and (x>0) for the second
388     //handle the case of unicode.
389     //when a unicode appears then we must use a buffer that holds char
390     // internal values
391     //At the end of this method currentCharacter holds the new visited char
392     //and currentPosition points right next after it
393     //Both previous lines are true if the currentCharacter is == to the
394     // testedChar1/2
395     //On false, no side effect has occured.
396     //ALL getNextChar.... ARE OPTIMIZED COPIES
397     int temp = currentPosition;
398     try {
399       int result;
400       currentCharacter = source[currentPosition++];
401       //      if (((currentCharacter = source[currentPosition++]) == '\\')
402       //        && (source[currentPosition] == 'u')) {
403       //        //-------------unicode traitement ------------
404       //        int c1, c2, c3, c4;
405       //        int unicodeSize = 6;
406       //        currentPosition++;
407       //        while (source[currentPosition] == 'u') {
408       //          currentPosition++;
409       //          unicodeSize++;
410       //        }
411       //
412       //        if (((c1 = Character.getNumericValue(source[currentPosition++])) > 15
413       //          || c1 < 0)
414       //          || ((c2 = Character.getNumericValue(source[currentPosition++])) > 15
415       //            || c2 < 0)
416       //          || ((c3 = Character.getNumericValue(source[currentPosition++])) > 15
417       //            || c3 < 0)
418       //          || ((c4 = Character.getNumericValue(source[currentPosition++])) > 15
419       //            || c4 < 0)) {
420       //          currentPosition = temp;
421       //          return 2;
422       //        }
423       //
424       //        currentCharacter = (char) (((c1 * 16 + c2) * 16 + c3) * 16 + c4);
425       //        if (currentCharacter == testedChar1)
426       //          result = 0;
427       //        else if (currentCharacter == testedChar2)
428       //          result = 1;
429       //        else {
430       //          currentPosition = temp;
431       //          return -1;
432       //        }
433       //
434       //        //need the unicode buffer
435       //        if (withoutUnicodePtr == 0) {
436       //          //buffer all the entries that have been left aside....
437       //          withoutUnicodePtr = currentPosition - unicodeSize - startPosition;
438       //          System.arraycopy(
439       //            source,
440       //            startPosition,
441       //            withoutUnicodeBuffer,
442       //            1,
443       //            withoutUnicodePtr);
444       //        }
445       //        //fill the buffer with the char
446       //        withoutUnicodeBuffer[++withoutUnicodePtr] = currentCharacter;
447       //        return result;
448       //      } //-------------end unicode traitement--------------
449       //      else {
450       if (currentCharacter == testedChar1)
451         result = 0;
452       else if (currentCharacter == testedChar2)
453         result = 1;
454       else {
455         currentPosition = temp;
456         return -1;
457       }
458       //        if (withoutUnicodePtr != 0)
459       //          withoutUnicodeBuffer[++withoutUnicodePtr] = currentCharacter;
460       return result;
461       //     }
462     } catch (IndexOutOfBoundsException e) {
463       currentPosition = temp;
464       return -1;
465     }
466   }
467   public final boolean getNextCharAsDigit() {
468     //BOOLEAN
469     //handle the case of unicode.
470     //when a unicode appears then we must use a buffer that holds char
471     // internal values
472     //At the end of this method currentCharacter holds the new visited char
473     //and currentPosition points right next after it
474     //Both previous lines are true if the currentCharacter is a digit
475     //On false, no side effect has occured.
476     //ALL getNextChar.... ARE OPTIMIZED COPIES
477     int temp = currentPosition;
478     try {
479       currentCharacter = source[currentPosition++];
480       //      if (((currentCharacter = source[currentPosition++]) == '\\')
481       //        && (source[currentPosition] == 'u')) {
482       //        //-------------unicode traitement ------------
483       //        int c1, c2, c3, c4;
484       //        int unicodeSize = 6;
485       //        currentPosition++;
486       //        while (source[currentPosition] == 'u') {
487       //          currentPosition++;
488       //          unicodeSize++;
489       //        }
490       //
491       //        if (((c1 = Character.getNumericValue(source[currentPosition++])) > 15
492       //          || c1 < 0)
493       //          || ((c2 = Character.getNumericValue(source[currentPosition++])) > 15
494       //            || c2 < 0)
495       //          || ((c3 = Character.getNumericValue(source[currentPosition++])) > 15
496       //            || c3 < 0)
497       //          || ((c4 = Character.getNumericValue(source[currentPosition++])) > 15
498       //            || c4 < 0)) {
499       //          currentPosition = temp;
500       //          return false;
501       //        }
502       //
503       //        currentCharacter = (char) (((c1 * 16 + c2) * 16 + c3) * 16 + c4);
504       //        if (!Character.isDigit(currentCharacter)) {
505       //          currentPosition = temp;
506       //          return false;
507       //        }
508       //
509       //        //need the unicode buffer
510       //        if (withoutUnicodePtr == 0) {
511       //          //buffer all the entries that have been left aside....
512       //          withoutUnicodePtr = currentPosition - unicodeSize - startPosition;
513       //          System.arraycopy(
514       //            source,
515       //            startPosition,
516       //            withoutUnicodeBuffer,
517       //            1,
518       //            withoutUnicodePtr);
519       //        }
520       //        //fill the buffer with the char
521       //        withoutUnicodeBuffer[++withoutUnicodePtr] = currentCharacter;
522       //        return true;
523       //      } //-------------end unicode traitement--------------
524       //      else {
525       if (!Character.isDigit(currentCharacter)) {
526         currentPosition = temp;
527         return false;
528       }
529       //        if (withoutUnicodePtr != 0)
530       //          withoutUnicodeBuffer[++withoutUnicodePtr] = currentCharacter;
531       return true;
532       //      }
533     } catch (IndexOutOfBoundsException e) {
534       currentPosition = temp;
535       return false;
536     }
537   }
538   public final boolean getNextCharAsDigit(int radix) {
539     //BOOLEAN
540     //handle the case of unicode.
541     //when a unicode appears then we must use a buffer that holds char
542     // internal values
543     //At the end of this method currentCharacter holds the new visited char
544     //and currentPosition points right next after it
545     //Both previous lines are true if the currentCharacter is a digit base on
546     // radix
547     //On false, no side effect has occured.
548     //ALL getNextChar.... ARE OPTIMIZED COPIES
549     int temp = currentPosition;
550     try {
551       currentCharacter = source[currentPosition++];
552       //      if (((currentCharacter = source[currentPosition++]) == '\\')
553       //        && (source[currentPosition] == 'u')) {
554       //        //-------------unicode traitement ------------
555       //        int c1, c2, c3, c4;
556       //        int unicodeSize = 6;
557       //        currentPosition++;
558       //        while (source[currentPosition] == 'u') {
559       //          currentPosition++;
560       //          unicodeSize++;
561       //        }
562       //
563       //        if (((c1 = Character.getNumericValue(source[currentPosition++])) > 15
564       //          || c1 < 0)
565       //          || ((c2 = Character.getNumericValue(source[currentPosition++])) > 15
566       //            || c2 < 0)
567       //          || ((c3 = Character.getNumericValue(source[currentPosition++])) > 15
568       //            || c3 < 0)
569       //          || ((c4 = Character.getNumericValue(source[currentPosition++])) > 15
570       //            || c4 < 0)) {
571       //          currentPosition = temp;
572       //          return false;
573       //        }
574       //
575       //        currentCharacter = (char) (((c1 * 16 + c2) * 16 + c3) * 16 + c4);
576       //        if (Character.digit(currentCharacter, radix) == -1) {
577       //          currentPosition = temp;
578       //          return false;
579       //        }
580       //
581       //        //need the unicode buffer
582       //        if (withoutUnicodePtr == 0) {
583       //          //buffer all the entries that have been left aside....
584       //          withoutUnicodePtr = currentPosition - unicodeSize - startPosition;
585       //          System.arraycopy(
586       //            source,
587       //            startPosition,
588       //            withoutUnicodeBuffer,
589       //            1,
590       //            withoutUnicodePtr);
591       //        }
592       //        //fill the buffer with the char
593       //        withoutUnicodeBuffer[++withoutUnicodePtr] = currentCharacter;
594       //        return true;
595       //      } //-------------end unicode traitement--------------
596       //      else {
597       if (Character.digit(currentCharacter, radix) == -1) {
598         currentPosition = temp;
599         return false;
600       }
601       //        if (withoutUnicodePtr != 0)
602       //          withoutUnicodeBuffer[++withoutUnicodePtr] = currentCharacter;
603       return true;
604       //      }
605     } catch (IndexOutOfBoundsException e) {
606       currentPosition = temp;
607       return false;
608     }
609   }
610   public boolean getNextCharAsJavaIdentifierPart() {
611     //BOOLEAN
612     //handle the case of unicode.
613     //when a unicode appears then we must use a buffer that holds char
614     // internal values
615     //At the end of this method currentCharacter holds the new visited char
616     //and currentPosition points right next after it
617     //Both previous lines are true if the currentCharacter is a
618     // JavaIdentifierPart
619     //On false, no side effect has occured.
620     //ALL getNextChar.... ARE OPTIMIZED COPIES
621     int temp = currentPosition;
622     try {
623       currentCharacter = source[currentPosition++];
624       //      if (((currentCharacter = source[currentPosition++]) == '\\')
625       //        && (source[currentPosition] == 'u')) {
626       //        //-------------unicode traitement ------------
627       //        int c1, c2, c3, c4;
628       //        int unicodeSize = 6;
629       //        currentPosition++;
630       //        while (source[currentPosition] == 'u') {
631       //          currentPosition++;
632       //          unicodeSize++;
633       //        }
634       //
635       //        if (((c1 = Character.getNumericValue(source[currentPosition++])) > 15
636       //          || c1 < 0)
637       //          || ((c2 = Character.getNumericValue(source[currentPosition++])) > 15
638       //            || c2 < 0)
639       //          || ((c3 = Character.getNumericValue(source[currentPosition++])) > 15
640       //            || c3 < 0)
641       //          || ((c4 = Character.getNumericValue(source[currentPosition++])) > 15
642       //            || c4 < 0)) {
643       //          currentPosition = temp;
644       //          return false;
645       //        }
646       //
647       //        currentCharacter = (char) (((c1 * 16 + c2) * 16 + c3) * 16 + c4);
648       //        if (!isPHPIdentifierPart(currentCharacter)) {
649       //          currentPosition = temp;
650       //          return false;
651       //        }
652       //
653       //        //need the unicode buffer
654       //        if (withoutUnicodePtr == 0) {
655       //          //buffer all the entries that have been left aside....
656       //          withoutUnicodePtr = currentPosition - unicodeSize - startPosition;
657       //          System.arraycopy(
658       //            source,
659       //            startPosition,
660       //            withoutUnicodeBuffer,
661       //            1,
662       //            withoutUnicodePtr);
663       //        }
664       //        //fill the buffer with the char
665       //        withoutUnicodeBuffer[++withoutUnicodePtr] = currentCharacter;
666       //        return true;
667       //      } //-------------end unicode traitement--------------
668       //      else {
669       if (!isPHPIdentifierPart(currentCharacter)) {
670         currentPosition = temp;
671         return false;
672       }
673       //        if (withoutUnicodePtr != 0)
674       //          withoutUnicodeBuffer[++withoutUnicodePtr] = currentCharacter;
675       return true;
676       //      }
677     } catch (IndexOutOfBoundsException e) {
678       currentPosition = temp;
679       return false;
680     }
681   }
682   public int getCastOrParen() {
683     int tempPosition = currentPosition;
684     char tempCharacter = currentCharacter;
685     int tempToken = TokenNameLPAREN;
686     boolean found = false;
687     StringBuffer buf = new StringBuffer();
688     try {
689       do {
690         currentCharacter = source[currentPosition++];
691       } while (currentCharacter == ' ' || currentCharacter == '\t');
692       while ((currentCharacter >= 'a' && currentCharacter <= 'z')
693           || (currentCharacter >= 'A' && currentCharacter <= 'Z')) {
694         buf.append(currentCharacter);
695         currentCharacter = source[currentPosition++];
696       }
697       if (buf.length() >= 3 && buf.length() <= 7) {
698         char[] data = buf.toString().toCharArray();
699         int index = 0;
700         switch (data.length) {
701           case 3 :
702             // int
703             if ((data[index] == 'i') && (data[++index] == 'n')
704                 && (data[++index] == 't')) {
705               found = true;
706               tempToken = TokenNameintCAST;
707             }
708             break;
709           case 4 :
710             // bool real
711             if ((data[index] == 'b') && (data[++index] == 'o')
712                 && (data[++index] == 'o') && (data[++index] == 'l')) {
713               found = true;
714               tempToken = TokenNameboolCAST;
715             } else {
716               index = 0;
717               if ((data[index] == 'r') && (data[++index] == 'e')
718                   && (data[++index] == 'a') && (data[++index] == 'l')) {
719                 found = true;
720                 tempToken = TokenNamedoubleCAST;
721               }
722             }
723             break;
724           case 5 :
725             // array unset float
726             if ((data[index] == 'a') && (data[++index] == 'r')
727                 && (data[++index] == 'r') && (data[++index] == 'a')
728                 && (data[++index] == 'y')) {
729               found = true;
730               tempToken = TokenNamearrayCAST;
731             } else {
732               index = 0;
733               if ((data[index] == 'u') && (data[++index] == 'n')
734                   && (data[++index] == 's') && (data[++index] == 'e')
735                   && (data[++index] == 't')) {
736                 found = true;
737                 tempToken = TokenNameunsetCAST;
738               } else {
739                 index = 0;
740                 if ((data[index] == 'f') && (data[++index] == 'l')
741                     && (data[++index] == 'o') && (data[++index] == 'a')
742                     && (data[++index] == 't')) {
743                   found = true;
744                   tempToken = TokenNamedoubleCAST;
745                 }
746               }
747             }
748             break;
749           case 6 :
750             // object string double
751             if ((data[index] == 'o') && (data[++index] == 'b')
752                 && (data[++index] == 'j') && (data[++index] == 'e')
753                 && (data[++index] == 'c') && (data[++index] == 't')) {
754               found = true;
755               tempToken = TokenNameobjectCAST;
756             } else {
757               index = 0;
758               if ((data[index] == 's') && (data[++index] == 't')
759                   && (data[++index] == 'r') && (data[++index] == 'i')
760                   && (data[++index] == 'n') && (data[++index] == 'g')) {
761                 found = true;
762                 tempToken = TokenNamestringCAST;
763               } else {
764                 index = 0;
765                 if ((data[index] == 'd') && (data[++index] == 'o')
766                     && (data[++index] == 'u') && (data[++index] == 'b')
767                     && (data[++index] == 'l') && (data[++index] == 'e')) {
768                   found = true;
769                   tempToken = TokenNamedoubleCAST;
770                 }
771               }
772             }
773             break;
774           case 7 :
775             // boolean integer
776             if ((data[index] == 'b') && (data[++index] == 'o')
777                 && (data[++index] == 'o') && (data[++index] == 'l')
778                 && (data[++index] == 'e') && (data[++index] == 'a')
779                 && (data[++index] == 'n')) {
780               found = true;
781               tempToken = TokenNameboolCAST;
782             } else {
783               index = 0;
784               if ((data[index] == 'i') && (data[++index] == 'n')
785                   && (data[++index] == 't') && (data[++index] == 'e')
786                   && (data[++index] == 'g') && (data[++index] == 'e')
787                   && (data[++index] == 'r')) {
788                 found = true;
789                 tempToken = TokenNameintCAST;
790               }
791             }
792             break;
793         }
794         if (found) {
795           while (currentCharacter == ' ' || currentCharacter == '\t') {
796             currentCharacter = source[currentPosition++];
797           }
798           if (currentCharacter == ')') {
799             return tempToken;
800           }
801         }
802       }
803     } catch (IndexOutOfBoundsException e) {
804     }
805     currentCharacter = tempCharacter;
806     currentPosition = tempPosition;
807     return TokenNameLPAREN;
808   }
809   public void consumeStringInterpolated() throws InvalidInputException {
810     try {
811       // consume next character
812       unicodeAsBackSlash = false;
813       currentCharacter = source[currentPosition++];
814       //                if (((currentCharacter = source[currentPosition++]) == '\\')
815       //                  && (source[currentPosition] == 'u')) {
816       //                  getNextUnicodeChar();
817       //                } else {
818       //                  if (withoutUnicodePtr != 0) {
819       //                    withoutUnicodeBuffer[++withoutUnicodePtr] =
820       //                      currentCharacter;
821       //                  }
822       //                }
823       while (currentCharacter != '`') {
824         /** ** in PHP \r and \n are valid in string literals *** */
825         //                if ((currentCharacter == '\n')
826         //                  || (currentCharacter == '\r')) {
827         //                  // relocate if finding another quote fairly close: thus unicode
828         // '/u000D' will be fully consumed
829         //                  for (int lookAhead = 0; lookAhead < 50; lookAhead++) {
830         //                    if (currentPosition + lookAhead == source.length)
831         //                      break;
832         //                    if (source[currentPosition + lookAhead] == '\n')
833         //                      break;
834         //                    if (source[currentPosition + lookAhead] == '\"') {
835         //                      currentPosition += lookAhead + 1;
836         //                      break;
837         //                    }
838         //                  }
839         //                  throw new InvalidInputException(INVALID_CHAR_IN_STRING);
840         //                }
841         if (currentCharacter == '\\') {
842           int escapeSize = currentPosition;
843           boolean backSlashAsUnicodeInString = unicodeAsBackSlash;
844           //scanEscapeCharacter make a side effect on this value and we need
845           // the previous value few lines down this one
846           scanDoubleQuotedEscapeCharacter();
847           escapeSize = currentPosition - escapeSize;
848           if (withoutUnicodePtr == 0) {
849             //buffer all the entries that have been left aside....
850             withoutUnicodePtr = currentPosition - escapeSize - 1
851                 - startPosition;
852             System.arraycopy(source, startPosition, withoutUnicodeBuffer, 1,
853                 withoutUnicodePtr);
854             withoutUnicodeBuffer[++withoutUnicodePtr] = currentCharacter;
855           } else { //overwrite the / in the buffer
856             withoutUnicodeBuffer[withoutUnicodePtr] = currentCharacter;
857             if (backSlashAsUnicodeInString) { //there are TWO \ in the stream
858                                               // where only one is correct
859               withoutUnicodePtr--;
860             }
861           }
862         }
863         // consume next character
864         unicodeAsBackSlash = false;
865         currentCharacter = source[currentPosition++];
866         //                  if (((currentCharacter = source[currentPosition++]) == '\\')
867         //                    && (source[currentPosition] == 'u')) {
868         //                    getNextUnicodeChar();
869         //                  } else {
870         if (withoutUnicodePtr != 0) {
871           withoutUnicodeBuffer[++withoutUnicodePtr] = currentCharacter;
872         }
873         //                  }
874       }
875     } catch (IndexOutOfBoundsException e) {
876       throw new InvalidInputException(UNTERMINATED_STRING);
877     } catch (InvalidInputException e) {
878       if (e.getMessage().equals(INVALID_ESCAPE)) {
879         // relocate if finding another quote fairly close: thus unicode
880         // '/u000D' will be fully consumed
881         for (int lookAhead = 0; lookAhead < 50; lookAhead++) {
882           if (currentPosition + lookAhead == source.length)
883             break;
884           if (source[currentPosition + lookAhead] == '\n')
885             break;
886           if (source[currentPosition + lookAhead] == '`') {
887             currentPosition += lookAhead + 1;
888             break;
889           }
890         }
891       }
892       throw e; // rethrow
893     }
894     if (checkNonExternalizedStringLiterals) { // check for presence of NLS tags
895                                               // //$NON-NLS-?$ where ? is an
896                                               // int.
897       if (currentLine == null) {
898         currentLine = new NLSLine();
899         lines.add(currentLine);
900       }
901       currentLine.add(new StringLiteral(getCurrentTokenSourceString(),
902           startPosition, currentPosition - 1));
903     }
904   }
905   public void consumeStringConstant() throws InvalidInputException {
906     try {
907       // consume next character
908       unicodeAsBackSlash = false;
909       currentCharacter = source[currentPosition++];
910       //                if (((currentCharacter = source[currentPosition++]) == '\\')
911       //                  && (source[currentPosition] == 'u')) {
912       //                  getNextUnicodeChar();
913       //                } else {
914       //                  if (withoutUnicodePtr != 0) {
915       //                    withoutUnicodeBuffer[++withoutUnicodePtr] =
916       //                      currentCharacter;
917       //                  }
918       //                }
919       while (currentCharacter != '\'') {
920         /** ** in PHP \r and \n are valid in string literals *** */
921         //                  if ((currentCharacter == '\n')
922         //                    || (currentCharacter == '\r')) {
923         //                    // relocate if finding another quote fairly close: thus unicode
924         // '/u000D' will be fully consumed
925         //                    for (int lookAhead = 0; lookAhead < 50; lookAhead++) {
926         //                      if (currentPosition + lookAhead == source.length)
927         //                        break;
928         //                      if (source[currentPosition + lookAhead] == '\n')
929         //                        break;
930         //                      if (source[currentPosition + lookAhead] == '\"') {
931         //                        currentPosition += lookAhead + 1;
932         //                        break;
933         //                      }
934         //                    }
935         //                    throw new InvalidInputException(INVALID_CHAR_IN_STRING);
936         //                  }
937         if (currentCharacter == '\\') {
938           int escapeSize = currentPosition;
939           boolean backSlashAsUnicodeInString = unicodeAsBackSlash;
940           //scanEscapeCharacter make a side effect on this value and we need
941           // the previous value few lines down this one
942           scanSingleQuotedEscapeCharacter();
943           escapeSize = currentPosition - escapeSize;
944           if (withoutUnicodePtr == 0) {
945             //buffer all the entries that have been left aside....
946             withoutUnicodePtr = currentPosition - escapeSize - 1
947                 - startPosition;
948             System.arraycopy(source, startPosition, withoutUnicodeBuffer, 1,
949                 withoutUnicodePtr);
950             withoutUnicodeBuffer[++withoutUnicodePtr] = currentCharacter;
951           } else { //overwrite the / in the buffer
952             withoutUnicodeBuffer[withoutUnicodePtr] = currentCharacter;
953             if (backSlashAsUnicodeInString) { //there are TWO \ in the stream
954                                               // where only one is correct
955               withoutUnicodePtr--;
956             }
957           }
958         }
959         // consume next character
960         unicodeAsBackSlash = false;
961         currentCharacter = source[currentPosition++];
962         //                  if (((currentCharacter = source[currentPosition++]) == '\\')
963         //                    && (source[currentPosition] == 'u')) {
964         //                    getNextUnicodeChar();
965         //                  } else {
966         if (withoutUnicodePtr != 0) {
967           withoutUnicodeBuffer[++withoutUnicodePtr] = currentCharacter;
968         }
969         //                  }
970       }
971     } catch (IndexOutOfBoundsException e) {
972       throw new InvalidInputException(UNTERMINATED_STRING);
973     } catch (InvalidInputException e) {
974       if (e.getMessage().equals(INVALID_ESCAPE)) {
975         // relocate if finding another quote fairly close: thus unicode
976         // '/u000D' will be fully consumed
977         for (int lookAhead = 0; lookAhead < 50; lookAhead++) {
978           if (currentPosition + lookAhead == source.length)
979             break;
980           if (source[currentPosition + lookAhead] == '\n')
981             break;
982           if (source[currentPosition + lookAhead] == '\'') {
983             currentPosition += lookAhead + 1;
984             break;
985           }
986         }
987       }
988       throw e; // rethrow
989     }
990     if (checkNonExternalizedStringLiterals) { // check for presence of NLS tags
991                                               // //$NON-NLS-?$ where ? is an
992                                               // int.
993       if (currentLine == null) {
994         currentLine = new NLSLine();
995         lines.add(currentLine);
996       }
997       currentLine.add(new StringLiteral(getCurrentTokenSourceString(),
998           startPosition, currentPosition - 1));
999     }
1000   }
1001   public void consumeStringLiteral() throws InvalidInputException {
1002     try {
1003       // consume next character
1004       unicodeAsBackSlash = false;
1005       currentCharacter = source[currentPosition++];
1006       //                if (((currentCharacter = source[currentPosition++]) == '\\')
1007       //                  && (source[currentPosition] == 'u')) {
1008       //                  getNextUnicodeChar();
1009       //                } else {
1010       //                  if (withoutUnicodePtr != 0) {
1011       //                    withoutUnicodeBuffer[++withoutUnicodePtr] =
1012       //                      currentCharacter;
1013       //                  }
1014       //                }
1015       while (currentCharacter != '"') {
1016         /** ** in PHP \r and \n are valid in string literals *** */
1017         //                  if ((currentCharacter == '\n')
1018         //                    || (currentCharacter == '\r')) {
1019         //                    // relocate if finding another quote fairly close: thus unicode
1020         // '/u000D' will be fully consumed
1021         //                    for (int lookAhead = 0; lookAhead < 50; lookAhead++) {
1022         //                      if (currentPosition + lookAhead == source.length)
1023         //                        break;
1024         //                      if (source[currentPosition + lookAhead] == '\n')
1025         //                        break;
1026         //                      if (source[currentPosition + lookAhead] == '\"') {
1027         //                        currentPosition += lookAhead + 1;
1028         //                        break;
1029         //                      }
1030         //                    }
1031         //                    throw new InvalidInputException(INVALID_CHAR_IN_STRING);
1032         //                  }
1033         if (currentCharacter == '\\') {
1034           int escapeSize = currentPosition;
1035           boolean backSlashAsUnicodeInString = unicodeAsBackSlash;
1036           //scanEscapeCharacter make a side effect on this value and we need
1037           // the previous value few lines down this one
1038           scanDoubleQuotedEscapeCharacter();
1039           escapeSize = currentPosition - escapeSize;
1040           if (withoutUnicodePtr == 0) {
1041             //buffer all the entries that have been left aside....
1042             withoutUnicodePtr = currentPosition - escapeSize - 1
1043                 - startPosition;
1044             System.arraycopy(source, startPosition, withoutUnicodeBuffer, 1,
1045                 withoutUnicodePtr);
1046             withoutUnicodeBuffer[++withoutUnicodePtr] = currentCharacter;
1047           } else { //overwrite the / in the buffer
1048             withoutUnicodeBuffer[withoutUnicodePtr] = currentCharacter;
1049             if (backSlashAsUnicodeInString) { //there are TWO \ in the stream
1050                                               // where only one is correct
1051               withoutUnicodePtr--;
1052             }
1053           }
1054         }
1055         // consume next character
1056         unicodeAsBackSlash = false;
1057         currentCharacter = source[currentPosition++];
1058         //                  if (((currentCharacter = source[currentPosition++]) == '\\')
1059         //                    && (source[currentPosition] == 'u')) {
1060         //                    getNextUnicodeChar();
1061         //                  } else {
1062         if (withoutUnicodePtr != 0) {
1063           withoutUnicodeBuffer[++withoutUnicodePtr] = currentCharacter;
1064         }
1065         //                  }
1066       }
1067     } catch (IndexOutOfBoundsException e) {
1068       throw new InvalidInputException(UNTERMINATED_STRING);
1069     } catch (InvalidInputException e) {
1070       if (e.getMessage().equals(INVALID_ESCAPE)) {
1071         // relocate if finding another quote fairly close: thus unicode
1072         // '/u000D' will be fully consumed
1073         for (int lookAhead = 0; lookAhead < 50; lookAhead++) {
1074           if (currentPosition + lookAhead == source.length)
1075             break;
1076           if (source[currentPosition + lookAhead] == '\n')
1077             break;
1078           if (source[currentPosition + lookAhead] == '\"') {
1079             currentPosition += lookAhead + 1;
1080             break;
1081           }
1082         }
1083       }
1084       throw e; // rethrow
1085     }
1086     if (checkNonExternalizedStringLiterals) { // check for presence of NLS tags
1087                                               // //$NON-NLS-?$ where ? is an
1088                                               // int.
1089       if (currentLine == null) {
1090         currentLine = new NLSLine();
1091         lines.add(currentLine);
1092       }
1093       currentLine.add(new StringLiteral(getCurrentTokenSourceString(),
1094           startPosition, currentPosition - 1));
1095     }
1096   }
1097   public int getNextToken() throws InvalidInputException {
1098     if (!phpMode) {
1099       return getInlinedHTML(currentPosition);
1100     }
1101     if (phpMode) {
1102       this.wasAcr = false;
1103       if (diet) {
1104         jumpOverMethodBody();
1105         diet = false;
1106         return currentPosition > source.length ? TokenNameEOF : TokenNameRBRACE;
1107       }
1108       try {
1109         while (true) {
1110           withoutUnicodePtr = 0;
1111           //start with a new token
1112           char encapsedChar = ' ';
1113           if (!encapsedStringStack.isEmpty()) {
1114             encapsedChar = ((Character) encapsedStringStack.peek()).charValue();
1115           }
1116           if (encapsedChar != '$' && encapsedChar != ' ') {
1117             currentCharacter = source[currentPosition++];
1118             if (currentCharacter == encapsedChar) {
1119               switch (currentCharacter) {
1120                 case '`' :
1121                   return TokenNameEncapsedString0;
1122                 case '\'' :
1123                   return TokenNameEncapsedString1;
1124                 case '"' :
1125                   return TokenNameEncapsedString2;
1126               }
1127             }
1128             while (currentCharacter != encapsedChar) {
1129               /** ** in PHP \r and \n are valid in string literals *** */
1130               switch (currentCharacter) {
1131                 case '\\' :
1132                   int escapeSize = currentPosition;
1133                   boolean backSlashAsUnicodeInString = unicodeAsBackSlash;
1134                   //scanEscapeCharacter make a side effect on this value and
1135                   // we need the previous value few lines down this one
1136                   scanDoubleQuotedEscapeCharacter();
1137                   escapeSize = currentPosition - escapeSize;
1138                   if (withoutUnicodePtr == 0) {
1139                     //buffer all the entries that have been left aside....
1140                     withoutUnicodePtr = currentPosition - escapeSize - 1
1141                         - startPosition;
1142                     System.arraycopy(source, startPosition,
1143                         withoutUnicodeBuffer, 1, withoutUnicodePtr);
1144                     withoutUnicodeBuffer[++withoutUnicodePtr] = currentCharacter;
1145                   } else { //overwrite the / in the buffer
1146                     withoutUnicodeBuffer[withoutUnicodePtr] = currentCharacter;
1147                     if (backSlashAsUnicodeInString) { //there are TWO \ in
1148                       withoutUnicodePtr--;
1149                     }
1150                   }
1151                   break;
1152                 case '$' :
1153                   if (isPHPIdentifierStart(source[currentPosition])
1154                       || source[currentPosition] == '{') {
1155                     currentPosition--;
1156                     encapsedStringStack.push(new Character('$'));
1157                     return TokenNameSTRING;
1158                   }
1159                   break;
1160                 case '{' :
1161                   if (source[currentPosition] == '$') { // CURLY_OPEN
1162                     currentPosition--;
1163                     encapsedStringStack.push(new Character('$'));
1164                     return TokenNameSTRING;
1165                   }
1166               }
1167               // consume next character
1168               unicodeAsBackSlash = false;
1169               currentCharacter = source[currentPosition++];
1170               if (withoutUnicodePtr != 0) {
1171                 withoutUnicodeBuffer[++withoutUnicodePtr] = currentCharacter;
1172               }
1173               //                  }
1174             } // end while
1175             currentPosition--;
1176             return TokenNameSTRING;
1177           }
1178           // ---------Consume white space and handles startPosition---------
1179           int whiteStart = currentPosition;
1180           startPosition = currentPosition;
1181           currentCharacter = source[currentPosition++];
1182           if (encapsedChar == '$') {
1183             switch (currentCharacter) {
1184               case '\\' :
1185                 currentCharacter = source[currentPosition++];
1186                 return TokenNameSTRING;
1187               case '{' :
1188                 if (encapsedChar == '$') {
1189                   if (getNextChar('$'))
1190                     return TokenNameCURLY_OPEN;
1191                 }
1192                 return TokenNameLBRACE;
1193               case '}' :
1194                 return TokenNameRBRACE;
1195               case '[' :
1196                 return TokenNameLBRACKET;
1197               case ']' :
1198                 return TokenNameRBRACKET;
1199               case '\'' :
1200                 if (tokenizeStrings) {
1201                   consumeStringConstant();
1202                   return TokenNameStringConstant;
1203                 }
1204                 return TokenNameEncapsedString1;
1205               case '"' :
1206                 return TokenNameEncapsedString2;
1207               case '`' :
1208                 if (tokenizeStrings) {
1209                   consumeStringInterpolated();
1210                   return TokenNameStringInterpolated;
1211                 }
1212                 return TokenNameEncapsedString0;
1213               case '-' :
1214                 if (getNextChar('>'))
1215                   return TokenNameMINUS_GREATER;
1216                 return TokenNameSTRING;
1217               default :
1218                 if (currentCharacter == '$') {
1219                   int oldPosition = currentPosition;
1220                   try {
1221                     currentCharacter = source[currentPosition++];
1222                     if (currentCharacter == '{') {
1223                       return TokenNameDOLLAR_LBRACE;
1224                     }
1225                     if (isPHPIdentifierStart(currentCharacter)) {
1226                       return scanIdentifierOrKeyword(true);
1227                     } else {
1228                       currentPosition = oldPosition;
1229                       return TokenNameSTRING;
1230                     }
1231                   } catch (IndexOutOfBoundsException e) {
1232                     currentPosition = oldPosition;
1233                     return TokenNameSTRING;
1234                   }
1235                 }
1236                 if (isPHPIdentifierStart(currentCharacter))
1237                   return scanIdentifierOrKeyword(false);
1238                 if (Character.isDigit(currentCharacter))
1239                   return scanNumber(false);
1240                 return TokenNameERROR;
1241             }
1242           }
1243           //          boolean isWhiteSpace;
1244           while ((currentCharacter == ' ')
1245               || Character.isWhitespace(currentCharacter)) {
1246             startPosition = currentPosition;
1247             currentCharacter = source[currentPosition++];
1248             //            if (((currentCharacter = source[currentPosition++]) == '\\')
1249             //              && (source[currentPosition] == 'u')) {
1250             //              isWhiteSpace = jumpOverUnicodeWhiteSpace();
1251             //            } else {
1252             if ((currentCharacter == '\r') || (currentCharacter == '\n')) {
1253               checkNonExternalizeString();
1254               if (recordLineSeparator) {
1255                 pushLineSeparator();
1256               } else {
1257                 currentLine = null;
1258               }
1259             }
1260             //            isWhiteSpace = (currentCharacter == ' ')
1261             //                || Character.isWhitespace(currentCharacter);
1262             //            }
1263           }
1264           if (tokenizeWhiteSpace && (whiteStart != currentPosition - 1)) {
1265             // reposition scanner in case we are interested by spaces as tokens
1266             currentPosition--;
1267             startPosition = whiteStart;
1268             return TokenNameWHITESPACE;
1269           }
1270           //little trick to get out in the middle of a source compuation
1271           if (currentPosition > eofPosition)
1272             return TokenNameEOF;
1273           // ---------Identify the next token-------------
1274           switch (currentCharacter) {
1275             case '(' :
1276               return getCastOrParen();
1277             case ')' :
1278               return TokenNameRPAREN;
1279             case '{' :
1280               return TokenNameLBRACE;
1281             case '}' :
1282               return TokenNameRBRACE;
1283             case '[' :
1284               return TokenNameLBRACKET;
1285             case ']' :
1286               return TokenNameRBRACKET;
1287             case ';' :
1288               return TokenNameSEMICOLON;
1289             case ',' :
1290               return TokenNameCOMMA;
1291             case '.' :
1292               if (getNextChar('='))
1293                 return TokenNameDOT_EQUAL;
1294               if (getNextCharAsDigit())
1295                 return scanNumber(true);
1296               return TokenNameDOT;
1297             case '+' :
1298               {
1299                 int test;
1300                 if ((test = getNextChar('+', '=')) == 0)
1301                   return TokenNamePLUS_PLUS;
1302                 if (test > 0)
1303                   return TokenNamePLUS_EQUAL;
1304                 return TokenNamePLUS;
1305               }
1306             case '-' :
1307               {
1308                 int test;
1309                 if ((test = getNextChar('-', '=')) == 0)
1310                   return TokenNameMINUS_MINUS;
1311                 if (test > 0)
1312                   return TokenNameMINUS_EQUAL;
1313                 if (getNextChar('>'))
1314                   return TokenNameMINUS_GREATER;
1315                 return TokenNameMINUS;
1316               }
1317             case '~' :
1318               if (getNextChar('='))
1319                 return TokenNameTWIDDLE_EQUAL;
1320               return TokenNameTWIDDLE;
1321             case '!' :
1322               if (getNextChar('=')) {
1323                 if (getNextChar('=')) {
1324                   return TokenNameNOT_EQUAL_EQUAL;
1325                 }
1326                 return TokenNameNOT_EQUAL;
1327               }
1328               return TokenNameNOT;
1329             case '*' :
1330               if (getNextChar('='))
1331                 return TokenNameMULTIPLY_EQUAL;
1332               return TokenNameMULTIPLY;
1333             case '%' :
1334               if (getNextChar('='))
1335                 return TokenNameREMAINDER_EQUAL;
1336               return TokenNameREMAINDER;
1337             case '<' :
1338               {
1339                 int oldPosition = currentPosition;
1340                 try {
1341                   currentCharacter = source[currentPosition++];
1342                 } catch (IndexOutOfBoundsException e) {
1343                   currentPosition = oldPosition;
1344                   return TokenNameLESS;
1345                 }
1346                 switch (currentCharacter) {
1347                   case '=' :
1348                     return TokenNameLESS_EQUAL;
1349                   case '>' :
1350                     return TokenNameNOT_EQUAL;
1351                   case '<' :
1352                     if (getNextChar('='))
1353                       return TokenNameLEFT_SHIFT_EQUAL;
1354                     if (getNextChar('<')) {
1355                       currentCharacter = source[currentPosition++];
1356                       while (Character.isWhitespace(currentCharacter)) {
1357                         currentCharacter = source[currentPosition++];
1358                       }
1359                       int heredocStart = currentPosition - 1;
1360                       int heredocLength = 0;
1361                       if (isPHPIdentifierStart(currentCharacter)) {
1362                         currentCharacter = source[currentPosition++];
1363                       } else {
1364                         return TokenNameERROR;
1365                       }
1366                       while (isPHPIdentifierPart(currentCharacter)) {
1367                         currentCharacter = source[currentPosition++];
1368                       }
1369                       heredocLength = currentPosition - heredocStart - 1;
1370                       // heredoc end-tag determination
1371                       boolean endTag = true;
1372                       char ch;
1373                       do {
1374                         ch = source[currentPosition++];
1375                         if (ch == '\r' || ch == '\n') {
1376                           if (recordLineSeparator) {
1377                             pushLineSeparator();
1378                           } else {
1379                             currentLine = null;
1380                           }
1381                           for (int i = 0; i < heredocLength; i++) {
1382                             if (source[currentPosition + i] != source[heredocStart
1383                                 + i]) {
1384                               endTag = false;
1385                               break;
1386                             }
1387                           }
1388                           if (endTag) {
1389                             currentPosition += heredocLength - 1;
1390                             currentCharacter = source[currentPosition++];
1391                             break; // do...while loop
1392                           } else {
1393                             endTag = true;
1394                           }
1395                         }
1396                       } while (true);
1397                       return TokenNameHEREDOC;
1398                     }
1399                     return TokenNameLEFT_SHIFT;
1400                 }
1401                 currentPosition = oldPosition;
1402                 return TokenNameLESS;
1403               }
1404             case '>' :
1405               {
1406                 int test;
1407                 if ((test = getNextChar('=', '>')) == 0)
1408                   return TokenNameGREATER_EQUAL;
1409                 if (test > 0) {
1410                   if ((test = getNextChar('=', '>')) == 0)
1411                     return TokenNameRIGHT_SHIFT_EQUAL;
1412                   return TokenNameRIGHT_SHIFT;
1413                 }
1414                 return TokenNameGREATER;
1415               }
1416             case '=' :
1417               if (getNextChar('=')) {
1418                 if (getNextChar('=')) {
1419                   return TokenNameEQUAL_EQUAL_EQUAL;
1420                 }
1421                 return TokenNameEQUAL_EQUAL;
1422               }
1423               if (getNextChar('>'))
1424                 return TokenNameEQUAL_GREATER;
1425               return TokenNameEQUAL;
1426             case '&' :
1427               {
1428                 int test;
1429                 if ((test = getNextChar('&', '=')) == 0)
1430                   return TokenNameAND_AND;
1431                 if (test > 0)
1432                   return TokenNameAND_EQUAL;
1433                 return TokenNameAND;
1434               }
1435             case '|' :
1436               {
1437                 int test;
1438                 if ((test = getNextChar('|', '=')) == 0)
1439                   return TokenNameOR_OR;
1440                 if (test > 0)
1441                   return TokenNameOR_EQUAL;
1442                 return TokenNameOR;
1443               }
1444             case '^' :
1445               if (getNextChar('='))
1446                 return TokenNameXOR_EQUAL;
1447               return TokenNameXOR;
1448             case '?' :
1449               if (getNextChar('>')) {
1450                 phpMode = false;
1451                 if (currentPosition == source.length) {
1452                   phpMode = true;
1453                   return TokenNameINLINE_HTML;
1454                 }
1455                 return getInlinedHTML(currentPosition - 2);
1456               }
1457               return TokenNameQUESTION;
1458             case ':' :
1459               if (getNextChar(':'))
1460                 return TokenNamePAAMAYIM_NEKUDOTAYIM;
1461               return TokenNameCOLON;
1462             case '@' :
1463               return TokenNameAT;
1464             case '\'' :
1465               consumeStringConstant();
1466               return TokenNameStringConstant;
1467             case '"' :
1468               if (tokenizeStrings) {
1469                 consumeStringLiteral();
1470                 return TokenNameStringLiteral;
1471               }
1472               return TokenNameEncapsedString2;
1473             case '`' :
1474               if (tokenizeStrings) {
1475                 consumeStringInterpolated();
1476                 return TokenNameStringInterpolated;
1477               }
1478               return TokenNameEncapsedString0;
1479             case '#' :
1480             case '/' :
1481               {
1482                 char startChar = currentCharacter;
1483                 if (getNextChar('=')) {
1484                   return TokenNameDIVIDE_EQUAL;
1485                 }
1486                 int test;
1487                 if ((startChar == '#') || (test = getNextChar('/', '*')) == 0) {
1488                   //line comment
1489                   int endPositionForLineComment = 0;
1490                   try { //get the next char
1491                     currentCharacter = source[currentPosition++];
1492                     //                    if (((currentCharacter = source[currentPosition++])
1493                     //                      == '\\')
1494                     //                      && (source[currentPosition] == 'u')) {
1495                     //                      //-------------unicode traitement ------------
1496                     //                      int c1 = 0, c2 = 0, c3 = 0, c4 = 0;
1497                     //                      currentPosition++;
1498                     //                      while (source[currentPosition] == 'u') {
1499                     //                        currentPosition++;
1500                     //                      }
1501                     //                      if ((c1 =
1502                     //                        Character.getNumericValue(source[currentPosition++]))
1503                     //                        > 15
1504                     //                        || c1 < 0
1505                     //                        || (c2 =
1506                     //                          Character.getNumericValue(source[currentPosition++]))
1507                     //                          > 15
1508                     //                        || c2 < 0
1509                     //                        || (c3 =
1510                     //                          Character.getNumericValue(source[currentPosition++]))
1511                     //                          > 15
1512                     //                        || c3 < 0
1513                     //                        || (c4 =
1514                     //                          Character.getNumericValue(source[currentPosition++]))
1515                     //                          > 15
1516                     //                        || c4 < 0) {
1517                     //                        throw new
1518                     // InvalidInputException(INVALID_UNICODE_ESCAPE);
1519                     //                      } else {
1520                     //                        currentCharacter =
1521                     //                          (char) (((c1 * 16 + c2) * 16 + c3) * 16 + c4);
1522                     //                      }
1523                     //                    }
1524                     //handle the \\u case manually into comment
1525                     //                    if (currentCharacter == '\\') {
1526                     //                      if (source[currentPosition] == '\\')
1527                     //                        currentPosition++;
1528                     //                    } //jump over the \\
1529                     boolean isUnicode = false;
1530                     while (currentCharacter != '\r' && currentCharacter != '\n') {
1531                       if (currentCharacter == '?') {
1532                         if (getNextChar('>')) {
1533                           startPosition = currentPosition - 2;
1534                           phpMode = false;
1535                           return TokenNameINLINE_HTML;
1536                         }
1537                       }
1538                       //get the next char
1539                       isUnicode = false;
1540                       currentCharacter = source[currentPosition++];
1541                       //                      if (((currentCharacter = source[currentPosition++])
1542                       //                        == '\\')
1543                       //                        && (source[currentPosition] == 'u')) {
1544                       //                        isUnicode = true;
1545                       //                        //-------------unicode traitement ------------
1546                       //                        int c1 = 0, c2 = 0, c3 = 0, c4 = 0;
1547                       //                        currentPosition++;
1548                       //                        while (source[currentPosition] == 'u') {
1549                       //                          currentPosition++;
1550                       //                        }
1551                       //                        if ((c1 =
1552                       //                          Character.getNumericValue(source[currentPosition++]))
1553                       //                          > 15
1554                       //                          || c1 < 0
1555                       //                          || (c2 =
1556                       //                            Character.getNumericValue(
1557                       //                              source[currentPosition++]))
1558                       //                            > 15
1559                       //                          || c2 < 0
1560                       //                          || (c3 =
1561                       //                            Character.getNumericValue(
1562                       //                              source[currentPosition++]))
1563                       //                            > 15
1564                       //                          || c3 < 0
1565                       //                          || (c4 =
1566                       //                            Character.getNumericValue(
1567                       //                              source[currentPosition++]))
1568                       //                            > 15
1569                       //                          || c4 < 0) {
1570                       //                          throw new
1571                       // InvalidInputException(INVALID_UNICODE_ESCAPE);
1572                       //                        } else {
1573                       //                          currentCharacter =
1574                       //                            (char) (((c1 * 16 + c2) * 16 + c3) * 16 + c4);
1575                       //                        }
1576                       //                      }
1577                       //handle the \\u case manually into comment
1578                       //                      if (currentCharacter == '\\') {
1579                       //                        if (source[currentPosition] == '\\')
1580                       //                          currentPosition++;
1581                       //                      } //jump over the \\
1582                     }
1583                     if (isUnicode) {
1584                       endPositionForLineComment = currentPosition - 6;
1585                     } else {
1586                       endPositionForLineComment = currentPosition - 1;
1587                     }
1588                     recordComment(false);
1589                     if ((currentCharacter == '\r')
1590                         || (currentCharacter == '\n')) {
1591                       checkNonExternalizeString();
1592                       if (recordLineSeparator) {
1593                         if (isUnicode) {
1594                           pushUnicodeLineSeparator();
1595                         } else {
1596                           pushLineSeparator();
1597                         }
1598                       } else {
1599                         currentLine = null;
1600                       }
1601                     }
1602                     if (tokenizeComments) {
1603                       if (!isUnicode) {
1604                         currentPosition = endPositionForLineComment;
1605                         // reset one character behind
1606                       }
1607                       return TokenNameCOMMENT_LINE;
1608                     }
1609                   } catch (IndexOutOfBoundsException e) { //an eof will them
1610                     // be generated
1611                     if (tokenizeComments) {
1612                       currentPosition--;
1613                       // reset one character behind
1614                       return TokenNameCOMMENT_LINE;
1615                     }
1616                   }
1617                   break;
1618                 }
1619                 if (test > 0) {
1620                   //traditional and annotation comment
1621                   boolean isJavadoc = false, star = false;
1622                   // consume next character
1623                   unicodeAsBackSlash = false;
1624                   currentCharacter = source[currentPosition++];
1625                   //                  if (((currentCharacter = source[currentPosition++]) ==
1626                   // '\\')
1627                   //                    && (source[currentPosition] == 'u')) {
1628                   //                    getNextUnicodeChar();
1629                   //                  } else {
1630                   //                    if (withoutUnicodePtr != 0) {
1631                   //                      withoutUnicodeBuffer[++withoutUnicodePtr] =
1632                   //                        currentCharacter;
1633                   //                    }
1634                   //                  }
1635                   if (currentCharacter == '*') {
1636                     isJavadoc = true;
1637                     star = true;
1638                   }
1639                   if ((currentCharacter == '\r') || (currentCharacter == '\n')) {
1640                     checkNonExternalizeString();
1641                     if (recordLineSeparator) {
1642                       pushLineSeparator();
1643                     } else {
1644                       currentLine = null;
1645                     }
1646                   }
1647                   try { //get the next char
1648                     currentCharacter = source[currentPosition++];
1649                     //                    if (((currentCharacter = source[currentPosition++])
1650                     //                      == '\\')
1651                     //                      && (source[currentPosition] == 'u')) {
1652                     //                      //-------------unicode traitement ------------
1653                     //                      getNextUnicodeChar();
1654                     //                    }
1655                     //handle the \\u case manually into comment
1656                     //                    if (currentCharacter == '\\') {
1657                     //                      if (source[currentPosition] == '\\')
1658                     //                        currentPosition++;
1659                     //                      //jump over the \\
1660                     //                    }
1661                     // empty comment is not a javadoc /**/
1662                     if (currentCharacter == '/') {
1663                       isJavadoc = false;
1664                     }
1665                     //loop until end of comment */
1666                     while ((currentCharacter != '/') || (!star)) {
1667                       if ((currentCharacter == '\r')
1668                           || (currentCharacter == '\n')) {
1669                         checkNonExternalizeString();
1670                         if (recordLineSeparator) {
1671                           pushLineSeparator();
1672                         } else {
1673                           currentLine = null;
1674                         }
1675                       }
1676                       star = currentCharacter == '*';
1677                       //get next char
1678                       currentCharacter = source[currentPosition++];
1679                       //                      if (((currentCharacter = source[currentPosition++])
1680                       //                        == '\\')
1681                       //                        && (source[currentPosition] == 'u')) {
1682                       //                        //-------------unicode traitement ------------
1683                       //                        getNextUnicodeChar();
1684                       //                      }
1685                       //handle the \\u case manually into comment
1686                       //                      if (currentCharacter == '\\') {
1687                       //                        if (source[currentPosition] == '\\')
1688                       //                          currentPosition++;
1689                       //                      } //jump over the \\
1690                     }
1691                     recordComment(isJavadoc);
1692                     if (tokenizeComments) {
1693                       if (isJavadoc)
1694                         return TokenNameCOMMENT_PHPDOC;
1695                       return TokenNameCOMMENT_BLOCK;
1696                     }
1697                   } catch (IndexOutOfBoundsException e) {
1698                     throw new InvalidInputException(UNTERMINATED_COMMENT);
1699                   }
1700                   break;
1701                 }
1702                 return TokenNameDIVIDE;
1703               }
1704             case '\u001a' :
1705               if (atEnd())
1706                 return TokenNameEOF;
1707               //the atEnd may not be <currentPosition == source.length> if
1708               // source is only some part of a real (external) stream
1709               throw new InvalidInputException("Ctrl-Z"); //$NON-NLS-1$
1710             default :
1711               if (currentCharacter == '$') {
1712                 int oldPosition = currentPosition;
1713                 try {
1714                   currentCharacter = source[currentPosition++];
1715                   if (isPHPIdentifierStart(currentCharacter)) {
1716                     return scanIdentifierOrKeyword(true);
1717                   } else {
1718                     currentPosition = oldPosition;
1719                     return TokenNameDOLLAR;
1720                   }
1721                 } catch (IndexOutOfBoundsException e) {
1722                   currentPosition = oldPosition;
1723                   return TokenNameDOLLAR;
1724                 }
1725               }
1726               if (isPHPIdentifierStart(currentCharacter))
1727                 return scanIdentifierOrKeyword(false);
1728               if (Character.isDigit(currentCharacter))
1729                 return scanNumber(false);
1730               return TokenNameERROR;
1731           }
1732         }
1733       } //-----------------end switch while try--------------------
1734       catch (IndexOutOfBoundsException e) {
1735       }
1736     }
1737     return TokenNameEOF;
1738   }
1739   /**
1740    * @return @throws
1741    *         InvalidInputException
1742    */
1743   private int getInlinedHTML(int start) throws InvalidInputException {
1744     //    int htmlPosition = start;
1745     if (currentPosition > source.length) {
1746       currentPosition = source.length;
1747       return TokenNameEOF;
1748     }
1749     startPosition = start;
1750     try {
1751       while (!phpMode) {
1752         currentCharacter = source[currentPosition++];
1753         if (currentCharacter == '<') {
1754           if (getNextChar('?')) {
1755             currentCharacter = source[currentPosition++];
1756             if ((currentCharacter == ' ')
1757                 || Character.isWhitespace(currentCharacter)) {
1758               // <?
1759               phpMode = true;
1760               return TokenNameINLINE_HTML;
1761             } else {
1762               boolean phpStart = (currentCharacter == 'P')
1763                   || (currentCharacter == 'p');
1764               if (phpStart) {
1765                 int test = getNextChar('H', 'h');
1766                 if (test >= 0) {
1767                   test = getNextChar('P', 'p');
1768                   if (test >= 0) {
1769                     // <?PHP <?php
1770                     phpMode = true;
1771                     return TokenNameINLINE_HTML;
1772                   }
1773                 }
1774               }
1775             }
1776           }
1777         }
1778         if ((currentCharacter == '\r') || (currentCharacter == '\n')) {
1779           if (recordLineSeparator) {
1780             pushLineSeparator();
1781           } else {
1782             currentLine = null;
1783           }
1784         }
1785       } //-----------------while--------------------
1786       phpMode = true;
1787       return TokenNameINLINE_HTML;
1788     } //-----------------try--------------------
1789     catch (IndexOutOfBoundsException e) {
1790       startPosition = start;
1791       currentPosition--;
1792     }
1793     phpMode = true;
1794     return TokenNameINLINE_HTML;
1795   }
1796   //  public final void getNextUnicodeChar()
1797   //    throws IndexOutOfBoundsException, InvalidInputException {
1798   //    //VOID
1799   //    //handle the case of unicode.
1800   //    //when a unicode appears then we must use a buffer that holds char
1801   // internal values
1802   //    //At the end of this method currentCharacter holds the new visited char
1803   //    //and currentPosition points right next after it
1804   //
1805   //    //ALL getNextChar.... ARE OPTIMIZED COPIES
1806   //
1807   //    int c1 = 0, c2 = 0, c3 = 0, c4 = 0, unicodeSize = 6;
1808   //    currentPosition++;
1809   //    while (source[currentPosition] == 'u') {
1810   //      currentPosition++;
1811   //      unicodeSize++;
1812   //    }
1813   //
1814   //    if ((c1 = Character.getNumericValue(source[currentPosition++])) > 15
1815   //      || c1 < 0
1816   //      || (c2 = Character.getNumericValue(source[currentPosition++])) > 15
1817   //      || c2 < 0
1818   //      || (c3 = Character.getNumericValue(source[currentPosition++])) > 15
1819   //      || c3 < 0
1820   //      || (c4 = Character.getNumericValue(source[currentPosition++])) > 15
1821   //      || c4 < 0) {
1822   //      throw new InvalidInputException(INVALID_UNICODE_ESCAPE);
1823   //    } else {
1824   //      currentCharacter = (char) (((c1 * 16 + c2) * 16 + c3) * 16 + c4);
1825   //      //need the unicode buffer
1826   //      if (withoutUnicodePtr == 0) {
1827   //        //buffer all the entries that have been left aside....
1828   //        withoutUnicodePtr = currentPosition - unicodeSize - startPosition;
1829   //        System.arraycopy(
1830   //          source,
1831   //          startPosition,
1832   //          withoutUnicodeBuffer,
1833   //          1,
1834   //          withoutUnicodePtr);
1835   //      }
1836   //      //fill the buffer with the char
1837   //      withoutUnicodeBuffer[++withoutUnicodePtr] = currentCharacter;
1838   //    }
1839   //    unicodeAsBackSlash = currentCharacter == '\\';
1840   //  }
1841   /*
1842    * Tokenize a method body, assuming that curly brackets are properly
1843    * balanced.
1844    */
1845   public final void jumpOverMethodBody() {
1846     this.wasAcr = false;
1847     int found = 1;
1848     try {
1849       while (true) { //loop for jumping over comments
1850         // ---------Consume white space and handles startPosition---------
1851         boolean isWhiteSpace;
1852         do {
1853           startPosition = currentPosition;
1854           currentCharacter = source[currentPosition++];
1855           //          if (((currentCharacter = source[currentPosition++]) == '\\')
1856           //            && (source[currentPosition] == 'u')) {
1857           //            isWhiteSpace = jumpOverUnicodeWhiteSpace();
1858           //          } else {
1859           if (recordLineSeparator
1860               && ((currentCharacter == '\r') || (currentCharacter == '\n')))
1861             pushLineSeparator();
1862           isWhiteSpace = Character.isWhitespace(currentCharacter);
1863           //          }
1864         } while (isWhiteSpace);
1865         // -------consume token until } is found---------
1866         switch (currentCharacter) {
1867           case '{' :
1868             found++;
1869             break;
1870           case '}' :
1871             found--;
1872             if (found == 0)
1873               return;
1874             break;
1875           case '\'' :
1876             {
1877               boolean test;
1878               test = getNextChar('\\');
1879               if (test) {
1880                 try {
1881                   scanDoubleQuotedEscapeCharacter();
1882                 } catch (InvalidInputException ex) {
1883                 };
1884               } else {
1885                 //                try { // consume next character
1886                 unicodeAsBackSlash = false;
1887                 currentCharacter = source[currentPosition++];
1888                 //                  if (((currentCharacter = source[currentPosition++]) == '\\')
1889                 //                    && (source[currentPosition] == 'u')) {
1890                 //                    getNextUnicodeChar();
1891                 //                  } else {
1892                 if (withoutUnicodePtr != 0) {
1893                   withoutUnicodeBuffer[++withoutUnicodePtr] = currentCharacter;
1894                 }
1895                 //                  }
1896                 //                } catch (InvalidInputException ex) {
1897                 //                };
1898               }
1899               getNextChar('\'');
1900               break;
1901             }
1902           case '"' :
1903             try {
1904               //              try { // consume next character
1905               unicodeAsBackSlash = false;
1906               currentCharacter = source[currentPosition++];
1907               //                if (((currentCharacter = source[currentPosition++]) == '\\')
1908               //                  && (source[currentPosition] == 'u')) {
1909               //                  getNextUnicodeChar();
1910               //                } else {
1911               if (withoutUnicodePtr != 0) {
1912                 withoutUnicodeBuffer[++withoutUnicodePtr] = currentCharacter;
1913               }
1914               //                }
1915               //              } catch (InvalidInputException ex) {
1916               //              };
1917               while (currentCharacter != '"') {
1918                 if (currentCharacter == '\r') {
1919                   if (source[currentPosition] == '\n')
1920                     currentPosition++;
1921                   break;
1922                   // the string cannot go further that the line
1923                 }
1924                 if (currentCharacter == '\n') {
1925                   break;
1926                   // the string cannot go further that the line
1927                 }
1928                 if (currentCharacter == '\\') {
1929                   try {
1930                     scanDoubleQuotedEscapeCharacter();
1931                   } catch (InvalidInputException ex) {
1932                   };
1933                 }
1934                 //                try { // consume next character
1935                 unicodeAsBackSlash = false;
1936                 currentCharacter = source[currentPosition++];
1937                 //                  if (((currentCharacter = source[currentPosition++]) == '\\')
1938                 //                    && (source[currentPosition] == 'u')) {
1939                 //                    getNextUnicodeChar();
1940                 //                  } else {
1941                 if (withoutUnicodePtr != 0) {
1942                   withoutUnicodeBuffer[++withoutUnicodePtr] = currentCharacter;
1943                 }
1944                 //                  }
1945                 //                } catch (InvalidInputException ex) {
1946                 //                };
1947               }
1948             } catch (IndexOutOfBoundsException e) {
1949               return;
1950             }
1951             break;
1952           case '/' :
1953             {
1954               int test;
1955               if ((test = getNextChar('/', '*')) == 0) {
1956                 //line comment
1957                 try {
1958                   //get the next char
1959                   currentCharacter = source[currentPosition++];
1960                   //                  if (((currentCharacter = source[currentPosition++]) ==
1961                   // '\\')
1962                   //                    && (source[currentPosition] == 'u')) {
1963                   //                    //-------------unicode traitement ------------
1964                   //                    int c1 = 0, c2 = 0, c3 = 0, c4 = 0;
1965                   //                    currentPosition++;
1966                   //                    while (source[currentPosition] == 'u') {
1967                   //                      currentPosition++;
1968                   //                    }
1969                   //                    if ((c1 =
1970                   //                      Character.getNumericValue(source[currentPosition++]))
1971                   //                      > 15
1972                   //                      || c1 < 0
1973                   //                      || (c2 =
1974                   //                        Character.getNumericValue(source[currentPosition++]))
1975                   //                        > 15
1976                   //                      || c2 < 0
1977                   //                      || (c3 =
1978                   //                        Character.getNumericValue(source[currentPosition++]))
1979                   //                        > 15
1980                   //                      || c3 < 0
1981                   //                      || (c4 =
1982                   //                        Character.getNumericValue(source[currentPosition++]))
1983                   //                        > 15
1984                   //                      || c4 < 0) {
1985                   //                      //error don't care of the value
1986                   //                      currentCharacter = 'A';
1987                   //                    } //something different from \n and \r
1988                   //                    else {
1989                   //                      currentCharacter =
1990                   //                        (char) (((c1 * 16 + c2) * 16 + c3) * 16 + c4);
1991                   //                    }
1992                   //                  }
1993                   while (currentCharacter != '\r' && currentCharacter != '\n') {
1994                     //get the next char
1995                     currentCharacter = source[currentPosition++];
1996                     //                    if (((currentCharacter = source[currentPosition++])
1997                     //                      == '\\')
1998                     //                      && (source[currentPosition] == 'u')) {
1999                     //                      //-------------unicode traitement ------------
2000                     //                      int c1 = 0, c2 = 0, c3 = 0, c4 = 0;
2001                     //                      currentPosition++;
2002                     //                      while (source[currentPosition] == 'u') {
2003                     //                        currentPosition++;
2004                     //                      }
2005                     //                      if ((c1 =
2006                     //                        Character.getNumericValue(source[currentPosition++]))
2007                     //                        > 15
2008                     //                        || c1 < 0
2009                     //                        || (c2 =
2010                     //                          Character.getNumericValue(source[currentPosition++]))
2011                     //                          > 15
2012                     //                        || c2 < 0
2013                     //                        || (c3 =
2014                     //                          Character.getNumericValue(source[currentPosition++]))
2015                     //                          > 15
2016                     //                        || c3 < 0
2017                     //                        || (c4 =
2018                     //                          Character.getNumericValue(source[currentPosition++]))
2019                     //                          > 15
2020                     //                        || c4 < 0) {
2021                     //                        //error don't care of the value
2022                     //                        currentCharacter = 'A';
2023                     //                      } //something different from \n and \r
2024                     //                      else {
2025                     //                        currentCharacter =
2026                     //                          (char) (((c1 * 16 + c2) * 16 + c3) * 16 + c4);
2027                     //                      }
2028                     //                    }
2029                   }
2030                   if (recordLineSeparator
2031                       && ((currentCharacter == '\r') || (currentCharacter == '\n')))
2032                     pushLineSeparator();
2033                 } catch (IndexOutOfBoundsException e) {
2034                 } //an eof will them be generated
2035                 break;
2036               }
2037               if (test > 0) {
2038                 //traditional and annotation comment
2039                 boolean star = false;
2040                 //                try { // consume next character
2041                 unicodeAsBackSlash = false;
2042                 currentCharacter = source[currentPosition++];
2043                 //                  if (((currentCharacter = source[currentPosition++]) == '\\')
2044                 //                    && (source[currentPosition] == 'u')) {
2045                 //                    getNextUnicodeChar();
2046                 //                  } else {
2047                 if (withoutUnicodePtr != 0) {
2048                   withoutUnicodeBuffer[++withoutUnicodePtr] = currentCharacter;
2049                 }
2050                 //                  };
2051                 //                } catch (InvalidInputException ex) {
2052                 //                };
2053                 if (currentCharacter == '*') {
2054                   star = true;
2055                 }
2056                 if (recordLineSeparator
2057                     && ((currentCharacter == '\r') || (currentCharacter == '\n')))
2058                   pushLineSeparator();
2059                 try { //get the next char
2060                   currentCharacter = source[currentPosition++];
2061                   //                  if (((currentCharacter = source[currentPosition++]) ==
2062                   // '\\')
2063                   //                    && (source[currentPosition] == 'u')) {
2064                   //                    //-------------unicode traitement ------------
2065                   //                    int c1 = 0, c2 = 0, c3 = 0, c4 = 0;
2066                   //                    currentPosition++;
2067                   //                    while (source[currentPosition] == 'u') {
2068                   //                      currentPosition++;
2069                   //                    }
2070                   //                    if ((c1 =
2071                   //                      Character.getNumericValue(source[currentPosition++]))
2072                   //                      > 15
2073                   //                      || c1 < 0
2074                   //                      || (c2 =
2075                   //                        Character.getNumericValue(source[currentPosition++]))
2076                   //                        > 15
2077                   //                      || c2 < 0
2078                   //                      || (c3 =
2079                   //                        Character.getNumericValue(source[currentPosition++]))
2080                   //                        > 15
2081                   //                      || c3 < 0
2082                   //                      || (c4 =
2083                   //                        Character.getNumericValue(source[currentPosition++]))
2084                   //                        > 15
2085                   //                      || c4 < 0) {
2086                   //                      //error don't care of the value
2087                   //                      currentCharacter = 'A';
2088                   //                    } //something different from * and /
2089                   //                    else {
2090                   //                      currentCharacter =
2091                   //                        (char) (((c1 * 16 + c2) * 16 + c3) * 16 + c4);
2092                   //                    }
2093                   //                  }
2094                   //loop until end of comment */
2095                   while ((currentCharacter != '/') || (!star)) {
2096                     if (recordLineSeparator
2097                         && ((currentCharacter == '\r') || (currentCharacter == '\n')))
2098                       pushLineSeparator();
2099                     star = currentCharacter == '*';
2100                     //get next char
2101                     currentCharacter = source[currentPosition++];
2102                     //                    if (((currentCharacter = source[currentPosition++])
2103                     //                      == '\\')
2104                     //                      && (source[currentPosition] == 'u')) {
2105                     //                      //-------------unicode traitement ------------
2106                     //                      int c1 = 0, c2 = 0, c3 = 0, c4 = 0;
2107                     //                      currentPosition++;
2108                     //                      while (source[currentPosition] == 'u') {
2109                     //                        currentPosition++;
2110                     //                      }
2111                     //                      if ((c1 =
2112                     //                        Character.getNumericValue(source[currentPosition++]))
2113                     //                        > 15
2114                     //                        || c1 < 0
2115                     //                        || (c2 =
2116                     //                          Character.getNumericValue(source[currentPosition++]))
2117                     //                          > 15
2118                     //                        || c2 < 0
2119                     //                        || (c3 =
2120                     //                          Character.getNumericValue(source[currentPosition++]))
2121                     //                          > 15
2122                     //                        || c3 < 0
2123                     //                        || (c4 =
2124                     //                          Character.getNumericValue(source[currentPosition++]))
2125                     //                          > 15
2126                     //                        || c4 < 0) {
2127                     //                        //error don't care of the value
2128                     //                        currentCharacter = 'A';
2129                     //                      } //something different from * and /
2130                     //                      else {
2131                     //                        currentCharacter =
2132                     //                          (char) (((c1 * 16 + c2) * 16 + c3) * 16 + c4);
2133                     //                      }
2134                     //                    }
2135                   }
2136                 } catch (IndexOutOfBoundsException e) {
2137                   return;
2138                 }
2139                 break;
2140               }
2141               break;
2142             }
2143           default :
2144             if (isPHPIdentifierStart(currentCharacter)
2145                 || currentCharacter == '$') {
2146               try {
2147                 scanIdentifierOrKeyword((currentCharacter == '$'));
2148               } catch (InvalidInputException ex) {
2149               };
2150               break;
2151             }
2152             if (Character.isDigit(currentCharacter)) {
2153               try {
2154                 scanNumber(false);
2155               } catch (InvalidInputException ex) {
2156               };
2157               break;
2158             }
2159         }
2160       }
2161       //-----------------end switch while try--------------------
2162     } catch (IndexOutOfBoundsException e) {
2163     } catch (InvalidInputException e) {
2164     }
2165     return;
2166   }
2167   //  public final boolean jumpOverUnicodeWhiteSpace()
2168   //    throws InvalidInputException {
2169   //    //BOOLEAN
2170   //    //handle the case of unicode. Jump over the next whiteSpace
2171   //    //making startPosition pointing on the next available char
2172   //    //On false, the currentCharacter is filled up with a potential
2173   //    //correct char
2174   //
2175   //    try {
2176   //      this.wasAcr = false;
2177   //      int c1, c2, c3, c4;
2178   //      int unicodeSize = 6;
2179   //      currentPosition++;
2180   //      while (source[currentPosition] == 'u') {
2181   //        currentPosition++;
2182   //        unicodeSize++;
2183   //      }
2184   //
2185   //      if (((c1 = Character.getNumericValue(source[currentPosition++])) > 15
2186   //        || c1 < 0)
2187   //        || ((c2 = Character.getNumericValue(source[currentPosition++])) > 15
2188   //          || c2 < 0)
2189   //        || ((c3 = Character.getNumericValue(source[currentPosition++])) > 15
2190   //          || c3 < 0)
2191   //        || ((c4 = Character.getNumericValue(source[currentPosition++])) > 15
2192   //          || c4 < 0)) {
2193   //        throw new InvalidInputException(INVALID_UNICODE_ESCAPE);
2194   //      }
2195   //
2196   //      currentCharacter = (char) (((c1 * 16 + c2) * 16 + c3) * 16 + c4);
2197   //      if (recordLineSeparator
2198   //        && ((currentCharacter == '\r') || (currentCharacter == '\n')))
2199   //        pushLineSeparator();
2200   //      if (Character.isWhitespace(currentCharacter))
2201   //        return true;
2202   //
2203   //      //buffer the new char which is not a white space
2204   //      withoutUnicodeBuffer[++withoutUnicodePtr] = currentCharacter;
2205   //      //withoutUnicodePtr == 1 is true here
2206   //      return false;
2207   //    } catch (IndexOutOfBoundsException e) {
2208   //      throw new InvalidInputException(INVALID_UNICODE_ESCAPE);
2209   //    }
2210   //  }
2211   public final int[] getLineEnds() {
2212     //return a bounded copy of this.lineEnds
2213     int[] copy;
2214     System.arraycopy(lineEnds, 0, copy = new int[linePtr + 1], 0, linePtr + 1);
2215     return copy;
2216   }
2217   public char[] getSource() {
2218     return this.source;
2219   }
2220   final char[] optimizedCurrentTokenSource1() {
2221     //return always the same char[] build only once
2222     //optimization at no speed cost of 99.5 % of the singleCharIdentifier
2223     char charOne = source[startPosition];
2224     switch (charOne) {
2225       case 'a' :
2226         return charArray_a;
2227       case 'b' :
2228         return charArray_b;
2229       case 'c' :
2230         return charArray_c;
2231       case 'd' :
2232         return charArray_d;
2233       case 'e' :
2234         return charArray_e;
2235       case 'f' :
2236         return charArray_f;
2237       case 'g' :
2238         return charArray_g;
2239       case 'h' :
2240         return charArray_h;
2241       case 'i' :
2242         return charArray_i;
2243       case 'j' :
2244         return charArray_j;
2245       case 'k' :
2246         return charArray_k;
2247       case 'l' :
2248         return charArray_l;
2249       case 'm' :
2250         return charArray_m;
2251       case 'n' :
2252         return charArray_n;
2253       case 'o' :
2254         return charArray_o;
2255       case 'p' :
2256         return charArray_p;
2257       case 'q' :
2258         return charArray_q;
2259       case 'r' :
2260         return charArray_r;
2261       case 's' :
2262         return charArray_s;
2263       case 't' :
2264         return charArray_t;
2265       case 'u' :
2266         return charArray_u;
2267       case 'v' :
2268         return charArray_v;
2269       case 'w' :
2270         return charArray_w;
2271       case 'x' :
2272         return charArray_x;
2273       case 'y' :
2274         return charArray_y;
2275       case 'z' :
2276         return charArray_z;
2277       default :
2278         return new char[]{charOne};
2279     }
2280   }
2281   final char[] optimizedCurrentTokenSource2() {
2282     //try to return the same char[] build only once
2283     char c0, c1;
2284     int hash = (((c0 = source[startPosition]) << 6) + (c1 = source[startPosition + 1]))
2285         % TableSize;
2286     char[][] table = charArray_length[0][hash];
2287     int i = newEntry2;
2288     while (++i < InternalTableSize) {
2289       char[] charArray = table[i];
2290       if ((c0 == charArray[0]) && (c1 == charArray[1]))
2291         return charArray;
2292     }
2293     //---------other side---------
2294     i = -1;
2295     int max = newEntry2;
2296     while (++i <= max) {
2297       char[] charArray = table[i];
2298       if ((c0 == charArray[0]) && (c1 == charArray[1]))
2299         return charArray;
2300     }
2301     //--------add the entry-------
2302     if (++max >= InternalTableSize)
2303       max = 0;
2304     char[] r;
2305     table[max] = (r = new char[]{c0, c1});
2306     newEntry2 = max;
2307     return r;
2308   }
2309   final char[] optimizedCurrentTokenSource3() {
2310     //try to return the same char[] build only once
2311     char c0, c1, c2;
2312     int hash = (((c0 = source[startPosition]) << 12)
2313         + ((c1 = source[startPosition + 1]) << 6) + (c2 = source[startPosition + 2]))
2314         % TableSize;
2315     char[][] table = charArray_length[1][hash];
2316     int i = newEntry3;
2317     while (++i < InternalTableSize) {
2318       char[] charArray = table[i];
2319       if ((c0 == charArray[0]) && (c1 == charArray[1]) && (c2 == charArray[2]))
2320         return charArray;
2321     }
2322     //---------other side---------
2323     i = -1;
2324     int max = newEntry3;
2325     while (++i <= max) {
2326       char[] charArray = table[i];
2327       if ((c0 == charArray[0]) && (c1 == charArray[1]) && (c2 == charArray[2]))
2328         return charArray;
2329     }
2330     //--------add the entry-------
2331     if (++max >= InternalTableSize)
2332       max = 0;
2333     char[] r;
2334     table[max] = (r = new char[]{c0, c1, c2});
2335     newEntry3 = max;
2336     return r;
2337   }
2338   final char[] optimizedCurrentTokenSource4() {
2339     //try to return the same char[] build only once
2340     char c0, c1, c2, c3;
2341     long hash = ((((long) (c0 = source[startPosition])) << 18)
2342         + ((c1 = source[startPosition + 1]) << 12)
2343         + ((c2 = source[startPosition + 2]) << 6) + (c3 = source[startPosition + 3]))
2344         % TableSize;
2345     char[][] table = charArray_length[2][(int) hash];
2346     int i = newEntry4;
2347     while (++i < InternalTableSize) {
2348       char[] charArray = table[i];
2349       if ((c0 == charArray[0]) && (c1 == charArray[1]) && (c2 == charArray[2])
2350           && (c3 == charArray[3]))
2351         return charArray;
2352     }
2353     //---------other side---------
2354     i = -1;
2355     int max = newEntry4;
2356     while (++i <= max) {
2357       char[] charArray = table[i];
2358       if ((c0 == charArray[0]) && (c1 == charArray[1]) && (c2 == charArray[2])
2359           && (c3 == charArray[3]))
2360         return charArray;
2361     }
2362     //--------add the entry-------
2363     if (++max >= InternalTableSize)
2364       max = 0;
2365     char[] r;
2366     table[max] = (r = new char[]{c0, c1, c2, c3});
2367     newEntry4 = max;
2368     return r;
2369   }
2370   final char[] optimizedCurrentTokenSource5() {
2371     //try to return the same char[] build only once
2372     char c0, c1, c2, c3, c4;
2373     long hash = ((((long) (c0 = source[startPosition])) << 24)
2374         + (((long) (c1 = source[startPosition + 1])) << 18)
2375         + ((c2 = source[startPosition + 2]) << 12)
2376         + ((c3 = source[startPosition + 3]) << 6) + (c4 = source[startPosition + 4]))
2377         % TableSize;
2378     char[][] table = charArray_length[3][(int) hash];
2379     int i = newEntry5;
2380     while (++i < InternalTableSize) {
2381       char[] charArray = table[i];
2382       if ((c0 == charArray[0]) && (c1 == charArray[1]) && (c2 == charArray[2])
2383           && (c3 == charArray[3]) && (c4 == charArray[4]))
2384         return charArray;
2385     }
2386     //---------other side---------
2387     i = -1;
2388     int max = newEntry5;
2389     while (++i <= max) {
2390       char[] charArray = table[i];
2391       if ((c0 == charArray[0]) && (c1 == charArray[1]) && (c2 == charArray[2])
2392           && (c3 == charArray[3]) && (c4 == charArray[4]))
2393         return charArray;
2394     }
2395     //--------add the entry-------
2396     if (++max >= InternalTableSize)
2397       max = 0;
2398     char[] r;
2399     table[max] = (r = new char[]{c0, c1, c2, c3, c4});
2400     newEntry5 = max;
2401     return r;
2402   }
2403   final char[] optimizedCurrentTokenSource6() {
2404     //try to return the same char[] build only once
2405     char c0, c1, c2, c3, c4, c5;
2406     long hash = ((((long) (c0 = source[startPosition])) << 32)
2407         + (((long) (c1 = source[startPosition + 1])) << 24)
2408         + (((long) (c2 = source[startPosition + 2])) << 18)
2409         + ((c3 = source[startPosition + 3]) << 12)
2410         + ((c4 = source[startPosition + 4]) << 6) + (c5 = source[startPosition + 5]))
2411         % TableSize;
2412     char[][] table = charArray_length[4][(int) hash];
2413     int i = newEntry6;
2414     while (++i < InternalTableSize) {
2415       char[] charArray = table[i];
2416       if ((c0 == charArray[0]) && (c1 == charArray[1]) && (c2 == charArray[2])
2417           && (c3 == charArray[3]) && (c4 == charArray[4])
2418           && (c5 == charArray[5]))
2419         return charArray;
2420     }
2421     //---------other side---------
2422     i = -1;
2423     int max = newEntry6;
2424     while (++i <= max) {
2425       char[] charArray = table[i];
2426       if ((c0 == charArray[0]) && (c1 == charArray[1]) && (c2 == charArray[2])
2427           && (c3 == charArray[3]) && (c4 == charArray[4])
2428           && (c5 == charArray[5]))
2429         return charArray;
2430     }
2431     //--------add the entry-------
2432     if (++max >= InternalTableSize)
2433       max = 0;
2434     char[] r;
2435     table[max] = (r = new char[]{c0, c1, c2, c3, c4, c5});
2436     newEntry6 = max;
2437     return r;
2438   }
2439   public final void pushLineSeparator() throws InvalidInputException {
2440     //see comment on isLineDelimiter(char) for the use of '\n' and '\r'
2441     final int INCREMENT = 250;
2442     if (this.checkNonExternalizedStringLiterals) {
2443       // reinitialize the current line for non externalize strings purpose
2444       currentLine = null;
2445     }
2446     //currentCharacter is at position currentPosition-1
2447     // cr 000D
2448     if (currentCharacter == '\r') {
2449       int separatorPos = currentPosition - 1;
2450       if ((linePtr > 0) && (lineEnds[linePtr] >= separatorPos))
2451         return;
2452       //System.out.println("CR-" + separatorPos);
2453       try {
2454         lineEnds[++linePtr] = separatorPos;
2455       } catch (IndexOutOfBoundsException e) {
2456         //linePtr value is correct
2457         int oldLength = lineEnds.length;
2458         int[] old = lineEnds;
2459         lineEnds = new int[oldLength + INCREMENT];
2460         System.arraycopy(old, 0, lineEnds, 0, oldLength);
2461         lineEnds[linePtr] = separatorPos;
2462       }
2463       // look-ahead for merged cr+lf
2464       try {
2465         if (source[currentPosition] == '\n') {
2466           //System.out.println("look-ahead LF-" + currentPosition);
2467           lineEnds[linePtr] = currentPosition;
2468           currentPosition++;
2469           wasAcr = false;
2470         } else {
2471           wasAcr = true;
2472         }
2473       } catch (IndexOutOfBoundsException e) {
2474         wasAcr = true;
2475       }
2476     } else {
2477       // lf 000A
2478       if (currentCharacter == '\n') {
2479         //must merge eventual cr followed by lf
2480         if (wasAcr && (lineEnds[linePtr] == (currentPosition - 2))) {
2481           //System.out.println("merge LF-" + (currentPosition - 1));
2482           lineEnds[linePtr] = currentPosition - 1;
2483         } else {
2484           int separatorPos = currentPosition - 1;
2485           if ((linePtr > 0) && (lineEnds[linePtr] >= separatorPos))
2486             return;
2487           // System.out.println("LF-" + separatorPos);
2488           try {
2489             lineEnds[++linePtr] = separatorPos;
2490           } catch (IndexOutOfBoundsException e) {
2491             //linePtr value is correct
2492             int oldLength = lineEnds.length;
2493             int[] old = lineEnds;
2494             lineEnds = new int[oldLength + INCREMENT];
2495             System.arraycopy(old, 0, lineEnds, 0, oldLength);
2496             lineEnds[linePtr] = separatorPos;
2497           }
2498         }
2499         wasAcr = false;
2500       }
2501     }
2502   }
2503   public final void pushUnicodeLineSeparator() {
2504     // isUnicode means that the \r or \n has been read as a unicode character
2505     //see comment on isLineDelimiter(char) for the use of '\n' and '\r'
2506     final int INCREMENT = 250;
2507     //currentCharacter is at position currentPosition-1
2508     if (this.checkNonExternalizedStringLiterals) {
2509       // reinitialize the current line for non externalize strings purpose
2510       currentLine = null;
2511     }
2512     // cr 000D
2513     if (currentCharacter == '\r') {
2514       int separatorPos = currentPosition - 6;
2515       if ((linePtr > 0) && (lineEnds[linePtr] >= separatorPos))
2516         return;
2517       //System.out.println("CR-" + separatorPos);
2518       try {
2519         lineEnds[++linePtr] = separatorPos;
2520       } catch (IndexOutOfBoundsException e) {
2521         //linePtr value is correct
2522         int oldLength = lineEnds.length;
2523         int[] old = lineEnds;
2524         lineEnds = new int[oldLength + INCREMENT];
2525         System.arraycopy(old, 0, lineEnds, 0, oldLength);
2526         lineEnds[linePtr] = separatorPos;
2527       }
2528       // look-ahead for merged cr+lf
2529       if (source[currentPosition] == '\n') {
2530         //System.out.println("look-ahead LF-" + currentPosition);
2531         lineEnds[linePtr] = currentPosition;
2532         currentPosition++;
2533         wasAcr = false;
2534       } else {
2535         wasAcr = true;
2536       }
2537     } else {
2538       // lf 000A
2539       if (currentCharacter == '\n') {
2540         //must merge eventual cr followed by lf
2541         if (wasAcr && (lineEnds[linePtr] == (currentPosition - 7))) {
2542           //System.out.println("merge LF-" + (currentPosition - 1));
2543           lineEnds[linePtr] = currentPosition - 6;
2544         } else {
2545           int separatorPos = currentPosition - 6;
2546           if ((linePtr > 0) && (lineEnds[linePtr] >= separatorPos))
2547             return;
2548           // System.out.println("LF-" + separatorPos);
2549           try {
2550             lineEnds[++linePtr] = separatorPos;
2551           } catch (IndexOutOfBoundsException e) {
2552             //linePtr value is correct
2553             int oldLength = lineEnds.length;
2554             int[] old = lineEnds;
2555             lineEnds = new int[oldLength + INCREMENT];
2556             System.arraycopy(old, 0, lineEnds, 0, oldLength);
2557             lineEnds[linePtr] = separatorPos;
2558           }
2559         }
2560         wasAcr = false;
2561       }
2562     }
2563   }
2564   public final void recordComment(boolean isJavadoc) {
2565     // a new annotation comment is recorded
2566     try {
2567       commentStops[++commentPtr] = isJavadoc
2568           ? currentPosition
2569           : -currentPosition;
2570     } catch (IndexOutOfBoundsException e) {
2571       int oldStackLength = commentStops.length;
2572       int[] oldStack = commentStops;
2573       commentStops = new int[oldStackLength + 30];
2574       System.arraycopy(oldStack, 0, commentStops, 0, oldStackLength);
2575       commentStops[commentPtr] = isJavadoc ? currentPosition : -currentPosition;
2576       //grows the positions buffers too
2577       int[] old = commentStarts;
2578       commentStarts = new int[oldStackLength + 30];
2579       System.arraycopy(old, 0, commentStarts, 0, oldStackLength);
2580     }
2581     //the buffer is of a correct size here
2582     commentStarts[commentPtr] = startPosition;
2583   }
2584   public void resetTo(int begin, int end) {
2585     //reset the scanner to a given position where it may rescan again
2586     diet = false;
2587     initialPosition = startPosition = currentPosition = begin;
2588     eofPosition = end < Integer.MAX_VALUE ? end + 1 : end;
2589     commentPtr = -1; // reset comment stack
2590   }
2591   public final void scanSingleQuotedEscapeCharacter()
2592       throws InvalidInputException {
2593     // the string with "\\u" is a legal string of two chars \ and u
2594     //thus we use a direct access to the source (for regular cases).
2595     //    if (unicodeAsBackSlash) {
2596     //      // consume next character
2597     //      unicodeAsBackSlash = false;
2598     //      if (((currentCharacter = source[currentPosition++]) == '\\')
2599     //        && (source[currentPosition] == 'u')) {
2600     //        getNextUnicodeChar();
2601     //      } else {
2602     //        if (withoutUnicodePtr != 0) {
2603     //          withoutUnicodeBuffer[++withoutUnicodePtr] = currentCharacter;
2604     //        }
2605     //      }
2606     //    } else
2607     currentCharacter = source[currentPosition++];
2608     switch (currentCharacter) {
2609       case '\'' :
2610         currentCharacter = '\'';
2611         break;
2612       case '\\' :
2613         currentCharacter = '\\';
2614         break;
2615       default :
2616         currentCharacter = '\\';
2617         currentPosition--;
2618     }
2619   }
2620   public final void scanDoubleQuotedEscapeCharacter()
2621       throws InvalidInputException {
2622     // the string with "\\u" is a legal string of two chars \ and u
2623     //thus we use a direct access to the source (for regular cases).
2624     //    if (unicodeAsBackSlash) {
2625     //      // consume next character
2626     //      unicodeAsBackSlash = false;
2627     //      if (((currentCharacter = source[currentPosition++]) == '\\')
2628     //        && (source[currentPosition] == 'u')) {
2629     //        getNextUnicodeChar();
2630     //      } else {
2631     //        if (withoutUnicodePtr != 0) {
2632     //          withoutUnicodeBuffer[++withoutUnicodePtr] = currentCharacter;
2633     //        }
2634     //      }
2635     //    } else
2636     currentCharacter = source[currentPosition++];
2637     switch (currentCharacter) {
2638       //      case 'b' :
2639       //        currentCharacter = '\b';
2640       //        break;
2641       case 't' :
2642         currentCharacter = '\t';
2643         break;
2644       case 'n' :
2645         currentCharacter = '\n';
2646         break;
2647       //      case 'f' :
2648       //        currentCharacter = '\f';
2649       //        break;
2650       case 'r' :
2651         currentCharacter = '\r';
2652         break;
2653       case '\"' :
2654         currentCharacter = '\"';
2655         break;
2656       case '\'' :
2657         currentCharacter = '\'';
2658         break;
2659       case '\\' :
2660         currentCharacter = '\\';
2661         break;
2662       case '$' :
2663         currentCharacter = '$';
2664         break;
2665       default :
2666         // -----------octal escape--------------
2667         // OctalDigit
2668         // OctalDigit OctalDigit
2669         // ZeroToThree OctalDigit OctalDigit
2670         int number = Character.getNumericValue(currentCharacter);
2671         if (number >= 0 && number <= 7) {
2672           boolean zeroToThreeNot = number > 3;
2673           if (Character.isDigit(currentCharacter = source[currentPosition++])) {
2674             int digit = Character.getNumericValue(currentCharacter);
2675             if (digit >= 0 && digit <= 7) {
2676               number = (number * 8) + digit;
2677               if (Character
2678                   .isDigit(currentCharacter = source[currentPosition++])) {
2679                 if (zeroToThreeNot) { // has read \NotZeroToThree OctalDigit
2680                   // Digit --> ignore last character
2681                   currentPosition--;
2682                 } else {
2683                   digit = Character.getNumericValue(currentCharacter);
2684                   if (digit >= 0 && digit <= 7) {
2685                     // has read \ZeroToThree OctalDigit OctalDigit
2686                     number = (number * 8) + digit;
2687                   } else { // has read \ZeroToThree OctalDigit NonOctalDigit
2688                     // --> ignore last character
2689                     currentPosition--;
2690                   }
2691                 }
2692               } else { // has read \OctalDigit NonDigit--> ignore last
2693                 // character
2694                 currentPosition--;
2695               }
2696             } else { // has read \OctalDigit NonOctalDigit--> ignore last
2697               // character
2698               currentPosition--;
2699             }
2700           } else { // has read \OctalDigit --> ignore last character
2701             currentPosition--;
2702           }
2703           if (number > 255)
2704             throw new InvalidInputException(INVALID_ESCAPE);
2705           currentCharacter = (char) number;
2706         }
2707     //else
2708     //     throw new InvalidInputException(INVALID_ESCAPE);
2709     }
2710   }
2711   //  public int scanIdentifierOrKeyword() throws InvalidInputException {
2712   //    return scanIdentifierOrKeyword( false );
2713   //  }
2714   public int scanIdentifierOrKeyword(boolean isVariable)
2715       throws InvalidInputException {
2716     //test keywords
2717     //first dispatch on the first char.
2718     //then the length. If there are several
2719     //keywors with the same length AND the same first char, then do another
2720     //disptach on the second char :-)...cool....but fast !
2721     useAssertAsAnIndentifier = false;
2722     while (getNextCharAsJavaIdentifierPart()) {
2723     };
2724     if (isVariable) {
2725       //      if (new String(getCurrentTokenSource()).equals("$this")) {
2726       //        return TokenNamethis;
2727       //      }
2728       return TokenNameVariable;
2729     }
2730     int index, length;
2731     char[] data;
2732     char firstLetter;
2733     //    if (withoutUnicodePtr == 0)
2734     //quick test on length == 1 but not on length > 12 while most identifier
2735     //have a length which is <= 12...but there are lots of identifier with
2736     //only one char....
2737     //      {
2738     if ((length = currentPosition - startPosition) == 1)
2739       return TokenNameIdentifier;
2740     //  data = source;
2741     data = new char[length];
2742     index = startPosition;
2743     for (int i = 0; i < length; i++) {
2744       data[i] = Character.toLowerCase(source[index + i]);
2745     }
2746     index = 0;
2747     //    } else {
2748     //      if ((length = withoutUnicodePtr) == 1)
2749     //        return TokenNameIdentifier;
2750     //      // data = withoutUnicodeBuffer;
2751     //      data = new char[withoutUnicodeBuffer.length];
2752     //      for (int i = 0; i < withoutUnicodeBuffer.length; i++) {
2753     //        data[i] = Character.toLowerCase(withoutUnicodeBuffer[i]);
2754     //      }
2755     //      index = 1;
2756     //    }
2757     firstLetter = data[index];
2758     switch (firstLetter) {
2759       case '_' :
2760         switch (length) {
2761           case 8 :
2762             //__FILE__
2763             if ((data[++index] == '_') && (data[++index] == 'f')
2764                 && (data[++index] == 'i') && (data[++index] == 'l')
2765                 && (data[++index] == 'e') && (data[++index] == '_')
2766                 && (data[++index] == '_'))
2767               return TokenNameFILE;
2768             index = 0; //__LINE__
2769             if ((data[++index] == '_') && (data[++index] == 'l')
2770                 && (data[++index] == 'i') && (data[++index] == 'n')
2771                 && (data[++index] == 'e') && (data[++index] == '_')
2772                 && (data[++index] == '_'))
2773               return TokenNameLINE;
2774             break;
2775           case 9 :
2776             //__CLASS__
2777             if ((data[++index] == '_') && (data[++index] == 'c')
2778                 && (data[++index] == 'l') && (data[++index] == 'a')
2779                 && (data[++index] == 's') && (data[++index] == 's')
2780                 && (data[++index] == '_') && (data[++index] == '_'))
2781               return TokenNameCLASS_C;
2782             break;
2783           case 11 :
2784             //__METHOD__
2785             if ((data[++index] == '_') && (data[++index] == 'm')
2786                 && (data[++index] == 'e') && (data[++index] == 't')
2787                 && (data[++index] == 'h') && (data[++index] == 'o')
2788                 && (data[++index] == 'd') && (data[++index] == '_')
2789                 && (data[++index] == '_'))
2790               return TokenNameMETHOD_C;
2791             break;
2792           case 12 :
2793             //__FUNCTION__
2794             if ((data[++index] == '_') && (data[++index] == 'f')
2795                 && (data[++index] == 'u') && (data[++index] == 'n')
2796                 && (data[++index] == 'c') && (data[++index] == 't')
2797                 && (data[++index] == 'i') && (data[++index] == 'o')
2798                 && (data[++index] == 'n') && (data[++index] == '_')
2799                 && (data[++index] == '_'))
2800               return TokenNameFUNC_C;
2801             break;
2802         }
2803         return TokenNameIdentifier;
2804       case 'a' :
2805         // as and array abstract
2806         switch (length) {
2807           case 2 :
2808             //as
2809             if ((data[++index] == 's')) {
2810               return TokenNameas;
2811             } else {
2812               return TokenNameIdentifier;
2813             }
2814           case 3 :
2815             //and
2816             if ((data[++index] == 'n') && (data[++index] == 'd')) {
2817               return TokenNameand;
2818             } else {
2819               return TokenNameIdentifier;
2820             }
2821           case 5 :
2822             // array
2823             if ((data[++index] == 'r') && (data[++index] == 'r')
2824                 && (data[++index] == 'a') && (data[++index] == 'y'))
2825               return TokenNamearray;
2826             else
2827               return TokenNameIdentifier;
2828           case 8 :
2829             if ((data[++index] == 'b') && (data[++index] == 's')
2830                 && (data[++index] == 't') && (data[++index] == 'r')
2831                 && (data[++index] == 'a') && (data[++index] == 'c')
2832                 && (data[++index] == 't'))
2833               return TokenNameabstract;
2834             else
2835               return TokenNameIdentifier;
2836           default :
2837             return TokenNameIdentifier;
2838         }
2839       case 'b' :
2840         //break
2841         switch (length) {
2842           case 5 :
2843             if ((data[++index] == 'r') && (data[++index] == 'e')
2844                 && (data[++index] == 'a') && (data[++index] == 'k'))
2845               return TokenNamebreak;
2846             else
2847               return TokenNameIdentifier;
2848           default :
2849             return TokenNameIdentifier;
2850         }
2851       case 'c' :
2852         //case catch class clone const continue
2853         switch (length) {
2854           case 4 :
2855             if ((data[++index] == 'a') && (data[++index] == 's')
2856                 && (data[++index] == 'e'))
2857               return TokenNamecase;
2858             else
2859               return TokenNameIdentifier;
2860           case 5 :
2861             if ((data[++index] == 'a') && (data[++index] == 't')
2862                 && (data[++index] == 'c') && (data[++index] == 'h'))
2863               return TokenNamecatch;
2864             index = 0;
2865             if ((data[++index] == 'l') && (data[++index] == 'a')
2866                 && (data[++index] == 's') && (data[++index] == 's'))
2867               return TokenNameclass;
2868             index = 0;
2869             if ((data[++index] == 'l') && (data[++index] == 'o')
2870                 && (data[++index] == 'n') && (data[++index] == 'e'))
2871               return TokenNameclone;
2872             index = 0;
2873             if ((data[++index] == 'o') && (data[++index] == 'n')
2874                 && (data[++index] == 's') && (data[++index] == 't'))
2875               return TokenNameconst;
2876             else
2877               return TokenNameIdentifier;
2878           case 8 :
2879             if ((data[++index] == 'o') && (data[++index] == 'n')
2880                 && (data[++index] == 't') && (data[++index] == 'i')
2881                 && (data[++index] == 'n') && (data[++index] == 'u')
2882                 && (data[++index] == 'e'))
2883               return TokenNamecontinue;
2884             else
2885               return TokenNameIdentifier;
2886           default :
2887             return TokenNameIdentifier;
2888         }
2889       case 'd' :
2890         // declare default do die
2891         // TODO delete define ==> no keyword !
2892         switch (length) {
2893           case 2 :
2894             if ((data[++index] == 'o'))
2895               return TokenNamedo;
2896             else
2897               return TokenNameIdentifier;
2898           //          case 6 :
2899           //            if ((data[++index] == 'e')
2900           //              && (data[++index] == 'f')
2901           //              && (data[++index] == 'i')
2902           //              && (data[++index] == 'n')
2903           //              && (data[++index] == 'e'))
2904           //              return TokenNamedefine;
2905           //            else
2906           //              return TokenNameIdentifier;
2907           case 7 :
2908             if ((data[++index] == 'e') && (data[++index] == 'c')
2909                 && (data[++index] == 'l') && (data[++index] == 'a')
2910                 && (data[++index] == 'r') && (data[++index] == 'e'))
2911               return TokenNamedeclare;
2912             index = 0;
2913             if ((data[++index] == 'e') && (data[++index] == 'f')
2914                 && (data[++index] == 'a') && (data[++index] == 'u')
2915                 && (data[++index] == 'l') && (data[++index] == 't'))
2916               return TokenNamedefault;
2917             else
2918               return TokenNameIdentifier;
2919           default :
2920             return TokenNameIdentifier;
2921         }
2922       case 'e' :
2923         //echo else exit elseif extends eval
2924         switch (length) {
2925           case 4 :
2926             if ((data[++index] == 'c') && (data[++index] == 'h')
2927                 && (data[++index] == 'o'))
2928               return TokenNameecho;
2929             else if ((data[index] == 'l') && (data[++index] == 's')
2930                 && (data[++index] == 'e'))
2931               return TokenNameelse;
2932             else if ((data[index] == 'x') && (data[++index] == 'i')
2933                 && (data[++index] == 't'))
2934               return TokenNameexit;
2935             else if ((data[index] == 'v') && (data[++index] == 'a')
2936                 && (data[++index] == 'l'))
2937               return TokenNameeval;
2938             else
2939               return TokenNameIdentifier;
2940           case 5 :
2941             // endif empty
2942             if ((data[++index] == 'n') && (data[++index] == 'd')
2943                 && (data[++index] == 'i') && (data[++index] == 'f'))
2944               return TokenNameendif;
2945             if ((data[index] == 'm') && (data[++index] == 'p')
2946                 && (data[++index] == 't') && (data[++index] == 'y'))
2947               return TokenNameempty;
2948             else
2949               return TokenNameIdentifier;
2950           case 6 :
2951             // endfor
2952             if ((data[++index] == 'n') && (data[++index] == 'd')
2953                 && (data[++index] == 'f') && (data[++index] == 'o')
2954                 && (data[++index] == 'r'))
2955               return TokenNameendfor;
2956             else if ((data[index] == 'l') && (data[++index] == 's')
2957                 && (data[++index] == 'e') && (data[++index] == 'i')
2958                 && (data[++index] == 'f'))
2959               return TokenNameelseif;
2960             else
2961               return TokenNameIdentifier;
2962           case 7 :
2963             if ((data[++index] == 'x') && (data[++index] == 't')
2964                 && (data[++index] == 'e') && (data[++index] == 'n')
2965                 && (data[++index] == 'd') && (data[++index] == 's'))
2966               return TokenNameextends;
2967             else
2968               return TokenNameIdentifier;
2969           case 8 :
2970             // endwhile
2971             if ((data[++index] == 'n') && (data[++index] == 'd')
2972                 && (data[++index] == 'w') && (data[++index] == 'h')
2973                 && (data[++index] == 'i') && (data[++index] == 'l')
2974                 && (data[++index] == 'e'))
2975               return TokenNameendwhile;
2976             else
2977               return TokenNameIdentifier;
2978           case 9 :
2979             // endswitch
2980             if ((data[++index] == 'n') && (data[++index] == 'd')
2981                 && (data[++index] == 's') && (data[++index] == 'w')
2982                 && (data[++index] == 'i') && (data[++index] == 't')
2983                 && (data[++index] == 'c') && (data[++index] == 'h'))
2984               return TokenNameendswitch;
2985             else
2986               return TokenNameIdentifier;
2987           case 10 :
2988             // enddeclare
2989             if ((data[++index] == 'n') && (data[++index] == 'd')
2990                 && (data[++index] == 'd') && (data[++index] == 'e')
2991                 && (data[++index] == 'c') && (data[++index] == 'l')
2992                 && (data[++index] == 'a') && (data[++index] == 'r')
2993                 && (data[++index] == 'e'))
2994               return TokenNameendforeach;
2995             index = 0;
2996             if ((data[++index] == 'n') // endforeach
2997                 && (data[++index] == 'd') && (data[++index] == 'f')
2998                 && (data[++index] == 'o') && (data[++index] == 'r')
2999                 && (data[++index] == 'e') && (data[++index] == 'a')
3000                 && (data[++index] == 'c') && (data[++index] == 'h'))
3001               return TokenNameendforeach;
3002             else
3003               return TokenNameIdentifier;
3004           default :
3005             return TokenNameIdentifier;
3006         }
3007       case 'f' :
3008         //for false final function
3009         switch (length) {
3010           case 3 :
3011             if ((data[++index] == 'o') && (data[++index] == 'r'))
3012               return TokenNamefor;
3013             else
3014               return TokenNameIdentifier;
3015           case 5 :
3016             //            if ((data[++index] == 'a') && (data[++index] == 'l')
3017             //                && (data[++index] == 's') && (data[++index] == 'e'))
3018             //              return TokenNamefalse;
3019             if ((data[++index] == 'i') && (data[++index] == 'n')
3020                 && (data[++index] == 'a') && (data[++index] == 'l'))
3021               return TokenNamefinal;
3022             else
3023               return TokenNameIdentifier;
3024           case 7 :
3025             // foreach
3026             if ((data[++index] == 'o') && (data[++index] == 'r')
3027                 && (data[++index] == 'e') && (data[++index] == 'a')
3028                 && (data[++index] == 'c') && (data[++index] == 'h'))
3029               return TokenNameforeach;
3030             else
3031               return TokenNameIdentifier;
3032           case 8 :
3033             // function
3034             if ((data[++index] == 'u') && (data[++index] == 'n')
3035                 && (data[++index] == 'c') && (data[++index] == 't')
3036                 && (data[++index] == 'i') && (data[++index] == 'o')
3037                 && (data[++index] == 'n'))
3038               return TokenNamefunction;
3039             else
3040               return TokenNameIdentifier;
3041           default :
3042             return TokenNameIdentifier;
3043         }
3044       case 'g' :
3045         //global
3046         if (length == 6) {
3047           if ((data[++index] == 'l') && (data[++index] == 'o')
3048               && (data[++index] == 'b') && (data[++index] == 'a')
3049               && (data[++index] == 'l')) {
3050             return TokenNameglobal;
3051           }
3052         }
3053         return TokenNameIdentifier;
3054       case 'i' :
3055         //if int isset include include_once instanceof interface implements
3056         switch (length) {
3057           case 2 :
3058             if (data[++index] == 'f')
3059               return TokenNameif;
3060             else
3061               return TokenNameIdentifier;
3062           //          case 3 :
3063           //            if ((data[++index] == 'n') && (data[++index] == 't'))
3064           //              return TokenNameint;
3065           //            else
3066           //              return TokenNameIdentifier;
3067           case 5 :
3068             if ((data[++index] == 's') && (data[++index] == 's')
3069                 && (data[++index] == 'e') && (data[++index] == 't'))
3070               return TokenNameisset;
3071             else
3072               return TokenNameIdentifier;
3073           case 7 :
3074             if ((data[++index] == 'n') && (data[++index] == 'c')
3075                 && (data[++index] == 'l') && (data[++index] == 'u')
3076                 && (data[++index] == 'd') && (data[++index] == 'e'))
3077               return TokenNameinclude;
3078             else
3079               return TokenNameIdentifier;
3080           case 9 :
3081             // interface
3082             if ((data[++index] == 'n') && (data[++index] == 't')
3083                 && (data[++index] == 'e') && (data[++index] == 'r')
3084                 && (data[++index] == 'f') && (data[++index] == 'a')
3085                 && (data[++index] == 'c') && (data[++index] == 'e'))
3086               return TokenNameinterface;
3087             else
3088               return TokenNameIdentifier;
3089           case 10 :
3090             // instanceof
3091             if ((data[++index] == 'n') && (data[++index] == 's')
3092                 && (data[++index] == 't') && (data[++index] == 'a')
3093                 && (data[++index] == 'n') && (data[++index] == 'c')
3094                 && (data[++index] == 'e') && (data[++index] == 'o')
3095                 && (data[++index] == 'f'))
3096               return TokenNameinstanceof;
3097             if ((data[index] == 'm') && (data[++index] == 'p')
3098                 && (data[++index] == 'l') && (data[++index] == 'e')
3099                 && (data[++index] == 'm') && (data[++index] == 'e')
3100                 && (data[++index] == 'n') && (data[++index] == 't')
3101                 && (data[++index] == 's'))
3102               return TokenNameimplements;
3103             else
3104               return TokenNameIdentifier;
3105           case 12 :
3106             if ((data[++index] == 'n') && (data[++index] == 'c')
3107                 && (data[++index] == 'l') && (data[++index] == 'u')
3108                 && (data[++index] == 'd') && (data[++index] == 'e')
3109                 && (data[++index] == '_') && (data[++index] == 'o')
3110                 && (data[++index] == 'n') && (data[++index] == 'c')
3111                 && (data[++index] == 'e'))
3112               return TokenNameinclude_once;
3113             else
3114               return TokenNameIdentifier;
3115           default :
3116             return TokenNameIdentifier;
3117         }
3118       case 'l' :
3119         //list
3120         if (length == 4) {
3121           if ((data[++index] == 'i') && (data[++index] == 's')
3122               && (data[++index] == 't')) {
3123             return TokenNamelist;
3124           }
3125         }
3126         return TokenNameIdentifier;
3127       case 'n' :
3128         // new null
3129         switch (length) {
3130           case 3 :
3131             if ((data[++index] == 'e') && (data[++index] == 'w'))
3132               return TokenNamenew;
3133             else
3134               return TokenNameIdentifier;
3135           //          case 4 :
3136           //            if ((data[++index] == 'u') && (data[++index] == 'l')
3137           //                && (data[++index] == 'l'))
3138           //              return TokenNamenull;
3139           //            else
3140           //              return TokenNameIdentifier;
3141           default :
3142             return TokenNameIdentifier;
3143         }
3144       case 'o' :
3145         // or old_function
3146         if (length == 2) {
3147           if (data[++index] == 'r') {
3148             return TokenNameor;
3149           }
3150         }
3151         //        if (length == 12) {
3152         //          if ((data[++index] == 'l')
3153         //            && (data[++index] == 'd')
3154         //            && (data[++index] == '_')
3155         //            && (data[++index] == 'f')
3156         //            && (data[++index] == 'u')
3157         //            && (data[++index] == 'n')
3158         //            && (data[++index] == 'c')
3159         //            && (data[++index] == 't')
3160         //            && (data[++index] == 'i')
3161         //            && (data[++index] == 'o')
3162         //            && (data[++index] == 'n')) {
3163         //            return TokenNameold_function;
3164         //          }
3165         //        }
3166         return TokenNameIdentifier;
3167       case 'p' :
3168         // print public private protected
3169         switch (length) {
3170           case 5 :
3171             if ((data[++index] == 'r') && (data[++index] == 'i')
3172                 && (data[++index] == 'n') && (data[++index] == 't')) {
3173               return TokenNameprint;
3174             } else
3175               return TokenNameIdentifier;
3176           case 6 :
3177             if ((data[++index] == 'u') && (data[++index] == 'b')
3178                 && (data[++index] == 'l') && (data[++index] == 'i')
3179                 && (data[++index] == 'c')) {
3180               return TokenNamepublic;
3181             } else
3182               return TokenNameIdentifier;
3183           case 7 :
3184             if ((data[++index] == 'r') && (data[++index] == 'i')
3185                 && (data[++index] == 'v') && (data[++index] == 'a')
3186                 && (data[++index] == 't') && (data[++index] == 'e')) {
3187               return TokenNameprivate;
3188             } else
3189               return TokenNameIdentifier;
3190           case 9 :
3191             if ((data[++index] == 'r') && (data[++index] == 'o')
3192                 && (data[++index] == 't') && (data[++index] == 'e')
3193                 && (data[++index] == 'c') && (data[++index] == 't')
3194                 && (data[++index] == 'e') && (data[++index] == 'd')) {
3195               return TokenNameprotected;
3196             } else
3197               return TokenNameIdentifier;
3198         }
3199         return TokenNameIdentifier;
3200       case 'r' :
3201         //return require require_once
3202         if (length == 6) {
3203           if ((data[++index] == 'e') && (data[++index] == 't')
3204               && (data[++index] == 'u') && (data[++index] == 'r')
3205               && (data[++index] == 'n')) {
3206             return TokenNamereturn;
3207           }
3208         } else if (length == 7) {
3209           if ((data[++index] == 'e') && (data[++index] == 'q')
3210               && (data[++index] == 'u') && (data[++index] == 'i')
3211               && (data[++index] == 'r') && (data[++index] == 'e')) {
3212             return TokenNamerequire;
3213           }
3214         } else if (length == 12) {
3215           if ((data[++index] == 'e') && (data[++index] == 'q')
3216               && (data[++index] == 'u') && (data[++index] == 'i')
3217               && (data[++index] == 'r') && (data[++index] == 'e')
3218               && (data[++index] == '_') && (data[++index] == 'o')
3219               && (data[++index] == 'n') && (data[++index] == 'c')
3220               && (data[++index] == 'e')) {
3221             return TokenNamerequire_once;
3222           }
3223         } else
3224           return TokenNameIdentifier;
3225       case 's' :
3226         //static switch
3227         switch (length) {
3228           case 6 :
3229             if (data[++index] == 't')
3230               if ((data[++index] == 'a') && (data[++index] == 't')
3231                   && (data[++index] == 'i') && (data[++index] == 'c')) {
3232                 return TokenNamestatic;
3233               } else
3234                 return TokenNameIdentifier;
3235             else if ((data[index] == 'w') && (data[++index] == 'i')
3236                 && (data[++index] == 't') && (data[++index] == 'c')
3237                 && (data[++index] == 'h'))
3238               return TokenNameswitch;
3239             else
3240               return TokenNameIdentifier;
3241           default :
3242             return TokenNameIdentifier;
3243         }
3244       case 't' :
3245         // try true throw
3246         switch (length) {
3247           case 3 :
3248             if ((data[++index] == 'r') && (data[++index] == 'y'))
3249               return TokenNametry;
3250             else
3251               return TokenNameIdentifier;
3252           //          case 4 :
3253           //            if ((data[++index] == 'r') && (data[++index] == 'u')
3254           //                && (data[++index] == 'e'))
3255           //              return TokenNametrue;
3256           //            else
3257           //              return TokenNameIdentifier;
3258           case 5 :
3259             if ((data[++index] == 'h') && (data[++index] == 'r')
3260                 && (data[++index] == 'o') && (data[++index] == 'w'))
3261               return TokenNamethrow;
3262             else
3263               return TokenNameIdentifier;
3264           default :
3265             return TokenNameIdentifier;
3266         }
3267       case 'u' :
3268         //use unset
3269         switch (length) {
3270           case 3 :
3271             if ((data[++index] == 's') && (data[++index] == 'e'))
3272               return TokenNameuse;
3273             else
3274               return TokenNameIdentifier;
3275           case 5 :
3276             if ((data[++index] == 'n') && (data[++index] == 's')
3277                 && (data[++index] == 'e') && (data[++index] == 't'))
3278               return TokenNameunset;
3279             else
3280               return TokenNameIdentifier;
3281           default :
3282             return TokenNameIdentifier;
3283         }
3284       case 'v' :
3285         //var
3286         switch (length) {
3287           case 3 :
3288             if ((data[++index] == 'a') && (data[++index] == 'r'))
3289               return TokenNamevar;
3290             else
3291               return TokenNameIdentifier;
3292           default :
3293             return TokenNameIdentifier;
3294         }
3295       case 'w' :
3296         //while
3297         switch (length) {
3298           case 5 :
3299             if ((data[++index] == 'h') && (data[++index] == 'i')
3300                 && (data[++index] == 'l') && (data[++index] == 'e'))
3301               return TokenNamewhile;
3302             else
3303               return TokenNameIdentifier;
3304           //case 6:if ( (data[++index] =='i') && (data[++index]=='d') &&
3305           // (data[++index]=='e') && (data[++index]=='f')&&
3306           // (data[++index]=='p'))
3307           //return TokenNamewidefp ;
3308           //else
3309           //return TokenNameIdentifier;
3310           default :
3311             return TokenNameIdentifier;
3312         }
3313       case 'x' :
3314         //xor
3315         switch (length) {
3316           case 3 :
3317             if ((data[++index] == 'o') && (data[++index] == 'r'))
3318               return TokenNamexor;
3319             else
3320               return TokenNameIdentifier;
3321           default :
3322             return TokenNameIdentifier;
3323         }
3324       default :
3325         return TokenNameIdentifier;
3326     }
3327   }
3328   public int scanNumber(boolean dotPrefix) throws InvalidInputException {
3329     //when entering this method the currentCharacter is the firt
3330     //digit of the number , i.e. it may be preceeded by a . when
3331     //dotPrefix is true
3332     boolean floating = dotPrefix;
3333     if ((!dotPrefix) && (currentCharacter == '0')) {
3334       if (getNextChar('x', 'X') >= 0) { //----------hexa-----------------
3335         //force the first char of the hexa number do exist...
3336         // consume next character
3337         unicodeAsBackSlash = false;
3338         currentCharacter = source[currentPosition++];
3339         //        if (((currentCharacter = source[currentPosition++]) == '\\')
3340         //          && (source[currentPosition] == 'u')) {
3341         //          getNextUnicodeChar();
3342         //        } else {
3343         //          if (withoutUnicodePtr != 0) {
3344         //            withoutUnicodeBuffer[++withoutUnicodePtr] = currentCharacter;
3345         //          }
3346         //        }
3347         if (Character.digit(currentCharacter, 16) == -1)
3348           throw new InvalidInputException(INVALID_HEXA);
3349         //---end forcing--
3350         while (getNextCharAsDigit(16)) {
3351         };
3352         //        if (getNextChar('l', 'L') >= 0)
3353         //          return TokenNameLongLiteral;
3354         //        else
3355         return TokenNameIntegerLiteral;
3356       }
3357       //there is x or X in the number
3358       //potential octal ! ... some one may write 000099.0 ! thus 00100 <
3359       // 00078.0 is true !!!!! crazy language
3360       if (getNextCharAsDigit()) {
3361         //-------------potential octal-----------------
3362         while (getNextCharAsDigit()) {
3363         };
3364         //        if (getNextChar('l', 'L') >= 0) {
3365         //          return TokenNameLongLiteral;
3366         //        }
3367         //
3368         //        if (getNextChar('f', 'F') >= 0) {
3369         //          return TokenNameFloatingPointLiteral;
3370         //        }
3371         if (getNextChar('d', 'D') >= 0) {
3372           return TokenNameDoubleLiteral;
3373         } else { //make the distinction between octal and float ....
3374           if (getNextChar('.')) { //bingo ! ....
3375             while (getNextCharAsDigit()) {
3376             };
3377             if (getNextChar('e', 'E') >= 0) {
3378               // consume next character
3379               unicodeAsBackSlash = false;
3380               currentCharacter = source[currentPosition++];
3381               //              if (((currentCharacter = source[currentPosition++]) == '\\')
3382               //                && (source[currentPosition] == 'u')) {
3383               //                getNextUnicodeChar();
3384               //              } else {
3385               //                if (withoutUnicodePtr != 0) {
3386               //                  withoutUnicodeBuffer[++withoutUnicodePtr] = currentCharacter;
3387               //                }
3388               //              }
3389               if ((currentCharacter == '-') || (currentCharacter == '+')) {
3390                 // consume next character
3391                 unicodeAsBackSlash = false;
3392                 currentCharacter = source[currentPosition++];
3393                 //                if (((currentCharacter = source[currentPosition++]) == '\\')
3394                 //                  && (source[currentPosition] == 'u')) {
3395                 //                  getNextUnicodeChar();
3396                 //                } else {
3397                 //                  if (withoutUnicodePtr != 0) {
3398                 //                    withoutUnicodeBuffer[++withoutUnicodePtr] =
3399                 //                      currentCharacter;
3400                 //                  }
3401                 //                }
3402               }
3403               if (!Character.isDigit(currentCharacter))
3404                 throw new InvalidInputException(INVALID_FLOAT);
3405               while (getNextCharAsDigit()) {
3406               };
3407             }
3408             //            if (getNextChar('f', 'F') >= 0)
3409             //              return TokenNameFloatingPointLiteral;
3410             getNextChar('d', 'D'); //jump over potential d or D
3411             return TokenNameDoubleLiteral;
3412           } else {
3413             return TokenNameIntegerLiteral;
3414           }
3415         }
3416       } else {
3417         /* carry on */
3418       }
3419     }
3420     while (getNextCharAsDigit()) {
3421     };
3422     //    if ((!dotPrefix) && (getNextChar('l', 'L') >= 0))
3423     //      return TokenNameLongLiteral;
3424     if ((!dotPrefix) && (getNextChar('.'))) { //decimal part that can be empty
3425       while (getNextCharAsDigit()) {
3426       };
3427       floating = true;
3428     }
3429     //if floating is true both exponant and suffix may be optional
3430     if (getNextChar('e', 'E') >= 0) {
3431       floating = true;
3432       // consume next character
3433       unicodeAsBackSlash = false;
3434       currentCharacter = source[currentPosition++];
3435       //      if (((currentCharacter = source[currentPosition++]) == '\\')
3436       //        && (source[currentPosition] == 'u')) {
3437       //        getNextUnicodeChar();
3438       //      } else {
3439       //        if (withoutUnicodePtr != 0) {
3440       //          withoutUnicodeBuffer[++withoutUnicodePtr] = currentCharacter;
3441       //        }
3442       //      }
3443       if ((currentCharacter == '-') || (currentCharacter == '+')) { // consume
3444         // next
3445         // character
3446         unicodeAsBackSlash = false;
3447         currentCharacter = source[currentPosition++];
3448         //        if (((currentCharacter = source[currentPosition++]) == '\\')
3449         //          && (source[currentPosition] == 'u')) {
3450         //          getNextUnicodeChar();
3451         //        } else {
3452         //          if (withoutUnicodePtr != 0) {
3453         //            withoutUnicodeBuffer[++withoutUnicodePtr] = currentCharacter;
3454         //          }
3455         //        }
3456       }
3457       if (!Character.isDigit(currentCharacter))
3458         throw new InvalidInputException(INVALID_FLOAT);
3459       while (getNextCharAsDigit()) {
3460       };
3461     }
3462     if (getNextChar('d', 'D') >= 0)
3463       return TokenNameDoubleLiteral;
3464     //    if (getNextChar('f', 'F') >= 0)
3465     //      return TokenNameFloatingPointLiteral;
3466     //the long flag has been tested before
3467     return floating ? TokenNameDoubleLiteral : TokenNameIntegerLiteral;
3468   }
3469   /**
3470    * Search the line number corresponding to a specific position
3471    *  
3472    */
3473   public final int getLineNumber(int position) {
3474     if (lineEnds == null)
3475       return 1;
3476     int length = linePtr + 1;
3477     if (length == 0)
3478       return 1;
3479     int g = 0, d = length - 1;
3480     int m = 0;
3481     while (g <= d) {
3482       m = (g + d) / 2;
3483       if (position < lineEnds[m]) {
3484         d = m - 1;
3485       } else if (position > lineEnds[m]) {
3486         g = m + 1;
3487       } else {
3488         return m + 1;
3489       }
3490     }
3491     if (position < lineEnds[m]) {
3492       return m + 1;
3493     }
3494     return m + 2;
3495   }
3496   public void setPHPMode(boolean mode) {
3497     phpMode = mode;
3498   }
3499   public final void setSource(char[] source) {
3500     //the source-buffer is set to sourceString
3501     if (source == null) {
3502       this.source = new char[0];
3503     } else {
3504       this.source = source;
3505     }
3506     startPosition = -1;
3507     initialPosition = currentPosition = 0;
3508     containsAssertKeyword = false;
3509     withoutUnicodeBuffer = new char[this.source.length];
3510     encapsedStringStack = new Stack();
3511   }
3512   public String toString() {
3513     if (startPosition == source.length)
3514       return "EOF\n\n" + new String(source); //$NON-NLS-1$
3515     if (currentPosition > source.length)
3516       return "behind the EOF :-( ....\n\n" + new String(source); //$NON-NLS-1$
3517     char front[] = new char[startPosition];
3518     System.arraycopy(source, 0, front, 0, startPosition);
3519     int middleLength = (currentPosition - 1) - startPosition + 1;
3520     char middle[];
3521     if (middleLength > -1) {
3522       middle = new char[middleLength];
3523       System.arraycopy(source, startPosition, middle, 0, middleLength);
3524     } else {
3525       middle = new char[0];
3526     }
3527     char end[] = new char[source.length - (currentPosition - 1)];
3528     System.arraycopy(source, (currentPosition - 1) + 1, end, 0, source.length
3529         - (currentPosition - 1) - 1);
3530     return new String(front)
3531         + "\n===============================\nStarts here -->" //$NON-NLS-1$
3532         + new String(middle)
3533         + "<-- Ends here\n===============================\n" //$NON-NLS-1$
3534         + new String(end);
3535   }
3536   public final String toStringAction(int act) {
3537     switch (act) {
3538       case TokenNameERROR :
3539         return "ScannerError"; // + new String(getCurrentTokenSource()) + ")";
3540       // //$NON-NLS-1$
3541       case TokenNameINLINE_HTML :
3542         return "Inline-HTML(" + new String(getCurrentTokenSource()) + ")"; //$NON-NLS-1$ //$NON-NLS-2$
3543       case TokenNameIdentifier :
3544         return "Identifier(" + new String(getCurrentTokenSource()) + ")"; //$NON-NLS-1$ //$NON-NLS-2$
3545       case TokenNameVariable :
3546         return "Variable(" + new String(getCurrentTokenSource()) + ")"; //$NON-NLS-1$ //$NON-NLS-2$
3547       case TokenNameabstract :
3548         return "abstract"; //$NON-NLS-1$
3549       case TokenNameand :
3550         return "AND"; //$NON-NLS-1$
3551       case TokenNamearray :
3552         return "array"; //$NON-NLS-1$
3553       case TokenNameas :
3554         return "as"; //$NON-NLS-1$
3555       case TokenNamebreak :
3556         return "break"; //$NON-NLS-1$
3557       case TokenNamecase :
3558         return "case"; //$NON-NLS-1$
3559       case TokenNameclass :
3560         return "class"; //$NON-NLS-1$
3561       case TokenNamecatch :
3562         return "catch"; //$NON-NLS-1$
3563       case TokenNameclone :
3564         //$NON-NLS-1$
3565         return "clone";
3566       case TokenNameconst :
3567         //$NON-NLS-1$
3568         return "const";
3569       case TokenNamecontinue :
3570         return "continue"; //$NON-NLS-1$
3571       case TokenNamedefault :
3572         return "default"; //$NON-NLS-1$
3573       //      case TokenNamedefine :
3574       //        return "define"; //$NON-NLS-1$
3575       case TokenNamedo :
3576         return "do"; //$NON-NLS-1$
3577       case TokenNameecho :
3578         return "echo"; //$NON-NLS-1$
3579       case TokenNameelse :
3580         return "else"; //$NON-NLS-1$
3581       case TokenNameelseif :
3582         return "elseif"; //$NON-NLS-1$
3583       case TokenNameendfor :
3584         return "endfor"; //$NON-NLS-1$
3585       case TokenNameendforeach :
3586         return "endforeach"; //$NON-NLS-1$
3587       case TokenNameendif :
3588         return "endif"; //$NON-NLS-1$
3589       case TokenNameendswitch :
3590         return "endswitch"; //$NON-NLS-1$
3591       case TokenNameendwhile :
3592         return "endwhile"; //$NON-NLS-1$
3593       case TokenNameextends :
3594         return "extends"; //$NON-NLS-1$
3595       //      case TokenNamefalse :
3596       //        return "false"; //$NON-NLS-1$
3597       case TokenNamefinal :
3598         return "final"; //$NON-NLS-1$
3599       case TokenNamefor :
3600         return "for"; //$NON-NLS-1$
3601       case TokenNameforeach :
3602         return "foreach"; //$NON-NLS-1$
3603       case TokenNamefunction :
3604         return "function"; //$NON-NLS-1$
3605       case TokenNameglobal :
3606         return "global"; //$NON-NLS-1$
3607       case TokenNameif :
3608         return "if"; //$NON-NLS-1$
3609       case TokenNameimplements :
3610         return "implements"; //$NON-NLS-1$
3611       case TokenNameinclude :
3612         return "include"; //$NON-NLS-1$
3613       case TokenNameinclude_once :
3614         return "include_once"; //$NON-NLS-1$
3615       case TokenNameinstanceof :
3616         return "instanceof"; //$NON-NLS-1$
3617       case TokenNameinterface :
3618         return "interface"; //$NON-NLS-1$
3619       case TokenNameisset :
3620         return "isset"; //$NON-NLS-1$
3621       case TokenNamelist :
3622         return "list"; //$NON-NLS-1$
3623       case TokenNamenew :
3624         return "new"; //$NON-NLS-1$
3625       //      case TokenNamenull :
3626       //        return "null"; //$NON-NLS-1$
3627       case TokenNameor :
3628         return "OR"; //$NON-NLS-1$
3629       case TokenNameprint :
3630         return "print"; //$NON-NLS-1$
3631       case TokenNameprivate :
3632         return "private"; //$NON-NLS-1$
3633       case TokenNameprotected :
3634         return "protected"; //$NON-NLS-1$
3635       case TokenNamepublic :
3636         return "public"; //$NON-NLS-1$
3637       case TokenNamerequire :
3638         return "require"; //$NON-NLS-1$
3639       case TokenNamerequire_once :
3640         return "require_once"; //$NON-NLS-1$
3641       case TokenNamereturn :
3642         return "return"; //$NON-NLS-1$
3643       case TokenNamestatic :
3644         return "static"; //$NON-NLS-1$
3645       case TokenNameswitch :
3646         return "switch"; //$NON-NLS-1$
3647       //      case TokenNametrue :
3648       //        return "true"; //$NON-NLS-1$
3649       case TokenNameunset :
3650         return "unset"; //$NON-NLS-1$
3651       case TokenNamevar :
3652         return "var"; //$NON-NLS-1$
3653       case TokenNamewhile :
3654         return "while"; //$NON-NLS-1$
3655       case TokenNamexor :
3656         return "XOR"; //$NON-NLS-1$
3657       //      case TokenNamethis :
3658       //        return "$this"; //$NON-NLS-1$
3659       case TokenNameIntegerLiteral :
3660         return "Integer(" + new String(getCurrentTokenSource()) + ")"; //$NON-NLS-1$ //$NON-NLS-2$
3661       case TokenNameDoubleLiteral :
3662         return "Double(" + new String(getCurrentTokenSource()) + ")"; //$NON-NLS-1$ //$NON-NLS-2$
3663       case TokenNameStringLiteral :
3664         return "StringLiteral(" + new String(getCurrentTokenSource()) + ")"; //$NON-NLS-1$ //$NON-NLS-2$
3665       case TokenNameStringConstant :
3666         return "StringConstant(" + new String(getCurrentTokenSource()) + ")"; //$NON-NLS-1$ //$NON-NLS-2$
3667       case TokenNameStringInterpolated :
3668         return "StringInterpolated(" + new String(getCurrentTokenSource())
3669             + ")"; //$NON-NLS-1$ //$NON-NLS-2$
3670       case TokenNameEncapsedString0 :
3671         return "`"; //$NON-NLS-1$  
3672       case TokenNameEncapsedString1 :
3673         return "\'"; //$NON-NLS-1$  
3674       case TokenNameEncapsedString2 :
3675         return "\""; //$NON-NLS-1$  
3676       case TokenNameSTRING :
3677         return "STRING(" + new String(getCurrentTokenSource()) + ")"; //$NON-NLS-1$ //$NON-NLS-2$
3678       case TokenNameHEREDOC :
3679         return "HEREDOC(" + new String(getCurrentTokenSource()) + ")"; //$NON-NLS-1$
3680       case TokenNamePLUS_PLUS :
3681         return "++"; //$NON-NLS-1$
3682       case TokenNameMINUS_MINUS :
3683         return "--"; //$NON-NLS-1$
3684       case TokenNameEQUAL_EQUAL :
3685         return "=="; //$NON-NLS-1$
3686       case TokenNameEQUAL_EQUAL_EQUAL :
3687         return "==="; //$NON-NLS-1$
3688       case TokenNameEQUAL_GREATER :
3689         return "=>"; //$NON-NLS-1$
3690       case TokenNameLESS_EQUAL :
3691         return "<="; //$NON-NLS-1$
3692       case TokenNameGREATER_EQUAL :
3693         return ">="; //$NON-NLS-1$
3694       case TokenNameNOT_EQUAL :
3695         return "!="; //$NON-NLS-1$
3696       case TokenNameNOT_EQUAL_EQUAL :
3697         return "!=="; //$NON-NLS-1$
3698       case TokenNameLEFT_SHIFT :
3699         return "<<"; //$NON-NLS-1$
3700       case TokenNameRIGHT_SHIFT :
3701         return ">>"; //$NON-NLS-1$
3702       case TokenNamePLUS_EQUAL :
3703         return "+="; //$NON-NLS-1$
3704       case TokenNameMINUS_EQUAL :
3705         return "-="; //$NON-NLS-1$
3706       case TokenNameMULTIPLY_EQUAL :
3707         return "*="; //$NON-NLS-1$
3708       case TokenNameDIVIDE_EQUAL :
3709         return "/="; //$NON-NLS-1$
3710       case TokenNameAND_EQUAL :
3711         return "&="; //$NON-NLS-1$
3712       case TokenNameOR_EQUAL :
3713         return "|="; //$NON-NLS-1$
3714       case TokenNameXOR_EQUAL :
3715         return "^="; //$NON-NLS-1$
3716       case TokenNameREMAINDER_EQUAL :
3717         return "%="; //$NON-NLS-1$
3718       case TokenNameDOT_EQUAL :
3719         return ".="; //$NON-NLS-1$
3720       case TokenNameLEFT_SHIFT_EQUAL :
3721         return "<<="; //$NON-NLS-1$
3722       case TokenNameRIGHT_SHIFT_EQUAL :
3723         return ">>="; //$NON-NLS-1$
3724       case TokenNameOR_OR :
3725         return "||"; //$NON-NLS-1$
3726       case TokenNameAND_AND :
3727         return "&&"; //$NON-NLS-1$
3728       case TokenNamePLUS :
3729         return "+"; //$NON-NLS-1$
3730       case TokenNameMINUS :
3731         return "-"; //$NON-NLS-1$
3732       case TokenNameMINUS_GREATER :
3733         return "->";
3734       case TokenNameNOT :
3735         return "!"; //$NON-NLS-1$
3736       case TokenNameREMAINDER :
3737         return "%"; //$NON-NLS-1$
3738       case TokenNameXOR :
3739         return "^"; //$NON-NLS-1$
3740       case TokenNameAND :
3741         return "&"; //$NON-NLS-1$
3742       case TokenNameMULTIPLY :
3743         return "*"; //$NON-NLS-1$
3744       case TokenNameOR :
3745         return "|"; //$NON-NLS-1$
3746       case TokenNameTWIDDLE :
3747         return "~"; //$NON-NLS-1$
3748       case TokenNameTWIDDLE_EQUAL :
3749         return "~="; //$NON-NLS-1$
3750       case TokenNameDIVIDE :
3751         return "/"; //$NON-NLS-1$
3752       case TokenNameGREATER :
3753         return ">"; //$NON-NLS-1$
3754       case TokenNameLESS :
3755         return "<"; //$NON-NLS-1$
3756       case TokenNameLPAREN :
3757         return "("; //$NON-NLS-1$
3758       case TokenNameRPAREN :
3759         return ")"; //$NON-NLS-1$
3760       case TokenNameLBRACE :
3761         return "{"; //$NON-NLS-1$
3762       case TokenNameRBRACE :
3763         return "}"; //$NON-NLS-1$
3764       case TokenNameLBRACKET :
3765         return "["; //$NON-NLS-1$
3766       case TokenNameRBRACKET :
3767         return "]"; //$NON-NLS-1$
3768       case TokenNameSEMICOLON :
3769         return ";"; //$NON-NLS-1$
3770       case TokenNameQUESTION :
3771         return "?"; //$NON-NLS-1$
3772       case TokenNameCOLON :
3773         return ":"; //$NON-NLS-1$
3774       case TokenNameCOMMA :
3775         return ","; //$NON-NLS-1$
3776       case TokenNameDOT :
3777         return "."; //$NON-NLS-1$
3778       case TokenNameEQUAL :
3779         return "="; //$NON-NLS-1$
3780       case TokenNameAT :
3781         return "@";
3782       case TokenNameDOLLAR :
3783         return "$";
3784       case TokenNameDOLLAR_LBRACE :
3785         return "${";
3786       case TokenNameEOF :
3787         return "EOF"; //$NON-NLS-1$
3788       case TokenNameWHITESPACE :
3789         return "WHITESPACE(" + new String(getCurrentTokenSource()) + ")"; //$NON-NLS-1$
3790       case TokenNameCOMMENT_LINE :
3791         return "COMMENT_LINE(" + new String(getCurrentTokenSource()) + ")"; //$NON-NLS-1$
3792       case TokenNameCOMMENT_BLOCK :
3793         return "COMMENT_BLOCK(" + new String(getCurrentTokenSource()) + ")"; //$NON-NLS-1$
3794       case TokenNameCOMMENT_PHPDOC :
3795         return "COMMENT_PHPDOC(" + new String(getCurrentTokenSource()) + ")"; //$NON-NLS-1$
3796       //      case TokenNameHTML :
3797       //        return "HTML(" + new String(getCurrentTokenSource()) + ")";
3798       // //$NON-NLS-1$
3799       case TokenNameFILE :
3800         return "__FILE__"; //$NON-NLS-1$
3801       case TokenNameLINE :
3802         return "__LINE__"; //$NON-NLS-1$
3803       case TokenNameCLASS_C :
3804         return "__CLASS__"; //$NON-NLS-1$
3805       case TokenNameMETHOD_C :
3806         return "__METHOD__"; //$NON-NLS-1$
3807       case TokenNameFUNC_C :
3808         return "__FUNCTION__"; //$NON-NLS-1
3809       case TokenNameboolCAST :
3810         return "( bool )"; //$NON-NLS-1$
3811       case TokenNameintCAST :
3812         return "( int )"; //$NON-NLS-1$
3813       case TokenNamedoubleCAST :
3814         return "( double )"; //$NON-NLS-1$
3815       case TokenNameobjectCAST :
3816         return "( object )"; //$NON-NLS-1$
3817       case TokenNamestringCAST :
3818         return "( string )"; //$NON-NLS-1$
3819       default :
3820         return "not-a-token(" + (new Integer(act)) + ") "
3821             + new String(getCurrentTokenSource()); //$NON-NLS-1$
3822     }
3823   }
3824   public Scanner(boolean tokenizeComments, boolean tokenizeWhiteSpace,
3825       boolean checkNonExternalizedStringLiterals) {
3826     this(tokenizeComments, tokenizeWhiteSpace,
3827         checkNonExternalizedStringLiterals, false);
3828   }
3829   public Scanner(boolean tokenizeComments, boolean tokenizeWhiteSpace,
3830       boolean checkNonExternalizedStringLiterals, boolean assertMode) {
3831     this(tokenizeComments, tokenizeWhiteSpace,
3832         checkNonExternalizedStringLiterals, assertMode, false);
3833   }
3834   public Scanner(boolean tokenizeComments, boolean tokenizeWhiteSpace,
3835       boolean checkNonExternalizedStringLiterals, boolean assertMode,
3836       boolean tokenizeStrings) {
3837     this.eofPosition = Integer.MAX_VALUE;
3838     this.tokenizeComments = tokenizeComments;
3839     this.tokenizeWhiteSpace = tokenizeWhiteSpace;
3840     this.tokenizeStrings = tokenizeStrings;
3841     this.checkNonExternalizedStringLiterals = checkNonExternalizedStringLiterals;
3842     this.assertMode = assertMode;
3843     this.encapsedStringStack = null;
3844   }
3845   private void checkNonExternalizeString() throws InvalidInputException {
3846     if (currentLine == null)
3847       return;
3848     parseTags(currentLine);
3849   }
3850   private void parseTags(NLSLine line) throws InvalidInputException {
3851     String s = new String(getCurrentTokenSource());
3852     int pos = s.indexOf(TAG_PREFIX);
3853     int lineLength = line.size();
3854     while (pos != -1) {
3855       int start = pos + TAG_PREFIX_LENGTH;
3856       int end = s.indexOf(TAG_POSTFIX, start);
3857       String index = s.substring(start, end);
3858       int i = 0;
3859       try {
3860         i = Integer.parseInt(index) - 1;
3861         // Tags are one based not zero based.
3862       } catch (NumberFormatException e) {
3863         i = -1; // we don't want to consider this as a valid NLS tag
3864       }
3865       if (line.exists(i)) {
3866         line.set(i, null);
3867       }
3868       pos = s.indexOf(TAG_PREFIX, start);
3869     }
3870     this.nonNLSStrings = new StringLiteral[lineLength];
3871     int nonNLSCounter = 0;
3872     for (Iterator iterator = line.iterator(); iterator.hasNext();) {
3873       StringLiteral literal = (StringLiteral) iterator.next();
3874       if (literal != null) {
3875         this.nonNLSStrings[nonNLSCounter++] = literal;
3876       }
3877     }
3878     if (nonNLSCounter == 0) {
3879       this.nonNLSStrings = null;
3880       currentLine = null;
3881       return;
3882     }
3883     this.wasNonExternalizedStringLiteral = true;
3884     if (nonNLSCounter != lineLength) {
3885       System.arraycopy(this.nonNLSStrings, 0,
3886           (this.nonNLSStrings = new StringLiteral[nonNLSCounter]), 0,
3887           nonNLSCounter);
3888     }
3889     currentLine = null;
3890   }
3891   public final void scanEscapeCharacter() throws InvalidInputException {
3892     // the string with "\\u" is a legal string of two chars \ and u
3893     //thus we use a direct access to the source (for regular cases).
3894     if (unicodeAsBackSlash) {
3895       // consume next character
3896       unicodeAsBackSlash = false;
3897       //                        if (((currentCharacter = source[currentPosition++]) == '\\') &&
3898       // (source[currentPosition] == 'u')) {
3899       //                                getNextUnicodeChar();
3900       //                        } else {
3901       if (withoutUnicodePtr != 0) {
3902         withoutUnicodeBuffer[++withoutUnicodePtr] = currentCharacter;
3903         //                              }
3904       }
3905     } else
3906       currentCharacter = source[currentPosition++];
3907     switch (currentCharacter) {
3908       case 'b' :
3909         currentCharacter = '\b';
3910         break;
3911       case 't' :
3912         currentCharacter = '\t';
3913         break;
3914       case 'n' :
3915         currentCharacter = '\n';
3916         break;
3917       case 'f' :
3918         currentCharacter = '\f';
3919         break;
3920       case 'r' :
3921         currentCharacter = '\r';
3922         break;
3923       case '\"' :
3924         currentCharacter = '\"';
3925         break;
3926       case '\'' :
3927         currentCharacter = '\'';
3928         break;
3929       case '\\' :
3930         currentCharacter = '\\';
3931         break;
3932       default :
3933         // -----------octal escape--------------
3934         // OctalDigit
3935         // OctalDigit OctalDigit
3936         // ZeroToThree OctalDigit OctalDigit
3937         int number = Character.getNumericValue(currentCharacter);
3938         if (number >= 0 && number <= 7) {
3939           boolean zeroToThreeNot = number > 3;
3940           if (Character.isDigit(currentCharacter = source[currentPosition++])) {
3941             int digit = Character.getNumericValue(currentCharacter);
3942             if (digit >= 0 && digit <= 7) {
3943               number = (number * 8) + digit;
3944               if (Character
3945                   .isDigit(currentCharacter = source[currentPosition++])) {
3946                 if (zeroToThreeNot) { // has read \NotZeroToThree OctalDigit
3947                   // Digit --> ignore last character
3948                   currentPosition--;
3949                 } else {
3950                   digit = Character.getNumericValue(currentCharacter);
3951                   if (digit >= 0 && digit <= 7) { // has read \ZeroToThree
3952                     // OctalDigit OctalDigit
3953                     number = (number * 8) + digit;
3954                   } else { // has read \ZeroToThree OctalDigit NonOctalDigit
3955                     // --> ignore last character
3956                     currentPosition--;
3957                   }
3958                 }
3959               } else { // has read \OctalDigit NonDigit--> ignore last
3960                 // character
3961                 currentPosition--;
3962               }
3963             } else { // has read \OctalDigit NonOctalDigit--> ignore last
3964               // character
3965               currentPosition--;
3966             }
3967           } else { // has read \OctalDigit --> ignore last character
3968             currentPosition--;
3969           }
3970           if (number > 255)
3971             throw new InvalidInputException(INVALID_ESCAPE);
3972           currentCharacter = (char) number;
3973         } else
3974           throw new InvalidInputException(INVALID_ESCAPE);
3975     }
3976   }
3977   // chech presence of task: tags
3978   public void checkTaskTag(int commentStart, int commentEnd) {
3979     // only look for newer task: tags
3980     if (this.foundTaskCount > 0
3981         && this.foundTaskPositions[this.foundTaskCount - 1][0] >= commentStart) {
3982       return;
3983     }
3984     int foundTaskIndex = this.foundTaskCount;
3985     nextChar : for (int i = commentStart; i < commentEnd
3986         && i < this.eofPosition; i++) {
3987       char[] tag = null;
3988       char[] priority = null;
3989       // check for tag occurrence
3990       nextTag : for (int itag = 0; itag < this.taskTags.length; itag++) {
3991         tag = this.taskTags[itag];
3992         priority = this.taskPriorities != null
3993             && itag < this.taskPriorities.length
3994             ? this.taskPriorities[itag]
3995             : null;
3996         int tagLength = tag.length;
3997         for (int t = 0; t < tagLength; t++) {
3998           if (this.source[i + t] != tag[t])
3999             continue nextTag;
4000         }
4001         if (this.foundTaskTags == null) {
4002           this.foundTaskTags = new char[5][];
4003           this.foundTaskMessages = new char[5][];
4004           this.foundTaskPriorities = new char[5][];
4005           this.foundTaskPositions = new int[5][];
4006         } else if (this.foundTaskCount == this.foundTaskTags.length) {
4007           System.arraycopy(this.foundTaskTags, 0,
4008               this.foundTaskTags = new char[this.foundTaskCount * 2][], 0,
4009               this.foundTaskCount);
4010           System.arraycopy(this.foundTaskMessages, 0,
4011               this.foundTaskMessages = new char[this.foundTaskCount * 2][], 0,
4012               this.foundTaskCount);
4013           System.arraycopy(this.foundTaskPriorities, 0,
4014               this.foundTaskPriorities = new char[this.foundTaskCount * 2][],
4015               0, this.foundTaskCount);
4016           System.arraycopy(this.foundTaskPositions, 0,
4017               this.foundTaskPositions = new int[this.foundTaskCount * 2][], 0,
4018               this.foundTaskCount);
4019         }
4020         this.foundTaskTags[this.foundTaskCount] = tag;
4021         this.foundTaskPriorities[this.foundTaskCount] = priority;
4022         this.foundTaskPositions[this.foundTaskCount] = new int[]{i,
4023             i + tagLength - 1};
4024         this.foundTaskMessages[this.foundTaskCount] = CharOperation.NO_CHAR;
4025         this.foundTaskCount++;
4026         i += tagLength - 1; // will be incremented when looping
4027       }
4028     }
4029     for (int i = foundTaskIndex; i < this.foundTaskCount; i++) {
4030       // retrieve message start and end positions
4031       int msgStart = this.foundTaskPositions[i][0]
4032           + this.foundTaskTags[i].length;
4033       int max_value = i + 1 < this.foundTaskCount
4034           ? this.foundTaskPositions[i + 1][0] - 1
4035           : commentEnd - 1;
4036       // at most beginning of next task
4037       if (max_value < msgStart)
4038         max_value = msgStart; // would only occur if tag is before EOF.
4039       int end = -1;
4040       char c;
4041       for (int j = msgStart; j < max_value; j++) {
4042         if ((c = this.source[j]) == '\n' || c == '\r') {
4043           end = j - 1;
4044           break;
4045         }
4046       }
4047       if (end == -1) {
4048         for (int j = max_value; j > msgStart; j--) {
4049           if ((c = this.source[j]) == '*') {
4050             end = j - 1;
4051             break;
4052           }
4053         }
4054         if (end == -1)
4055           end = max_value;
4056       }
4057       if (msgStart == end)
4058         continue; // empty
4059       // trim the message
4060       while (CharOperation.isWhitespace(source[end]) && msgStart <= end)
4061         end--;
4062       while (CharOperation.isWhitespace(source[msgStart]) && msgStart <= end)
4063         msgStart++;
4064       // update the end position of the task
4065       this.foundTaskPositions[i][1] = end;
4066       // get the message source
4067       final int messageLength = end - msgStart + 1;
4068       char[] message = new char[messageLength];
4069       System.arraycopy(source, msgStart, message, 0, messageLength);
4070       this.foundTaskMessages[i] = message;
4071     }
4072   }
4073 }