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