1 /*******************************************************************************
2 * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others.
3 * All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the Common Public License v0.5
5 * which accompanies this distribution, and is available at
6 * http://www.eclipse.org/legal/cpl-v05.html
9 * IBM Corporation - initial API and implementation
10 ******************************************************************************/
11 package net.sourceforge.phpdt.internal.compiler.parser;
13 import java.util.ArrayList;
14 import java.util.Iterator;
15 import java.util.List;
17 import net.sourceforge.phpdt.core.compiler.*;
18 import net.sourceforge.phpdt.internal.compiler.ast.StringLiteral;
20 public class Scanner implements IScanner, ITerminalSymbols {
23 - getNextToken() which return the current type of the token
24 (this value is not memorized by the scanner)
25 - getCurrentTokenSource() which provides with the token "REAL" source
26 (aka all unicode have been transformed into a correct char)
27 - sourceStart gives the position into the stream
28 - currentPosition-1 gives the sourceEnd position into the stream
32 private boolean assertMode;
33 public boolean useAssertAsAnIndentifier = false;
34 //flag indicating if processed source contains occurrences of keyword assert
35 public boolean containsAssertKeyword = false;
37 public boolean recordLineSeparator;
38 public boolean phpMode = false;
40 public char currentCharacter;
41 public int startPosition;
42 public int currentPosition;
43 public int initialPosition, eofPosition;
44 // after this position eof are generated instead of real token from the source
46 public boolean tokenizeComments;
47 public boolean tokenizeWhiteSpace;
49 //source should be viewed as a window (aka a part)
50 //of a entire very large stream
54 public char[] withoutUnicodeBuffer;
55 public int withoutUnicodePtr;
56 //when == 0 ==> no unicode in the current token
57 public boolean unicodeAsBackSlash = false;
59 public boolean scanningFloatLiteral = false;
61 //support for /** comments
62 //public char[][] comments = new char[10][];
63 public int[] commentStops = new int[10];
64 public int[] commentStarts = new int[10];
65 public int commentPtr = -1; // no comment test with commentPtr value -1
67 //diet parsing support - jump over some method body when requested
68 public boolean diet = false;
70 //support for the poor-line-debuggers ....
71 //remember the position of the cr/lf
72 public int[] lineEnds = new int[250];
73 public int linePtr = -1;
74 public boolean wasAcr = false;
76 public static final String END_OF_SOURCE = "End_Of_Source"; //$NON-NLS-1$
78 public static final String INVALID_HEXA = "Invalid_Hexa_Literal"; //$NON-NLS-1$
79 public static final String INVALID_OCTAL = "Invalid_Octal_Literal"; //$NON-NLS-1$
80 public static final String INVALID_CHARACTER_CONSTANT = "Invalid_Character_Constant"; //$NON-NLS-1$
81 public static final String INVALID_ESCAPE = "Invalid_Escape"; //$NON-NLS-1$
82 public static final String INVALID_INPUT = "Invalid_Input"; //$NON-NLS-1$
83 public static final String INVALID_UNICODE_ESCAPE = "Invalid_Unicode_Escape"; //$NON-NLS-1$
84 public static final String INVALID_FLOAT = "Invalid_Float_Literal"; //$NON-NLS-1$
86 public static final String NULL_SOURCE_STRING = "Null_Source_String"; //$NON-NLS-1$
87 public static final String UNTERMINATED_STRING = "Unterminated_String"; //$NON-NLS-1$
88 public static final String UNTERMINATED_COMMENT = "Unterminated_Comment"; //$NON-NLS-1$
89 public static final String INVALID_CHAR_IN_STRING = "Invalid_Char_In_String"; //$NON-NLS-1$
91 //----------------optimized identifier managment------------------
92 static final char[] charArray_a = new char[] { 'a' },
93 charArray_b = new char[] { 'b' },
94 charArray_c = new char[] { 'c' },
95 charArray_d = new char[] { 'd' },
96 charArray_e = new char[] { 'e' },
97 charArray_f = new char[] { 'f' },
98 charArray_g = new char[] { 'g' },
99 charArray_h = new char[] { 'h' },
100 charArray_i = new char[] { 'i' },
101 charArray_j = new char[] { 'j' },
102 charArray_k = new char[] { 'k' },
103 charArray_l = new char[] { 'l' },
104 charArray_m = new char[] { 'm' },
105 charArray_n = new char[] { 'n' },
106 charArray_o = new char[] { 'o' },
107 charArray_p = new char[] { 'p' },
108 charArray_q = new char[] { 'q' },
109 charArray_r = new char[] { 'r' },
110 charArray_s = new char[] { 's' },
111 charArray_t = new char[] { 't' },
112 charArray_u = new char[] { 'u' },
113 charArray_v = new char[] { 'v' },
114 charArray_w = new char[] { 'w' },
115 charArray_x = new char[] { 'x' },
116 charArray_y = new char[] { 'y' },
117 charArray_z = new char[] { 'z' };
119 static final char[] initCharArray =
120 new char[] { '\u0000', '\u0000', '\u0000', '\u0000', '\u0000', '\u0000' };
121 static final int TableSize = 30, InternalTableSize = 6;
123 public static final int OptimizedLength = 6;
125 final char[][][][] charArray_length =
126 new char[OptimizedLength][TableSize][InternalTableSize][];
127 // support for detecting non-externalized string literals
128 int currentLineNr = -1;
129 int previousLineNr = -1;
130 NLSLine currentLine = null;
131 List lines = new ArrayList();
132 public static final String TAG_PREFIX = "//$NON-NLS-"; //$NON-NLS-1$
133 public static final int TAG_PREFIX_LENGTH = TAG_PREFIX.length();
134 public static final String TAG_POSTFIX = "$"; //$NON-NLS-1$
135 public static final int TAG_POSTFIX_LENGTH = TAG_POSTFIX.length();
136 public StringLiteral[] nonNLSStrings = null;
137 public boolean checkNonExternalizedStringLiterals = true;
138 public boolean wasNonExternalizedStringLiteral = false;
141 for (int i = 0; i < 6; i++) {
142 for (int j = 0; j < TableSize; j++) {
143 for (int k = 0; k < InternalTableSize; k++) {
144 charArray_length[i][j][k] = initCharArray;
149 static int newEntry2 = 0,
155 public static final int RoundBracket = 0;
156 public static final int SquareBracket = 1;
157 public static final int CurlyBracket = 2;
158 public static final int BracketKinds = 3;
160 public static final boolean DEBUG = false;
164 public Scanner(boolean tokenizeComments, boolean tokenizeWhiteSpace) {
165 this(tokenizeComments, tokenizeWhiteSpace, false);
169 * Determines if the specified character is
170 * permissible as the first character in a PHP identifier
172 public static boolean isPHPIdentifierStart(char ch) {
173 return Character.isLetter(ch) || (ch == '_');
177 * Determines if the specified character may be part of a PHP identifier as
178 * other than the first character
180 public static boolean isPHPIdentifierPart(char ch) {
181 return Character.isLetterOrDigit(ch) || (ch == '_');
184 public final boolean atEnd() {
185 // This code is not relevant if source is
186 // Only a part of the real stream input
188 return source.length == currentPosition;
190 public char[] getCurrentIdentifierSource() {
191 //return the token REAL source (aka unicodes are precomputed)
194 if (withoutUnicodePtr != 0)
195 //0 is used as a fast test flag so the real first char is in position 1
197 withoutUnicodeBuffer,
199 result = new char[withoutUnicodePtr],
203 int length = currentPosition - startPosition;
204 switch (length) { // see OptimizedLength
206 return optimizedCurrentTokenSource1();
208 return optimizedCurrentTokenSource2();
210 return optimizedCurrentTokenSource3();
212 return optimizedCurrentTokenSource4();
214 return optimizedCurrentTokenSource5();
216 return optimizedCurrentTokenSource6();
222 result = new char[length],
228 public int getCurrentTokenEndPosition() {
229 return this.currentPosition - 1;
231 public final char[] getCurrentTokenSource() {
232 // Return the token REAL source (aka unicodes are precomputed)
235 if (withoutUnicodePtr != 0)
236 // 0 is used as a fast test flag so the real first char is in position 1
238 withoutUnicodeBuffer,
240 result = new char[withoutUnicodePtr],
248 result = new char[length = currentPosition - startPosition],
255 public final char[] getCurrentTokenSource(int startPos) {
256 // Return the token REAL source (aka unicodes are precomputed)
259 if (withoutUnicodePtr != 0)
260 // 0 is used as a fast test flag so the real first char is in position 1
262 withoutUnicodeBuffer,
264 result = new char[withoutUnicodePtr],
272 result = new char[length = currentPosition - startPos],
279 public final char[] getCurrentTokenSourceString() {
280 //return the token REAL source (aka unicodes are precomputed).
281 //REMOVE the two " that are at the beginning and the end.
284 if (withoutUnicodePtr != 0)
285 //0 is used as a fast test flag so the real first char is in position 1
286 System.arraycopy(withoutUnicodeBuffer, 2,
287 //2 is 1 (real start) + 1 (to jump over the ")
288 result = new char[withoutUnicodePtr - 2], 0, withoutUnicodePtr - 2);
294 result = new char[length = currentPosition - startPosition - 2],
300 public int getCurrentTokenStartPosition() {
301 return this.startPosition;
304 * Search the source position corresponding to the end of a given line number
306 * Line numbers are 1-based, and relative to the scanner initialPosition.
307 * Character positions are 0-based.
309 * In case the given line number is inconsistent, answers -1.
311 public final int getLineEnd(int lineNumber) {
313 if (lineEnds == null)
315 if (lineNumber >= lineEnds.length)
320 if (lineNumber == lineEnds.length - 1)
322 return lineEnds[lineNumber - 1];
323 // next line start one character behind the lineEnd of the previous line
326 * Search the source position corresponding to the beginning of a given line number
328 * Line numbers are 1-based, and relative to the scanner initialPosition.
329 * Character positions are 0-based.
331 * e.g. getLineStart(1) --> 0 i.e. first line starts at character 0.
333 * In case the given line number is inconsistent, answers -1.
335 public final int getLineStart(int lineNumber) {
337 if (lineEnds == null)
339 if (lineNumber >= lineEnds.length)
345 return initialPosition;
346 return lineEnds[lineNumber - 2] + 1;
347 // next line start one character behind the lineEnd of the previous line
349 public final boolean getNextChar(char testedChar) {
351 //handle the case of unicode.
352 //when a unicode appears then we must use a buffer that holds char internal values
353 //At the end of this method currentCharacter holds the new visited char
354 //and currentPosition points right next after it
355 //Both previous lines are true if the currentCharacter is == to the testedChar
356 //On false, no side effect has occured.
358 //ALL getNextChar.... ARE OPTIMIZED COPIES
360 int temp = currentPosition;
362 if (((currentCharacter = source[currentPosition++]) == '\\')
363 && (source[currentPosition] == 'u')) {
364 //-------------unicode traitement ------------
368 while (source[currentPosition] == 'u') {
373 if (((c1 = Character.getNumericValue(source[currentPosition++])) > 15
375 || ((c2 = Character.getNumericValue(source[currentPosition++])) > 15
377 || ((c3 = Character.getNumericValue(source[currentPosition++])) > 15
379 || ((c4 = Character.getNumericValue(source[currentPosition++])) > 15
381 currentPosition = temp;
385 currentCharacter = (char) (((c1 * 16 + c2) * 16 + c3) * 16 + c4);
386 if (currentCharacter != testedChar) {
387 currentPosition = temp;
390 unicodeAsBackSlash = currentCharacter == '\\';
392 //need the unicode buffer
393 if (withoutUnicodePtr == 0) {
394 //buffer all the entries that have been left aside....
395 withoutUnicodePtr = currentPosition - unicodeSize - startPosition;
399 withoutUnicodeBuffer,
403 //fill the buffer with the char
404 withoutUnicodeBuffer[++withoutUnicodePtr] = currentCharacter;
407 } //-------------end unicode traitement--------------
409 if (currentCharacter != testedChar) {
410 currentPosition = temp;
413 unicodeAsBackSlash = false;
414 if (withoutUnicodePtr != 0)
415 withoutUnicodeBuffer[++withoutUnicodePtr] = currentCharacter;
418 } catch (IndexOutOfBoundsException e) {
419 unicodeAsBackSlash = false;
420 currentPosition = temp;
424 public final int getNextChar(char testedChar1, char testedChar2) {
425 //INT 0 : testChar1 \\\\///\\\\ 1 : testedChar2 \\\\///\\\\ -1 : others
426 //test can be done with (x==0) for the first and (x>0) for the second
427 //handle the case of unicode.
428 //when a unicode appears then we must use a buffer that holds char internal values
429 //At the end of this method currentCharacter holds the new visited char
430 //and currentPosition points right next after it
431 //Both previous lines are true if the currentCharacter is == to the testedChar1/2
432 //On false, no side effect has occured.
434 //ALL getNextChar.... ARE OPTIMIZED COPIES
436 int temp = currentPosition;
439 if (((currentCharacter = source[currentPosition++]) == '\\')
440 && (source[currentPosition] == 'u')) {
441 //-------------unicode traitement ------------
445 while (source[currentPosition] == 'u') {
450 if (((c1 = Character.getNumericValue(source[currentPosition++])) > 15
452 || ((c2 = Character.getNumericValue(source[currentPosition++])) > 15
454 || ((c3 = Character.getNumericValue(source[currentPosition++])) > 15
456 || ((c4 = Character.getNumericValue(source[currentPosition++])) > 15
458 currentPosition = temp;
462 currentCharacter = (char) (((c1 * 16 + c2) * 16 + c3) * 16 + c4);
463 if (currentCharacter == testedChar1)
465 else if (currentCharacter == testedChar2)
468 currentPosition = temp;
472 //need the unicode buffer
473 if (withoutUnicodePtr == 0) {
474 //buffer all the entries that have been left aside....
475 withoutUnicodePtr = currentPosition - unicodeSize - startPosition;
479 withoutUnicodeBuffer,
483 //fill the buffer with the char
484 withoutUnicodeBuffer[++withoutUnicodePtr] = currentCharacter;
486 } //-------------end unicode traitement--------------
488 if (currentCharacter == testedChar1)
490 else if (currentCharacter == testedChar2)
493 currentPosition = temp;
497 if (withoutUnicodePtr != 0)
498 withoutUnicodeBuffer[++withoutUnicodePtr] = currentCharacter;
501 } catch (IndexOutOfBoundsException e) {
502 currentPosition = temp;
506 public final boolean getNextCharAsDigit() {
508 //handle the case of unicode.
509 //when a unicode appears then we must use a buffer that holds char internal values
510 //At the end of this method currentCharacter holds the new visited char
511 //and currentPosition points right next after it
512 //Both previous lines are true if the currentCharacter is a digit
513 //On false, no side effect has occured.
515 //ALL getNextChar.... ARE OPTIMIZED COPIES
517 int temp = currentPosition;
519 if (((currentCharacter = source[currentPosition++]) == '\\')
520 && (source[currentPosition] == 'u')) {
521 //-------------unicode traitement ------------
525 while (source[currentPosition] == 'u') {
530 if (((c1 = Character.getNumericValue(source[currentPosition++])) > 15
532 || ((c2 = Character.getNumericValue(source[currentPosition++])) > 15
534 || ((c3 = Character.getNumericValue(source[currentPosition++])) > 15
536 || ((c4 = Character.getNumericValue(source[currentPosition++])) > 15
538 currentPosition = temp;
542 currentCharacter = (char) (((c1 * 16 + c2) * 16 + c3) * 16 + c4);
543 if (!Character.isDigit(currentCharacter)) {
544 currentPosition = temp;
548 //need the unicode buffer
549 if (withoutUnicodePtr == 0) {
550 //buffer all the entries that have been left aside....
551 withoutUnicodePtr = currentPosition - unicodeSize - startPosition;
555 withoutUnicodeBuffer,
559 //fill the buffer with the char
560 withoutUnicodeBuffer[++withoutUnicodePtr] = currentCharacter;
562 } //-------------end unicode traitement--------------
564 if (!Character.isDigit(currentCharacter)) {
565 currentPosition = temp;
568 if (withoutUnicodePtr != 0)
569 withoutUnicodeBuffer[++withoutUnicodePtr] = currentCharacter;
572 } catch (IndexOutOfBoundsException e) {
573 currentPosition = temp;
577 public final boolean getNextCharAsDigit(int radix) {
579 //handle the case of unicode.
580 //when a unicode appears then we must use a buffer that holds char internal values
581 //At the end of this method currentCharacter holds the new visited char
582 //and currentPosition points right next after it
583 //Both previous lines are true if the currentCharacter is a digit base on radix
584 //On false, no side effect has occured.
586 //ALL getNextChar.... ARE OPTIMIZED COPIES
588 int temp = currentPosition;
590 if (((currentCharacter = source[currentPosition++]) == '\\')
591 && (source[currentPosition] == 'u')) {
592 //-------------unicode traitement ------------
596 while (source[currentPosition] == 'u') {
601 if (((c1 = Character.getNumericValue(source[currentPosition++])) > 15
603 || ((c2 = Character.getNumericValue(source[currentPosition++])) > 15
605 || ((c3 = Character.getNumericValue(source[currentPosition++])) > 15
607 || ((c4 = Character.getNumericValue(source[currentPosition++])) > 15
609 currentPosition = temp;
613 currentCharacter = (char) (((c1 * 16 + c2) * 16 + c3) * 16 + c4);
614 if (Character.digit(currentCharacter, radix) == -1) {
615 currentPosition = temp;
619 //need the unicode buffer
620 if (withoutUnicodePtr == 0) {
621 //buffer all the entries that have been left aside....
622 withoutUnicodePtr = currentPosition - unicodeSize - startPosition;
626 withoutUnicodeBuffer,
630 //fill the buffer with the char
631 withoutUnicodeBuffer[++withoutUnicodePtr] = currentCharacter;
633 } //-------------end unicode traitement--------------
635 if (Character.digit(currentCharacter, radix) == -1) {
636 currentPosition = temp;
639 if (withoutUnicodePtr != 0)
640 withoutUnicodeBuffer[++withoutUnicodePtr] = currentCharacter;
643 } catch (IndexOutOfBoundsException e) {
644 currentPosition = temp;
648 public boolean getNextCharAsJavaIdentifierPart() {
650 //handle the case of unicode.
651 //when a unicode appears then we must use a buffer that holds char internal values
652 //At the end of this method currentCharacter holds the new visited char
653 //and currentPosition points right next after it
654 //Both previous lines are true if the currentCharacter is a JavaIdentifierPart
655 //On false, no side effect has occured.
657 //ALL getNextChar.... ARE OPTIMIZED COPIES
659 int temp = currentPosition;
661 if (((currentCharacter = source[currentPosition++]) == '\\')
662 && (source[currentPosition] == 'u')) {
663 //-------------unicode traitement ------------
667 while (source[currentPosition] == 'u') {
672 if (((c1 = Character.getNumericValue(source[currentPosition++])) > 15
674 || ((c2 = Character.getNumericValue(source[currentPosition++])) > 15
676 || ((c3 = Character.getNumericValue(source[currentPosition++])) > 15
678 || ((c4 = Character.getNumericValue(source[currentPosition++])) > 15
680 currentPosition = temp;
684 currentCharacter = (char) (((c1 * 16 + c2) * 16 + c3) * 16 + c4);
685 if (!isPHPIdentifierPart(currentCharacter)) {
686 currentPosition = temp;
690 //need the unicode buffer
691 if (withoutUnicodePtr == 0) {
692 //buffer all the entries that have been left aside....
693 withoutUnicodePtr = currentPosition - unicodeSize - startPosition;
697 withoutUnicodeBuffer,
701 //fill the buffer with the char
702 withoutUnicodeBuffer[++withoutUnicodePtr] = currentCharacter;
704 } //-------------end unicode traitement--------------
706 if (!isPHPIdentifierPart(currentCharacter)) {
707 currentPosition = temp;
711 if (withoutUnicodePtr != 0)
712 withoutUnicodeBuffer[++withoutUnicodePtr] = currentCharacter;
715 } catch (IndexOutOfBoundsException e) {
716 currentPosition = temp;
721 public int getNextToken() throws InvalidInputException {
724 startPosition = currentPosition;
725 currentCharacter = source[currentPosition++];
726 if (currentCharacter == '<') {
727 if (getNextChar('?')) {
728 currentCharacter = source[currentPosition++];
729 if ((currentCharacter == ' ')
730 || Character.isWhitespace(currentCharacter)) {
732 startPosition = currentPosition;
736 (currentCharacter == 'P') || (currentCharacter == 'p');
738 int test = getNextChar('H', 'h');
740 test = getNextChar('P', 'p');
743 startPosition = currentPosition;
752 if ((currentCharacter == '\r') || (currentCharacter == '\n')) {
753 if (recordLineSeparator) {
760 } //-----------------end switch while try--------------------
761 catch (IndexOutOfBoundsException e) {
768 jumpOverMethodBody();
770 return currentPosition > source.length ? TokenNameEOF : TokenNameRBRACE;
773 while (true) { //loop for jumping over comments
774 withoutUnicodePtr = 0;
775 //start with a new token (even comment written with unicode )
777 // ---------Consume white space and handles startPosition---------
778 int whiteStart = currentPosition;
779 boolean isWhiteSpace;
781 startPosition = currentPosition;
782 if (((currentCharacter = source[currentPosition++]) == '\\')
783 && (source[currentPosition] == 'u')) {
784 isWhiteSpace = jumpOverUnicodeWhiteSpace();
786 if ((currentCharacter == '\r') || (currentCharacter == '\n')) {
787 checkNonExternalizeString();
788 if (recordLineSeparator) {
795 (currentCharacter == ' ')
796 || Character.isWhitespace(currentCharacter);
798 } while (isWhiteSpace);
799 if (tokenizeWhiteSpace && (whiteStart != currentPosition - 1)) {
800 // reposition scanner in case we are interested by spaces as tokens
802 startPosition = whiteStart;
803 return TokenNameWHITESPACE;
805 //little trick to get out in the middle of a source compuation
806 if (currentPosition > eofPosition)
809 // ---------Identify the next token-------------
811 switch (currentCharacter) {
813 return TokenNameLPAREN;
815 return TokenNameRPAREN;
817 return TokenNameLBRACE;
819 return TokenNameRBRACE;
821 return TokenNameLBRACKET;
823 return TokenNameRBRACKET;
825 return TokenNameSEMICOLON;
827 return TokenNameCOMMA;
830 if (getNextCharAsDigit())
831 return scanNumber(true);
836 if ((test = getNextChar('+', '=')) == 0)
837 return TokenNamePLUS_PLUS;
839 return TokenNamePLUS_EQUAL;
840 return TokenNamePLUS;
845 if ((test = getNextChar('-', '=')) == 0)
846 return TokenNameMINUS_MINUS;
848 return TokenNameMINUS_EQUAL;
849 if (getNextChar('>'))
850 return TokenNameMINUS_GREATER;
852 return TokenNameMINUS;
855 if (getNextChar('='))
856 return TokenNameTWIDDLE_EQUAL;
857 return TokenNameTWIDDLE;
859 if (getNextChar('='))
860 return TokenNameNOT_EQUAL;
863 if (getNextChar('='))
864 return TokenNameMULTIPLY_EQUAL;
865 return TokenNameMULTIPLY;
867 if (getNextChar('='))
868 return TokenNameREMAINDER_EQUAL;
869 return TokenNameREMAINDER;
873 if ((test = getNextChar('=', '<')) == 0)
874 return TokenNameLESS_EQUAL;
876 if (getNextChar('='))
877 return TokenNameLEFT_SHIFT_EQUAL;
878 if (getNextChar('<')) {
879 int heredocStart = currentPosition;
880 int heredocLength = 0;
881 currentCharacter = source[currentPosition++];
882 if (isPHPIdentifierStart(currentCharacter)) {
883 currentCharacter = source[currentPosition++];
885 return TokenNameERROR;
887 while (isPHPIdentifierPart(currentCharacter)) {
888 currentCharacter = source[currentPosition++];
891 heredocLength = currentPosition - heredocStart - 1;
893 // heredoc end-tag determination
894 boolean endTag = true;
897 ch = source[currentPosition++];
898 if (ch == '\r' || ch == '\n') {
899 if (recordLineSeparator) {
904 for (int i = 0; i < heredocLength; i++) {
905 if (source[currentPosition + i]
906 != source[heredocStart + i]) {
912 currentPosition += heredocLength - 1;
913 currentCharacter = source[currentPosition++];
914 break; // do...while loop
922 return TokenNameHEREDOC;
924 return TokenNameLEFT_SHIFT;
926 return TokenNameLESS;
931 if ((test = getNextChar('=', '>')) == 0)
932 return TokenNameGREATER_EQUAL;
934 if ((test = getNextChar('=', '>')) == 0)
935 return TokenNameRIGHT_SHIFT_EQUAL;
936 return TokenNameRIGHT_SHIFT;
938 return TokenNameGREATER;
941 if (getNextChar('='))
942 return TokenNameEQUAL_EQUAL;
943 if (getNextChar('>'))
944 return TokenNameEQUAL_GREATER;
945 return TokenNameEQUAL;
949 if ((test = getNextChar('&', '=')) == 0)
950 return TokenNameAND_AND;
952 return TokenNameAND_EQUAL;
958 if ((test = getNextChar('|', '=')) == 0)
959 return TokenNameOR_OR;
961 return TokenNameOR_EQUAL;
965 if (getNextChar('='))
966 return TokenNameXOR_EQUAL;
969 if (getNextChar('>')) {
971 return TokenNameStopPHP;
973 return TokenNameQUESTION;
975 if (getNextChar(':'))
976 return TokenNameCOLON_COLON;
977 return TokenNameCOLON;
983 // if ((test = getNextChar('\n', '\r')) == 0) {
984 // throw new InvalidInputException(INVALID_CHARACTER_CONSTANT);
987 // // relocate if finding another quote fairly close: thus unicode '/u000D' will be fully consumed
988 // for (int lookAhead = 0;
991 // if (currentPosition + lookAhead
994 // if (source[currentPosition + lookAhead]
997 // if (source[currentPosition + lookAhead]
999 // currentPosition += lookAhead + 1;
1003 // throw new InvalidInputException(INVALID_CHARACTER_CONSTANT);
1006 // if (getNextChar('\'')) {
1007 // // relocate if finding another quote fairly close: thus unicode '/u000D' will be fully consumed
1008 // for (int lookAhead = 0;
1011 // if (currentPosition + lookAhead
1012 // == source.length)
1014 // if (source[currentPosition + lookAhead]
1017 // if (source[currentPosition + lookAhead]
1019 // currentPosition += lookAhead + 1;
1023 // throw new InvalidInputException(INVALID_CHARACTER_CONSTANT);
1025 // if (getNextChar('\\'))
1026 // scanEscapeCharacter();
1027 // else { // consume next character
1028 // unicodeAsBackSlash = false;
1029 // if (((currentCharacter = source[currentPosition++])
1031 // && (source[currentPosition] == 'u')) {
1032 // getNextUnicodeChar();
1034 // if (withoutUnicodePtr != 0) {
1035 // withoutUnicodeBuffer[++withoutUnicodePtr] =
1036 // currentCharacter;
1040 // // if (getNextChar('\''))
1041 // // return TokenNameCharacterLiteral;
1042 // // relocate if finding another quote fairly close: thus unicode '/u000D' will be fully consumed
1043 // for (int lookAhead = 0; lookAhead < 20; lookAhead++) {
1044 // if (currentPosition + lookAhead == source.length)
1046 // if (source[currentPosition + lookAhead] == '\n')
1048 // if (source[currentPosition + lookAhead] == '\'') {
1049 // currentPosition += lookAhead + 1;
1053 // throw new InvalidInputException(INVALID_CHARACTER_CONSTANT);
1056 // consume next character
1057 unicodeAsBackSlash = false;
1058 if (((currentCharacter = source[currentPosition++]) == '\\')
1059 && (source[currentPosition] == 'u')) {
1060 getNextUnicodeChar();
1062 if (withoutUnicodePtr != 0) {
1063 withoutUnicodeBuffer[++withoutUnicodePtr] =
1068 while (currentCharacter != '\'') {
1070 /**** in PHP \r and \n are valid in string literals ****/
1071 // if ((currentCharacter == '\n')
1072 // || (currentCharacter == '\r')) {
1073 // // relocate if finding another quote fairly close: thus unicode '/u000D' will be fully consumed
1074 // for (int lookAhead = 0; lookAhead < 50; lookAhead++) {
1075 // if (currentPosition + lookAhead == source.length)
1077 // if (source[currentPosition + lookAhead] == '\n')
1079 // if (source[currentPosition + lookAhead] == '\"') {
1080 // currentPosition += lookAhead + 1;
1084 // throw new InvalidInputException(INVALID_CHAR_IN_STRING);
1086 if (currentCharacter == '\\') {
1087 int escapeSize = currentPosition;
1088 boolean backSlashAsUnicodeInString = unicodeAsBackSlash;
1089 //scanEscapeCharacter make a side effect on this value and we need the previous value few lines down this one
1090 scanSingleQuotedEscapeCharacter();
1091 escapeSize = currentPosition - escapeSize;
1092 if (withoutUnicodePtr == 0) {
1093 //buffer all the entries that have been left aside....
1095 currentPosition - escapeSize - 1 - startPosition;
1099 withoutUnicodeBuffer,
1102 withoutUnicodeBuffer[++withoutUnicodePtr] =
1104 } else { //overwrite the / in the buffer
1105 withoutUnicodeBuffer[withoutUnicodePtr] =
1107 if (backSlashAsUnicodeInString) { //there are TWO \ in the stream where only one is correct
1108 withoutUnicodePtr--;
1112 // consume next character
1113 unicodeAsBackSlash = false;
1114 if (((currentCharacter = source[currentPosition++]) == '\\')
1115 && (source[currentPosition] == 'u')) {
1116 getNextUnicodeChar();
1118 if (withoutUnicodePtr != 0) {
1119 withoutUnicodeBuffer[++withoutUnicodePtr] =
1125 } catch (IndexOutOfBoundsException e) {
1126 throw new InvalidInputException(UNTERMINATED_STRING);
1127 } catch (InvalidInputException e) {
1128 if (e.getMessage().equals(INVALID_ESCAPE)) {
1129 // relocate if finding another quote fairly close: thus unicode '/u000D' will be fully consumed
1130 for (int lookAhead = 0; lookAhead < 50; lookAhead++) {
1131 if (currentPosition + lookAhead == source.length)
1133 if (source[currentPosition + lookAhead] == '\n')
1135 if (source[currentPosition + lookAhead] == '\'') {
1136 currentPosition += lookAhead + 1;
1144 if (checkNonExternalizedStringLiterals) { // check for presence of NLS tags //$NON-NLS-?$ where ? is an int.
1145 if (currentLine == null) {
1146 currentLine = new NLSLine();
1147 lines.add(currentLine);
1151 getCurrentTokenSourceString(),
1153 currentPosition - 1));
1155 return TokenNameStringConstant;
1158 // consume next character
1159 unicodeAsBackSlash = false;
1160 if (((currentCharacter = source[currentPosition++]) == '\\')
1161 && (source[currentPosition] == 'u')) {
1162 getNextUnicodeChar();
1164 if (withoutUnicodePtr != 0) {
1165 withoutUnicodeBuffer[++withoutUnicodePtr] =
1170 while (currentCharacter != '"') {
1172 /**** in PHP \r and \n are valid in string literals ****/
1173 // if ((currentCharacter == '\n')
1174 // || (currentCharacter == '\r')) {
1175 // // relocate if finding another quote fairly close: thus unicode '/u000D' will be fully consumed
1176 // for (int lookAhead = 0; lookAhead < 50; lookAhead++) {
1177 // if (currentPosition + lookAhead == source.length)
1179 // if (source[currentPosition + lookAhead] == '\n')
1181 // if (source[currentPosition + lookAhead] == '\"') {
1182 // currentPosition += lookAhead + 1;
1186 // throw new InvalidInputException(INVALID_CHAR_IN_STRING);
1188 if (currentCharacter == '\\') {
1189 int escapeSize = currentPosition;
1190 boolean backSlashAsUnicodeInString = unicodeAsBackSlash;
1191 //scanEscapeCharacter make a side effect on this value and we need the previous value few lines down this one
1192 scanDoubleQuotedEscapeCharacter();
1193 escapeSize = currentPosition - escapeSize;
1194 if (withoutUnicodePtr == 0) {
1195 //buffer all the entries that have been left aside....
1197 currentPosition - escapeSize - 1 - startPosition;
1201 withoutUnicodeBuffer,
1204 withoutUnicodeBuffer[++withoutUnicodePtr] =
1206 } else { //overwrite the / in the buffer
1207 withoutUnicodeBuffer[withoutUnicodePtr] =
1209 if (backSlashAsUnicodeInString) { //there are TWO \ in the stream where only one is correct
1210 withoutUnicodePtr--;
1214 // consume next character
1215 unicodeAsBackSlash = false;
1216 if (((currentCharacter = source[currentPosition++]) == '\\')
1217 && (source[currentPosition] == 'u')) {
1218 getNextUnicodeChar();
1220 if (withoutUnicodePtr != 0) {
1221 withoutUnicodeBuffer[++withoutUnicodePtr] =
1227 } catch (IndexOutOfBoundsException e) {
1228 throw new InvalidInputException(UNTERMINATED_STRING);
1229 } catch (InvalidInputException e) {
1230 if (e.getMessage().equals(INVALID_ESCAPE)) {
1231 // relocate if finding another quote fairly close: thus unicode '/u000D' will be fully consumed
1232 for (int lookAhead = 0; lookAhead < 50; lookAhead++) {
1233 if (currentPosition + lookAhead == source.length)
1235 if (source[currentPosition + lookAhead] == '\n')
1237 if (source[currentPosition + lookAhead] == '\"') {
1238 currentPosition += lookAhead + 1;
1246 if (checkNonExternalizedStringLiterals) { // check for presence of NLS tags //$NON-NLS-?$ where ? is an int.
1247 if (currentLine == null) {
1248 currentLine = new NLSLine();
1249 lines.add(currentLine);
1253 getCurrentTokenSourceString(),
1255 currentPosition - 1));
1257 return TokenNameStringLiteral;
1260 // consume next character
1261 unicodeAsBackSlash = false;
1262 if (((currentCharacter = source[currentPosition++]) == '\\')
1263 && (source[currentPosition] == 'u')) {
1264 getNextUnicodeChar();
1266 if (withoutUnicodePtr != 0) {
1267 withoutUnicodeBuffer[++withoutUnicodePtr] =
1272 while (currentCharacter != '`') {
1274 /**** in PHP \r and \n are valid in string literals ****/
1275 // if ((currentCharacter == '\n')
1276 // || (currentCharacter == '\r')) {
1277 // // relocate if finding another quote fairly close: thus unicode '/u000D' will be fully consumed
1278 // for (int lookAhead = 0; lookAhead < 50; lookAhead++) {
1279 // if (currentPosition + lookAhead == source.length)
1281 // if (source[currentPosition + lookAhead] == '\n')
1283 // if (source[currentPosition + lookAhead] == '\"') {
1284 // currentPosition += lookAhead + 1;
1288 // throw new InvalidInputException(INVALID_CHAR_IN_STRING);
1290 if (currentCharacter == '\\') {
1291 int escapeSize = currentPosition;
1292 boolean backSlashAsUnicodeInString = unicodeAsBackSlash;
1293 //scanEscapeCharacter make a side effect on this value and we need the previous value few lines down this one
1294 scanDoubleQuotedEscapeCharacter();
1295 escapeSize = currentPosition - escapeSize;
1296 if (withoutUnicodePtr == 0) {
1297 //buffer all the entries that have been left aside....
1299 currentPosition - escapeSize - 1 - startPosition;
1303 withoutUnicodeBuffer,
1306 withoutUnicodeBuffer[++withoutUnicodePtr] =
1308 } else { //overwrite the / in the buffer
1309 withoutUnicodeBuffer[withoutUnicodePtr] =
1311 if (backSlashAsUnicodeInString) { //there are TWO \ in the stream where only one is correct
1312 withoutUnicodePtr--;
1316 // consume next character
1317 unicodeAsBackSlash = false;
1318 if (((currentCharacter = source[currentPosition++]) == '\\')
1319 && (source[currentPosition] == 'u')) {
1320 getNextUnicodeChar();
1322 if (withoutUnicodePtr != 0) {
1323 withoutUnicodeBuffer[++withoutUnicodePtr] =
1329 } catch (IndexOutOfBoundsException e) {
1330 throw new InvalidInputException(UNTERMINATED_STRING);
1331 } catch (InvalidInputException e) {
1332 if (e.getMessage().equals(INVALID_ESCAPE)) {
1333 // relocate if finding another quote fairly close: thus unicode '/u000D' will be fully consumed
1334 for (int lookAhead = 0; lookAhead < 50; lookAhead++) {
1335 if (currentPosition + lookAhead == source.length)
1337 if (source[currentPosition + lookAhead] == '\n')
1339 if (source[currentPosition + lookAhead] == '`') {
1340 currentPosition += lookAhead + 1;
1348 if (checkNonExternalizedStringLiterals) { // check for presence of NLS tags //$NON-NLS-?$ where ? is an int.
1349 if (currentLine == null) {
1350 currentLine = new NLSLine();
1351 lines.add(currentLine);
1355 getCurrentTokenSourceString(),
1357 currentPosition - 1));
1359 return TokenNameStringInterpolated;
1364 if ((currentCharacter == '#')
1365 || (test = getNextChar('/', '*')) == 0) {
1367 int endPositionForLineComment = 0;
1368 try { //get the next char
1369 if (((currentCharacter = source[currentPosition++])
1371 && (source[currentPosition] == 'u')) {
1372 //-------------unicode traitement ------------
1373 int c1 = 0, c2 = 0, c3 = 0, c4 = 0;
1375 while (source[currentPosition] == 'u') {
1379 Character.getNumericValue(source[currentPosition++]))
1383 Character.getNumericValue(source[currentPosition++]))
1387 Character.getNumericValue(source[currentPosition++]))
1391 Character.getNumericValue(source[currentPosition++]))
1394 throw new InvalidInputException(INVALID_UNICODE_ESCAPE);
1397 (char) (((c1 * 16 + c2) * 16 + c3) * 16 + c4);
1401 //handle the \\u case manually into comment
1402 if (currentCharacter == '\\') {
1403 if (source[currentPosition] == '\\')
1405 } //jump over the \\
1406 boolean isUnicode = false;
1407 while (currentCharacter != '\r'
1408 && currentCharacter != '\n') {
1409 if (currentCharacter == '?') {
1410 if (getNextChar('>')) {
1411 startPosition = currentPosition - 2;
1413 return TokenNameStopPHP;
1419 if (((currentCharacter = source[currentPosition++])
1421 && (source[currentPosition] == 'u')) {
1423 //-------------unicode traitement ------------
1424 int c1 = 0, c2 = 0, c3 = 0, c4 = 0;
1426 while (source[currentPosition] == 'u') {
1430 Character.getNumericValue(source[currentPosition++]))
1434 Character.getNumericValue(
1435 source[currentPosition++]))
1439 Character.getNumericValue(
1440 source[currentPosition++]))
1444 Character.getNumericValue(
1445 source[currentPosition++]))
1448 throw new InvalidInputException(INVALID_UNICODE_ESCAPE);
1451 (char) (((c1 * 16 + c2) * 16 + c3) * 16 + c4);
1454 //handle the \\u case manually into comment
1455 if (currentCharacter == '\\') {
1456 if (source[currentPosition] == '\\')
1458 } //jump over the \\
1461 endPositionForLineComment = currentPosition - 6;
1463 endPositionForLineComment = currentPosition - 1;
1465 recordComment(false);
1466 if ((currentCharacter == '\r')
1467 || (currentCharacter == '\n')) {
1468 checkNonExternalizeString();
1469 if (recordLineSeparator) {
1471 pushUnicodeLineSeparator();
1473 pushLineSeparator();
1479 if (tokenizeComments) {
1481 currentPosition = endPositionForLineComment;
1482 // reset one character behind
1484 return TokenNameCOMMENT_LINE;
1486 } catch (IndexOutOfBoundsException e) { //an eof will them be generated
1487 if (tokenizeComments) {
1489 // reset one character behind
1490 return TokenNameCOMMENT_LINE;
1496 //traditional and annotation comment
1497 boolean isJavadoc = false, star = false;
1498 // consume next character
1499 unicodeAsBackSlash = false;
1500 if (((currentCharacter = source[currentPosition++]) == '\\')
1501 && (source[currentPosition] == 'u')) {
1502 getNextUnicodeChar();
1504 if (withoutUnicodePtr != 0) {
1505 withoutUnicodeBuffer[++withoutUnicodePtr] =
1510 if (currentCharacter == '*') {
1514 if ((currentCharacter == '\r')
1515 || (currentCharacter == '\n')) {
1516 checkNonExternalizeString();
1517 if (recordLineSeparator) {
1518 pushLineSeparator();
1523 try { //get the next char
1524 if (((currentCharacter = source[currentPosition++])
1526 && (source[currentPosition] == 'u')) {
1527 //-------------unicode traitement ------------
1528 getNextUnicodeChar();
1530 //handle the \\u case manually into comment
1531 if (currentCharacter == '\\') {
1532 if (source[currentPosition] == '\\')
1536 // empty comment is not a javadoc /**/
1537 if (currentCharacter == '/') {
1540 //loop until end of comment */
1541 while ((currentCharacter != '/') || (!star)) {
1542 if ((currentCharacter == '\r')
1543 || (currentCharacter == '\n')) {
1544 checkNonExternalizeString();
1545 if (recordLineSeparator) {
1546 pushLineSeparator();
1551 star = currentCharacter == '*';
1553 if (((currentCharacter = source[currentPosition++])
1555 && (source[currentPosition] == 'u')) {
1556 //-------------unicode traitement ------------
1557 getNextUnicodeChar();
1559 //handle the \\u case manually into comment
1560 if (currentCharacter == '\\') {
1561 if (source[currentPosition] == '\\')
1563 } //jump over the \\
1565 recordComment(isJavadoc);
1566 if (tokenizeComments) {
1568 return TokenNameCOMMENT_PHPDOC;
1569 return TokenNameCOMMENT_BLOCK;
1571 } catch (IndexOutOfBoundsException e) {
1572 throw new InvalidInputException(UNTERMINATED_COMMENT);
1576 if (getNextChar('='))
1577 return TokenNameDIVIDE_EQUAL;
1578 return TokenNameDIVIDE;
1582 return TokenNameEOF;
1583 //the atEnd may not be <currentPosition == source.length> if source is only some part of a real (external) stream
1584 throw new InvalidInputException("Ctrl-Z"); //$NON-NLS-1$
1587 if (currentCharacter == '$') {
1588 while ((currentCharacter = source[currentPosition++]) == '$') {
1590 if (currentCharacter == '{')
1591 return TokenNameDOLLAR_LBRACE;
1592 if (isPHPIdentifierStart(currentCharacter))
1593 return scanIdentifierOrKeyword(true);
1594 return TokenNameERROR;
1596 if (isPHPIdentifierStart(currentCharacter))
1597 return scanIdentifierOrKeyword(false);
1598 if (Character.isDigit(currentCharacter))
1599 return scanNumber(false);
1600 return TokenNameERROR;
1603 } //-----------------end switch while try--------------------
1604 catch (IndexOutOfBoundsException e) {
1607 return TokenNameEOF;
1610 public final void getNextUnicodeChar()
1611 throws IndexOutOfBoundsException, InvalidInputException {
1613 //handle the case of unicode.
1614 //when a unicode appears then we must use a buffer that holds char internal values
1615 //At the end of this method currentCharacter holds the new visited char
1616 //and currentPosition points right next after it
1618 //ALL getNextChar.... ARE OPTIMIZED COPIES
1620 int c1 = 0, c2 = 0, c3 = 0, c4 = 0, unicodeSize = 6;
1622 while (source[currentPosition] == 'u') {
1627 if ((c1 = Character.getNumericValue(source[currentPosition++])) > 15
1629 || (c2 = Character.getNumericValue(source[currentPosition++])) > 15
1631 || (c3 = Character.getNumericValue(source[currentPosition++])) > 15
1633 || (c4 = Character.getNumericValue(source[currentPosition++])) > 15
1635 throw new InvalidInputException(INVALID_UNICODE_ESCAPE);
1637 currentCharacter = (char) (((c1 * 16 + c2) * 16 + c3) * 16 + c4);
1638 //need the unicode buffer
1639 if (withoutUnicodePtr == 0) {
1640 //buffer all the entries that have been left aside....
1641 withoutUnicodePtr = currentPosition - unicodeSize - startPosition;
1645 withoutUnicodeBuffer,
1649 //fill the buffer with the char
1650 withoutUnicodeBuffer[++withoutUnicodePtr] = currentCharacter;
1652 unicodeAsBackSlash = currentCharacter == '\\';
1654 /* Tokenize a method body, assuming that curly brackets are properly balanced.
1656 public final void jumpOverMethodBody() {
1658 this.wasAcr = false;
1661 while (true) { //loop for jumping over comments
1662 // ---------Consume white space and handles startPosition---------
1663 boolean isWhiteSpace;
1665 startPosition = currentPosition;
1666 if (((currentCharacter = source[currentPosition++]) == '\\')
1667 && (source[currentPosition] == 'u')) {
1668 isWhiteSpace = jumpOverUnicodeWhiteSpace();
1670 if (recordLineSeparator
1671 && ((currentCharacter == '\r') || (currentCharacter == '\n')))
1672 pushLineSeparator();
1673 isWhiteSpace = Character.isWhitespace(currentCharacter);
1675 } while (isWhiteSpace);
1677 // -------consume token until } is found---------
1678 switch (currentCharacter) {
1690 test = getNextChar('\\');
1693 scanDoubleQuotedEscapeCharacter();
1694 } catch (InvalidInputException ex) {
1697 try { // consume next character
1698 unicodeAsBackSlash = false;
1699 if (((currentCharacter = source[currentPosition++]) == '\\')
1700 && (source[currentPosition] == 'u')) {
1701 getNextUnicodeChar();
1703 if (withoutUnicodePtr != 0) {
1704 withoutUnicodeBuffer[++withoutUnicodePtr] =
1708 } catch (InvalidInputException ex) {
1716 try { // consume next character
1717 unicodeAsBackSlash = false;
1718 if (((currentCharacter = source[currentPosition++]) == '\\')
1719 && (source[currentPosition] == 'u')) {
1720 getNextUnicodeChar();
1722 if (withoutUnicodePtr != 0) {
1723 withoutUnicodeBuffer[++withoutUnicodePtr] =
1727 } catch (InvalidInputException ex) {
1729 while (currentCharacter != '"') {
1730 if (currentCharacter == '\r') {
1731 if (source[currentPosition] == '\n')
1734 // the string cannot go further that the line
1736 if (currentCharacter == '\n') {
1738 // the string cannot go further that the line
1740 if (currentCharacter == '\\') {
1742 scanDoubleQuotedEscapeCharacter();
1743 } catch (InvalidInputException ex) {
1746 try { // consume next character
1747 unicodeAsBackSlash = false;
1748 if (((currentCharacter = source[currentPosition++]) == '\\')
1749 && (source[currentPosition] == 'u')) {
1750 getNextUnicodeChar();
1752 if (withoutUnicodePtr != 0) {
1753 withoutUnicodeBuffer[++withoutUnicodePtr] =
1757 } catch (InvalidInputException ex) {
1760 } catch (IndexOutOfBoundsException e) {
1767 if ((test = getNextChar('/', '*')) == 0) {
1771 if (((currentCharacter = source[currentPosition++]) == '\\')
1772 && (source[currentPosition] == 'u')) {
1773 //-------------unicode traitement ------------
1774 int c1 = 0, c2 = 0, c3 = 0, c4 = 0;
1776 while (source[currentPosition] == 'u') {
1780 Character.getNumericValue(source[currentPosition++]))
1784 Character.getNumericValue(source[currentPosition++]))
1788 Character.getNumericValue(source[currentPosition++]))
1792 Character.getNumericValue(source[currentPosition++]))
1795 //error don't care of the value
1796 currentCharacter = 'A';
1797 } //something different from \n and \r
1800 (char) (((c1 * 16 + c2) * 16 + c3) * 16 + c4);
1804 while (currentCharacter != '\r'
1805 && currentCharacter != '\n') {
1807 if (((currentCharacter = source[currentPosition++])
1809 && (source[currentPosition] == 'u')) {
1810 //-------------unicode traitement ------------
1811 int c1 = 0, c2 = 0, c3 = 0, c4 = 0;
1813 while (source[currentPosition] == 'u') {
1817 Character.getNumericValue(source[currentPosition++]))
1821 Character.getNumericValue(source[currentPosition++]))
1825 Character.getNumericValue(source[currentPosition++]))
1829 Character.getNumericValue(source[currentPosition++]))
1832 //error don't care of the value
1833 currentCharacter = 'A';
1834 } //something different from \n and \r
1837 (char) (((c1 * 16 + c2) * 16 + c3) * 16 + c4);
1841 if (recordLineSeparator
1842 && ((currentCharacter == '\r') || (currentCharacter == '\n')))
1843 pushLineSeparator();
1844 } catch (IndexOutOfBoundsException e) {
1845 } //an eof will them be generated
1849 //traditional and annotation comment
1850 boolean star = false;
1851 try { // consume next character
1852 unicodeAsBackSlash = false;
1853 if (((currentCharacter = source[currentPosition++]) == '\\')
1854 && (source[currentPosition] == 'u')) {
1855 getNextUnicodeChar();
1857 if (withoutUnicodePtr != 0) {
1858 withoutUnicodeBuffer[++withoutUnicodePtr] =
1862 } catch (InvalidInputException ex) {
1864 if (currentCharacter == '*') {
1867 if (recordLineSeparator
1868 && ((currentCharacter == '\r') || (currentCharacter == '\n')))
1869 pushLineSeparator();
1870 try { //get the next char
1871 if (((currentCharacter = source[currentPosition++]) == '\\')
1872 && (source[currentPosition] == 'u')) {
1873 //-------------unicode traitement ------------
1874 int c1 = 0, c2 = 0, c3 = 0, c4 = 0;
1876 while (source[currentPosition] == 'u') {
1880 Character.getNumericValue(source[currentPosition++]))
1884 Character.getNumericValue(source[currentPosition++]))
1888 Character.getNumericValue(source[currentPosition++]))
1892 Character.getNumericValue(source[currentPosition++]))
1895 //error don't care of the value
1896 currentCharacter = 'A';
1897 } //something different from * and /
1900 (char) (((c1 * 16 + c2) * 16 + c3) * 16 + c4);
1903 //loop until end of comment */
1904 while ((currentCharacter != '/') || (!star)) {
1905 if (recordLineSeparator
1906 && ((currentCharacter == '\r')
1907 || (currentCharacter == '\n')))
1908 pushLineSeparator();
1909 star = currentCharacter == '*';
1911 if (((currentCharacter = source[currentPosition++])
1913 && (source[currentPosition] == 'u')) {
1914 //-------------unicode traitement ------------
1915 int c1 = 0, c2 = 0, c3 = 0, c4 = 0;
1917 while (source[currentPosition] == 'u') {
1921 Character.getNumericValue(source[currentPosition++]))
1925 Character.getNumericValue(source[currentPosition++]))
1929 Character.getNumericValue(source[currentPosition++]))
1933 Character.getNumericValue(source[currentPosition++]))
1936 //error don't care of the value
1937 currentCharacter = 'A';
1938 } //something different from * and /
1941 (char) (((c1 * 16 + c2) * 16 + c3) * 16 + c4);
1945 } catch (IndexOutOfBoundsException e) {
1954 if (isPHPIdentifierStart(currentCharacter)
1955 || currentCharacter == '$') {
1957 scanIdentifierOrKeyword((currentCharacter == '$'));
1958 } catch (InvalidInputException ex) {
1962 if (Character.isDigit(currentCharacter)) {
1965 } catch (InvalidInputException ex) {
1971 //-----------------end switch while try--------------------
1972 } catch (IndexOutOfBoundsException e) {
1973 } catch (InvalidInputException e) {
1977 public final boolean jumpOverUnicodeWhiteSpace()
1978 throws InvalidInputException {
1980 //handle the case of unicode. Jump over the next whiteSpace
1981 //making startPosition pointing on the next available char
1982 //On false, the currentCharacter is filled up with a potential
1986 this.wasAcr = false;
1988 int unicodeSize = 6;
1990 while (source[currentPosition] == 'u') {
1995 if (((c1 = Character.getNumericValue(source[currentPosition++])) > 15
1997 || ((c2 = Character.getNumericValue(source[currentPosition++])) > 15
1999 || ((c3 = Character.getNumericValue(source[currentPosition++])) > 15
2001 || ((c4 = Character.getNumericValue(source[currentPosition++])) > 15
2003 throw new InvalidInputException(INVALID_UNICODE_ESCAPE);
2006 currentCharacter = (char) (((c1 * 16 + c2) * 16 + c3) * 16 + c4);
2007 if (recordLineSeparator
2008 && ((currentCharacter == '\r') || (currentCharacter == '\n')))
2009 pushLineSeparator();
2010 if (Character.isWhitespace(currentCharacter))
2013 //buffer the new char which is not a white space
2014 withoutUnicodeBuffer[++withoutUnicodePtr] = currentCharacter;
2015 //withoutUnicodePtr == 1 is true here
2017 } catch (IndexOutOfBoundsException e) {
2018 throw new InvalidInputException(INVALID_UNICODE_ESCAPE);
2021 public final int[] getLineEnds() {
2022 //return a bounded copy of this.lineEnds
2025 System.arraycopy(lineEnds, 0, copy = new int[linePtr + 1], 0, linePtr + 1);
2029 public char[] getSource() {
2032 final char[] optimizedCurrentTokenSource1() {
2033 //return always the same char[] build only once
2035 //optimization at no speed cost of 99.5 % of the singleCharIdentifier
2036 char charOne = source[startPosition];
2091 return new char[] { charOne };
2095 final char[] optimizedCurrentTokenSource2() {
2096 //try to return the same char[] build only once
2100 (((c0 = source[startPosition]) << 6) + (c1 = source[startPosition + 1]))
2102 char[][] table = charArray_length[0][hash];
2104 while (++i < InternalTableSize) {
2105 char[] charArray = table[i];
2106 if ((c0 == charArray[0]) && (c1 == charArray[1]))
2109 //---------other side---------
2111 int max = newEntry2;
2112 while (++i <= max) {
2113 char[] charArray = table[i];
2114 if ((c0 == charArray[0]) && (c1 == charArray[1]))
2117 //--------add the entry-------
2118 if (++max >= InternalTableSize)
2121 table[max] = (r = new char[] { c0, c1 });
2126 final char[] optimizedCurrentTokenSource3() {
2127 //try to return the same char[] build only once
2131 (((c0 = source[startPosition]) << 12)
2132 + ((c1 = source[startPosition + 1]) << 6)
2133 + (c2 = source[startPosition + 2]))
2135 char[][] table = charArray_length[1][hash];
2137 while (++i < InternalTableSize) {
2138 char[] charArray = table[i];
2139 if ((c0 == charArray[0]) && (c1 == charArray[1]) && (c2 == charArray[2]))
2142 //---------other side---------
2144 int max = newEntry3;
2145 while (++i <= max) {
2146 char[] charArray = table[i];
2147 if ((c0 == charArray[0]) && (c1 == charArray[1]) && (c2 == charArray[2]))
2150 //--------add the entry-------
2151 if (++max >= InternalTableSize)
2154 table[max] = (r = new char[] { c0, c1, c2 });
2159 final char[] optimizedCurrentTokenSource4() {
2160 //try to return the same char[] build only once
2162 char c0, c1, c2, c3;
2164 ((((long) (c0 = source[startPosition])) << 18)
2165 + ((c1 = source[startPosition + 1]) << 12)
2166 + ((c2 = source[startPosition + 2]) << 6)
2167 + (c3 = source[startPosition + 3]))
2169 char[][] table = charArray_length[2][(int) hash];
2171 while (++i < InternalTableSize) {
2172 char[] charArray = table[i];
2173 if ((c0 == charArray[0])
2174 && (c1 == charArray[1])
2175 && (c2 == charArray[2])
2176 && (c3 == charArray[3]))
2179 //---------other side---------
2181 int max = newEntry4;
2182 while (++i <= max) {
2183 char[] charArray = table[i];
2184 if ((c0 == charArray[0])
2185 && (c1 == charArray[1])
2186 && (c2 == charArray[2])
2187 && (c3 == charArray[3]))
2190 //--------add the entry-------
2191 if (++max >= InternalTableSize)
2194 table[max] = (r = new char[] { c0, c1, c2, c3 });
2200 final char[] optimizedCurrentTokenSource5() {
2201 //try to return the same char[] build only once
2203 char c0, c1, c2, c3, c4;
2205 ((((long) (c0 = source[startPosition])) << 24)
2206 + (((long) (c1 = source[startPosition + 1])) << 18)
2207 + ((c2 = source[startPosition + 2]) << 12)
2208 + ((c3 = source[startPosition + 3]) << 6)
2209 + (c4 = source[startPosition + 4]))
2211 char[][] table = charArray_length[3][(int) hash];
2213 while (++i < InternalTableSize) {
2214 char[] charArray = table[i];
2215 if ((c0 == charArray[0])
2216 && (c1 == charArray[1])
2217 && (c2 == charArray[2])
2218 && (c3 == charArray[3])
2219 && (c4 == charArray[4]))
2222 //---------other side---------
2224 int max = newEntry5;
2225 while (++i <= max) {
2226 char[] charArray = table[i];
2227 if ((c0 == charArray[0])
2228 && (c1 == charArray[1])
2229 && (c2 == charArray[2])
2230 && (c3 == charArray[3])
2231 && (c4 == charArray[4]))
2234 //--------add the entry-------
2235 if (++max >= InternalTableSize)
2238 table[max] = (r = new char[] { c0, c1, c2, c3, c4 });
2244 final char[] optimizedCurrentTokenSource6() {
2245 //try to return the same char[] build only once
2247 char c0, c1, c2, c3, c4, c5;
2249 ((((long) (c0 = source[startPosition])) << 32)
2250 + (((long) (c1 = source[startPosition + 1])) << 24)
2251 + (((long) (c2 = source[startPosition + 2])) << 18)
2252 + ((c3 = source[startPosition + 3]) << 12)
2253 + ((c4 = source[startPosition + 4]) << 6)
2254 + (c5 = source[startPosition + 5]))
2256 char[][] table = charArray_length[4][(int) hash];
2258 while (++i < InternalTableSize) {
2259 char[] charArray = table[i];
2260 if ((c0 == charArray[0])
2261 && (c1 == charArray[1])
2262 && (c2 == charArray[2])
2263 && (c3 == charArray[3])
2264 && (c4 == charArray[4])
2265 && (c5 == charArray[5]))
2268 //---------other side---------
2270 int max = newEntry6;
2271 while (++i <= max) {
2272 char[] charArray = table[i];
2273 if ((c0 == charArray[0])
2274 && (c1 == charArray[1])
2275 && (c2 == charArray[2])
2276 && (c3 == charArray[3])
2277 && (c4 == charArray[4])
2278 && (c5 == charArray[5]))
2281 //--------add the entry-------
2282 if (++max >= InternalTableSize)
2285 table[max] = (r = new char[] { c0, c1, c2, c3, c4, c5 });
2290 public final void pushLineSeparator() throws InvalidInputException {
2291 //see comment on isLineDelimiter(char) for the use of '\n' and '\r'
2292 final int INCREMENT = 250;
2294 if (this.checkNonExternalizedStringLiterals) {
2295 // reinitialize the current line for non externalize strings purpose
2298 //currentCharacter is at position currentPosition-1
2301 if (currentCharacter == '\r') {
2302 int separatorPos = currentPosition - 1;
2303 if ((linePtr > 0) && (lineEnds[linePtr] >= separatorPos))
2305 //System.out.println("CR-" + separatorPos);
2307 lineEnds[++linePtr] = separatorPos;
2308 } catch (IndexOutOfBoundsException e) {
2309 //linePtr value is correct
2310 int oldLength = lineEnds.length;
2311 int[] old = lineEnds;
2312 lineEnds = new int[oldLength + INCREMENT];
2313 System.arraycopy(old, 0, lineEnds, 0, oldLength);
2314 lineEnds[linePtr] = separatorPos;
2316 // look-ahead for merged cr+lf
2318 if (source[currentPosition] == '\n') {
2319 //System.out.println("look-ahead LF-" + currentPosition);
2320 lineEnds[linePtr] = currentPosition;
2326 } catch (IndexOutOfBoundsException e) {
2331 if (currentCharacter == '\n') {
2332 //must merge eventual cr followed by lf
2333 if (wasAcr && (lineEnds[linePtr] == (currentPosition - 2))) {
2334 //System.out.println("merge LF-" + (currentPosition - 1));
2335 lineEnds[linePtr] = currentPosition - 1;
2337 int separatorPos = currentPosition - 1;
2338 if ((linePtr > 0) && (lineEnds[linePtr] >= separatorPos))
2340 // System.out.println("LF-" + separatorPos);
2342 lineEnds[++linePtr] = separatorPos;
2343 } catch (IndexOutOfBoundsException e) {
2344 //linePtr value is correct
2345 int oldLength = lineEnds.length;
2346 int[] old = lineEnds;
2347 lineEnds = new int[oldLength + INCREMENT];
2348 System.arraycopy(old, 0, lineEnds, 0, oldLength);
2349 lineEnds[linePtr] = separatorPos;
2356 public final void pushUnicodeLineSeparator() {
2357 // isUnicode means that the \r or \n has been read as a unicode character
2359 //see comment on isLineDelimiter(char) for the use of '\n' and '\r'
2361 final int INCREMENT = 250;
2362 //currentCharacter is at position currentPosition-1
2364 if (this.checkNonExternalizedStringLiterals) {
2365 // reinitialize the current line for non externalize strings purpose
2370 if (currentCharacter == '\r') {
2371 int separatorPos = currentPosition - 6;
2372 if ((linePtr > 0) && (lineEnds[linePtr] >= separatorPos))
2374 //System.out.println("CR-" + separatorPos);
2376 lineEnds[++linePtr] = separatorPos;
2377 } catch (IndexOutOfBoundsException e) {
2378 //linePtr value is correct
2379 int oldLength = lineEnds.length;
2380 int[] old = lineEnds;
2381 lineEnds = new int[oldLength + INCREMENT];
2382 System.arraycopy(old, 0, lineEnds, 0, oldLength);
2383 lineEnds[linePtr] = separatorPos;
2385 // look-ahead for merged cr+lf
2386 if (source[currentPosition] == '\n') {
2387 //System.out.println("look-ahead LF-" + currentPosition);
2388 lineEnds[linePtr] = currentPosition;
2396 if (currentCharacter == '\n') {
2397 //must merge eventual cr followed by lf
2398 if (wasAcr && (lineEnds[linePtr] == (currentPosition - 7))) {
2399 //System.out.println("merge LF-" + (currentPosition - 1));
2400 lineEnds[linePtr] = currentPosition - 6;
2402 int separatorPos = currentPosition - 6;
2403 if ((linePtr > 0) && (lineEnds[linePtr] >= separatorPos))
2405 // System.out.println("LF-" + separatorPos);
2407 lineEnds[++linePtr] = separatorPos;
2408 } catch (IndexOutOfBoundsException e) {
2409 //linePtr value is correct
2410 int oldLength = lineEnds.length;
2411 int[] old = lineEnds;
2412 lineEnds = new int[oldLength + INCREMENT];
2413 System.arraycopy(old, 0, lineEnds, 0, oldLength);
2414 lineEnds[linePtr] = separatorPos;
2421 public final void recordComment(boolean isJavadoc) {
2423 // a new annotation comment is recorded
2425 commentStops[++commentPtr] =
2426 isJavadoc ? currentPosition : -currentPosition;
2427 } catch (IndexOutOfBoundsException e) {
2428 int oldStackLength = commentStops.length;
2429 int[] oldStack = commentStops;
2430 commentStops = new int[oldStackLength + 30];
2431 System.arraycopy(oldStack, 0, commentStops, 0, oldStackLength);
2432 commentStops[commentPtr] = isJavadoc ? currentPosition : -currentPosition;
2433 //grows the positions buffers too
2434 int[] old = commentStarts;
2435 commentStarts = new int[oldStackLength + 30];
2436 System.arraycopy(old, 0, commentStarts, 0, oldStackLength);
2439 //the buffer is of a correct size here
2440 commentStarts[commentPtr] = startPosition;
2442 public void resetTo(int begin, int end) {
2443 //reset the scanner to a given position where it may rescan again
2446 initialPosition = startPosition = currentPosition = begin;
2447 eofPosition = end < Integer.MAX_VALUE ? end + 1 : end;
2448 commentPtr = -1; // reset comment stack
2451 public final void scanSingleQuotedEscapeCharacter()
2452 throws InvalidInputException {
2453 // the string with "\\u" is a legal string of two chars \ and u
2454 //thus we use a direct access to the source (for regular cases).
2456 if (unicodeAsBackSlash) {
2457 // consume next character
2458 unicodeAsBackSlash = false;
2459 if (((currentCharacter = source[currentPosition++]) == '\\')
2460 && (source[currentPosition] == 'u')) {
2461 getNextUnicodeChar();
2463 if (withoutUnicodePtr != 0) {
2464 withoutUnicodeBuffer[++withoutUnicodePtr] = currentCharacter;
2468 currentCharacter = source[currentPosition++];
2469 switch (currentCharacter) {
2471 currentCharacter = '\'';
2474 currentCharacter = '\\';
2477 currentCharacter = '\\';
2482 public final void scanDoubleQuotedEscapeCharacter()
2483 throws InvalidInputException {
2484 // the string with "\\u" is a legal string of two chars \ and u
2485 //thus we use a direct access to the source (for regular cases).
2487 if (unicodeAsBackSlash) {
2488 // consume next character
2489 unicodeAsBackSlash = false;
2490 if (((currentCharacter = source[currentPosition++]) == '\\')
2491 && (source[currentPosition] == 'u')) {
2492 getNextUnicodeChar();
2494 if (withoutUnicodePtr != 0) {
2495 withoutUnicodeBuffer[++withoutUnicodePtr] = currentCharacter;
2499 currentCharacter = source[currentPosition++];
2500 switch (currentCharacter) {
2502 // currentCharacter = '\b';
2505 currentCharacter = '\t';
2508 currentCharacter = '\n';
2511 // currentCharacter = '\f';
2514 currentCharacter = '\r';
2517 currentCharacter = '\"';
2520 currentCharacter = '\'';
2523 currentCharacter = '\\';
2526 currentCharacter = '$';
2529 // -----------octal escape--------------
2531 // OctalDigit OctalDigit
2532 // ZeroToThree OctalDigit OctalDigit
2534 int number = Character.getNumericValue(currentCharacter);
2535 if (number >= 0 && number <= 7) {
2536 boolean zeroToThreeNot = number > 3;
2538 .isDigit(currentCharacter = source[currentPosition++])) {
2539 int digit = Character.getNumericValue(currentCharacter);
2540 if (digit >= 0 && digit <= 7) {
2541 number = (number * 8) + digit;
2543 .isDigit(currentCharacter = source[currentPosition++])) {
2544 if (zeroToThreeNot) { // has read \NotZeroToThree OctalDigit Digit --> ignore last character
2547 digit = Character.getNumericValue(currentCharacter);
2548 if (digit >= 0 && digit <= 7) {
2549 // has read \ZeroToThree OctalDigit OctalDigit
2550 number = (number * 8) + digit;
2551 } else { // has read \ZeroToThree OctalDigit NonOctalDigit --> ignore last character
2555 } else { // has read \OctalDigit NonDigit--> ignore last character
2558 } else { // has read \OctalDigit NonOctalDigit--> ignore last character
2561 } else { // has read \OctalDigit --> ignore last character
2565 throw new InvalidInputException(INVALID_ESCAPE);
2566 currentCharacter = (char) number;
2569 // throw new InvalidInputException(INVALID_ESCAPE);
2573 // public int scanIdentifierOrKeyword() throws InvalidInputException {
2574 // return scanIdentifierOrKeyword( false );
2577 public int scanIdentifierOrKeyword(boolean isVariable)
2578 throws InvalidInputException {
2581 //first dispatch on the first char.
2582 //then the length. If there are several
2583 //keywors with the same length AND the same first char, then do another
2584 //disptach on the second char :-)...cool....but fast !
2586 useAssertAsAnIndentifier = false;
2588 while (getNextCharAsJavaIdentifierPart()) {
2592 return TokenNameVariable;
2597 if (withoutUnicodePtr == 0)
2599 //quick test on length == 1 but not on length > 12 while most identifier
2600 //have a length which is <= 12...but there are lots of identifier with
2604 if ((length = currentPosition - startPosition) == 1)
2605 return TokenNameIdentifier;
2607 data = new char[length];
2608 index = startPosition;
2609 for (int i = 0; i < length; i++) {
2610 data[i] = Character.toLowerCase(source[index + i]);
2614 if ((length = withoutUnicodePtr) == 1)
2615 return TokenNameIdentifier;
2616 // data = withoutUnicodeBuffer;
2617 data = new char[withoutUnicodeBuffer.length];
2618 for (int i = 0; i < withoutUnicodeBuffer.length; i++) {
2619 data[i] = Character.toLowerCase(withoutUnicodeBuffer[i]);
2624 firstLetter = data[index];
2625 switch (firstLetter) {
2627 case 'a' : // as and array
2630 if ((data[++index] == 's')) {
2633 return TokenNameIdentifier;
2636 if ((data[++index] == 'n') && (data[++index] == 'd')) {
2637 return TokenNameAND;
2639 return TokenNameIdentifier;
2642 // if ((data[++index] == 'r') && (data[++index] == 'r') && (data[++index] == 'a') && (data[++index] == 'y'))
2643 // return TokenNamearray;
2645 // return TokenNameIdentifier;
2647 return TokenNameIdentifier;
2652 if ((data[++index] == 'r')
2653 && (data[++index] == 'e')
2654 && (data[++index] == 'a')
2655 && (data[++index] == 'k'))
2656 return TokenNamebreak;
2658 return TokenNameIdentifier;
2660 return TokenNameIdentifier;
2663 case 'c' : //case class continue
2666 if ((data[++index] == 'a')
2667 && (data[++index] == 's')
2668 && (data[++index] == 'e'))
2669 return TokenNamecase;
2671 return TokenNameIdentifier;
2673 if ((data[++index] == 'l')
2674 && (data[++index] == 'a')
2675 && (data[++index] == 's')
2676 && (data[++index] == 's'))
2677 return TokenNameclass;
2679 return TokenNameIdentifier;
2681 if ((data[++index] == 'o')
2682 && (data[++index] == 'n')
2683 && (data[++index] == 't')
2684 && (data[++index] == 'i')
2685 && (data[++index] == 'n')
2686 && (data[++index] == 'u')
2687 && (data[++index] == 'e'))
2688 return TokenNamecontinue;
2690 return TokenNameIdentifier;
2692 return TokenNameIdentifier;
2695 case 'd' : //define default do
2698 if ((data[++index] == 'o'))
2701 return TokenNameIdentifier;
2703 if ((data[++index] == 'e')
2704 && (data[++index] == 'f')
2705 && (data[++index] == 'i')
2706 && (data[++index] == 'n')
2707 && (data[++index] == 'e'))
2708 return TokenNamedefine;
2710 return TokenNameIdentifier;
2712 if ((data[++index] == 'e')
2713 && (data[++index] == 'f')
2714 && (data[++index] == 'a')
2715 && (data[++index] == 'u')
2716 && (data[++index] == 'l')
2717 && (data[++index] == 't'))
2718 return TokenNamedefault;
2720 return TokenNameIdentifier;
2722 return TokenNameIdentifier;
2724 case 'e' : //echo else elseif extends
2727 if ((data[++index] == 'c')
2728 && (data[++index] == 'h')
2729 && (data[++index] == 'o'))
2730 return TokenNameecho;
2732 (data[index] == 'l')
2733 && (data[++index] == 's')
2734 && (data[++index] == 'e'))
2735 return TokenNameelse;
2737 return TokenNameIdentifier;
2739 if ((data[++index] == 'n')
2740 && (data[++index] == 'd')
2741 && (data[++index] == 'i')
2742 && (data[++index] == 'f'))
2743 return TokenNameendif;
2745 return TokenNameIdentifier;
2747 if ((data[++index] == 'n')
2748 && (data[++index] == 'd')
2749 && (data[++index] == 'f')
2750 && (data[++index] == 'o')
2751 && (data[++index] == 'r'))
2752 return TokenNameendfor;
2754 (data[index] == 'l')
2755 && (data[++index] == 's')
2756 && (data[++index] == 'e')
2757 && (data[++index] == 'i')
2758 && (data[++index] == 'f'))
2759 return TokenNameelseif;
2761 return TokenNameIdentifier;
2763 if ((data[++index] == 'x')
2764 && (data[++index] == 't')
2765 && (data[++index] == 'e')
2766 && (data[++index] == 'n')
2767 && (data[++index] == 'd')
2768 && (data[++index] == 's'))
2769 return TokenNameextends;
2771 return TokenNameIdentifier;
2772 case 8 : // endwhile
2773 if ((data[++index] == 'n')
2774 && (data[++index] == 'd')
2775 && (data[++index] == 'w')
2776 && (data[++index] == 'h')
2777 && (data[++index] == 'i')
2778 && (data[++index] == 'l')
2779 && (data[++index] == 'e'))
2780 return TokenNameendwhile;
2782 return TokenNameIdentifier;
2783 case 9 : // endswitch
2784 if ((data[++index] == 'n')
2785 && (data[++index] == 'd')
2786 && (data[++index] == 's')
2787 && (data[++index] == 'w')
2788 && (data[++index] == 'i')
2789 && (data[++index] == 't')
2790 && (data[++index] == 'c')
2791 && (data[++index] == 'h'))
2792 return TokenNameendswitch;
2794 return TokenNameIdentifier;
2795 case 10 : // endforeach
2796 if ((data[++index] == 'n')
2797 && (data[++index] == 'd')
2798 && (data[++index] == 'f')
2799 && (data[++index] == 'o')
2800 && (data[++index] == 'r')
2801 && (data[++index] == 'e')
2802 && (data[++index] == 'a')
2803 && (data[++index] == 'c')
2804 && (data[++index] == 'h'))
2805 return TokenNameendforeach;
2807 return TokenNameIdentifier;
2810 return TokenNameIdentifier;
2813 case 'f' : //for false function
2816 if ((data[++index] == 'o') && (data[++index] == 'r'))
2817 return TokenNamefor;
2819 return TokenNameIdentifier;
2821 if ((data[++index] == 'a')
2822 && (data[++index] == 'l')
2823 && (data[++index] == 's')
2824 && (data[++index] == 'e'))
2825 return TokenNamefalse;
2827 return TokenNameIdentifier;
2828 case 7 : // function
2829 if ((data[++index] == 'o')
2830 && (data[++index] == 'r')
2831 && (data[++index] == 'e')
2832 && (data[++index] == 'a')
2833 && (data[++index] == 'c')
2834 && (data[++index] == 'h'))
2835 return TokenNameforeach;
2837 return TokenNameIdentifier;
2838 case 8 : // function
2839 if ((data[++index] == 'u')
2840 && (data[++index] == 'n')
2841 && (data[++index] == 'c')
2842 && (data[++index] == 't')
2843 && (data[++index] == 'i')
2844 && (data[++index] == 'o')
2845 && (data[++index] == 'n'))
2846 return TokenNamefunction;
2848 return TokenNameIdentifier;
2850 return TokenNameIdentifier;
2854 if ((data[++index] == 'l')
2855 && (data[++index] == 'o')
2856 && (data[++index] == 'b')
2857 && (data[++index] == 'a')
2858 && (data[++index] == 'l')) {
2859 return TokenNameglobal;
2862 return TokenNameIdentifier;
2867 if (data[++index] == 'f')
2870 return TokenNameIdentifier;
2872 // if ((data[++index] == 'n') && (data[++index] == 't'))
2873 // return TokenNameint;
2875 // return TokenNameIdentifier;
2877 if ((data[++index] == 'n')
2878 && (data[++index] == 'c')
2879 && (data[++index] == 'l')
2880 && (data[++index] == 'u')
2881 && (data[++index] == 'd')
2882 && (data[++index] == 'e'))
2883 return TokenNameinclude;
2885 return TokenNameIdentifier;
2887 if ((data[++index] == 'n')
2888 && (data[++index] == 'c')
2889 && (data[++index] == 'l')
2890 && (data[++index] == 'u')
2891 && (data[++index] == 'd')
2892 && (data[++index] == 'e')
2893 && (data[++index] == '_')
2894 && (data[++index] == 'o')
2895 && (data[++index] == 'n')
2896 && (data[++index] == 'c')
2897 && (data[++index] == 'e'))
2898 return TokenNameinclude_once;
2900 return TokenNameIdentifier;
2902 return TokenNameIdentifier;
2907 if ((data[++index] == 'i')
2908 && (data[++index] == 's')
2909 && (data[++index] == 't')) {
2910 return TokenNamelist;
2913 return TokenNameIdentifier;
2915 case 'n' : // new null
2918 if ((data[++index] == 'e') && (data[++index] == 'w'))
2919 return TokenNamenew;
2921 return TokenNameIdentifier;
2923 if ((data[++index] == 'u')
2924 && (data[++index] == 'l')
2925 && (data[++index] == 'l'))
2926 return TokenNamenull;
2928 return TokenNameIdentifier;
2931 return TokenNameIdentifier;
2933 case 'o' : // or old_function
2935 if (data[++index] == 'r') {
2939 // if (length == 12) {
2940 // if ((data[++index] == 'l')
2941 // && (data[++index] == 'd')
2942 // && (data[++index] == '_')
2943 // && (data[++index] == 'f')
2944 // && (data[++index] == 'u')
2945 // && (data[++index] == 'n')
2946 // && (data[++index] == 'c')
2947 // && (data[++index] == 't')
2948 // && (data[++index] == 'i')
2949 // && (data[++index] == 'o')
2950 // && (data[++index] == 'n')) {
2951 // return TokenNameold_function;
2954 return TokenNameIdentifier;
2958 if ((data[++index] == 'r')
2959 && (data[++index] == 'i')
2960 && (data[++index] == 'n')
2961 && (data[++index] == 't')) {
2962 return TokenNameprint;
2965 return TokenNameIdentifier;
2966 case 'r' : //return require require_once
2968 if ((data[++index] == 'e')
2969 && (data[++index] == 't')
2970 && (data[++index] == 'u')
2971 && (data[++index] == 'r')
2972 && (data[++index] == 'n')) {
2973 return TokenNamereturn;
2975 } else if (length == 7) {
2976 if ((data[++index] == 'e')
2977 && (data[++index] == 'q')
2978 && (data[++index] == 'u')
2979 && (data[++index] == 'i')
2980 && (data[++index] == 'r')
2981 && (data[++index] == 'e')) {
2982 return TokenNamerequire;
2984 } else if (length == 12) {
2985 if ((data[++index] == 'e')
2986 && (data[++index] == 'q')
2987 && (data[++index] == 'u')
2988 && (data[++index] == 'i')
2989 && (data[++index] == 'r')
2990 && (data[++index] == 'e')
2991 && (data[++index] == '_')
2992 && (data[++index] == 'o')
2993 && (data[++index] == 'n')
2994 && (data[++index] == 'c')
2995 && (data[++index] == 'e')) {
2996 return TokenNamerequire_once;
2999 return TokenNameIdentifier;
3001 case 's' : //static switch
3004 if (data[++index] == 't')
3005 if ((data[++index] == 'a')
3006 && (data[++index] == 't')
3007 && (data[++index] == 'i')
3008 && (data[++index] == 'c')) {
3009 return TokenNamestatic;
3011 return TokenNameIdentifier;
3013 (data[index] == 'w')
3014 && (data[++index] == 'i')
3015 && (data[++index] == 't')
3016 && (data[++index] == 'c')
3017 && (data[++index] == 'h'))
3018 return TokenNameswitch;
3020 return TokenNameIdentifier;
3022 return TokenNameIdentifier;
3029 if ((data[++index] == 'r')
3030 && (data[++index] == 'u')
3031 && (data[++index] == 'e'))
3032 return TokenNametrue;
3034 return TokenNameIdentifier;
3035 // if ((data[++index] == 'h') && (data[++index] == 'i') && (data[++index] == 's'))
3036 // return TokenNamethis;
3039 return TokenNameIdentifier;
3045 if ((data[++index] == 'a') && (data[++index] == 'r'))
3046 return TokenNamevar;
3048 return TokenNameIdentifier;
3051 return TokenNameIdentifier;
3057 if ((data[++index] == 'h')
3058 && (data[++index] == 'i')
3059 && (data[++index] == 'l')
3060 && (data[++index] == 'e'))
3061 return TokenNamewhile;
3063 return TokenNameIdentifier;
3064 //case 6:if ( (data[++index] =='i') && (data[++index]=='d') && (data[++index]=='e') && (data[++index]=='f')&& (data[++index]=='p'))
3065 //return TokenNamewidefp ;
3067 //return TokenNameIdentifier;
3069 return TokenNameIdentifier;
3075 if ((data[++index] == 'o') && (data[++index] == 'r'))
3076 return TokenNameXOR;
3078 return TokenNameIdentifier;
3081 return TokenNameIdentifier;
3084 return TokenNameIdentifier;
3087 public int scanNumber(boolean dotPrefix) throws InvalidInputException {
3089 //when entering this method the currentCharacter is the firt
3090 //digit of the number , i.e. it may be preceeded by a . when
3093 boolean floating = dotPrefix;
3094 if ((!dotPrefix) && (currentCharacter == '0')) {
3095 if (getNextChar('x', 'X') >= 0) { //----------hexa-----------------
3096 //force the first char of the hexa number do exist...
3097 // consume next character
3098 unicodeAsBackSlash = false;
3099 if (((currentCharacter = source[currentPosition++]) == '\\')
3100 && (source[currentPosition] == 'u')) {
3101 getNextUnicodeChar();
3103 if (withoutUnicodePtr != 0) {
3104 withoutUnicodeBuffer[++withoutUnicodePtr] = currentCharacter;
3107 if (Character.digit(currentCharacter, 16) == -1)
3108 throw new InvalidInputException(INVALID_HEXA);
3110 while (getNextCharAsDigit(16)) {
3112 // if (getNextChar('l', 'L') >= 0)
3113 // return TokenNameLongLiteral;
3115 return TokenNameIntegerLiteral;
3118 //there is x or X in the number
3119 //potential octal ! ... some one may write 000099.0 ! thus 00100 < 00078.0 is true !!!!! crazy language
3120 if (getNextCharAsDigit()) {
3121 //-------------potential octal-----------------
3122 while (getNextCharAsDigit()) {
3125 // if (getNextChar('l', 'L') >= 0) {
3126 // return TokenNameLongLiteral;
3129 // if (getNextChar('f', 'F') >= 0) {
3130 // return TokenNameFloatingPointLiteral;
3133 if (getNextChar('d', 'D') >= 0) {
3134 return TokenNameDoubleLiteral;
3135 } else { //make the distinction between octal and float ....
3136 if (getNextChar('.')) { //bingo ! ....
3137 while (getNextCharAsDigit()) {
3139 if (getNextChar('e', 'E') >= 0) {
3140 // consume next character
3141 unicodeAsBackSlash = false;
3142 if (((currentCharacter = source[currentPosition++]) == '\\')
3143 && (source[currentPosition] == 'u')) {
3144 getNextUnicodeChar();
3146 if (withoutUnicodePtr != 0) {
3147 withoutUnicodeBuffer[++withoutUnicodePtr] = currentCharacter;
3151 if ((currentCharacter == '-') || (currentCharacter == '+')) {
3152 // consume next character
3153 unicodeAsBackSlash = false;
3154 if (((currentCharacter = source[currentPosition++]) == '\\')
3155 && (source[currentPosition] == 'u')) {
3156 getNextUnicodeChar();
3158 if (withoutUnicodePtr != 0) {
3159 withoutUnicodeBuffer[++withoutUnicodePtr] =
3164 if (!Character.isDigit(currentCharacter))
3165 throw new InvalidInputException(INVALID_FLOAT);
3166 while (getNextCharAsDigit()) {
3169 // if (getNextChar('f', 'F') >= 0)
3170 // return TokenNameFloatingPointLiteral;
3171 getNextChar('d', 'D'); //jump over potential d or D
3172 return TokenNameDoubleLiteral;
3174 return TokenNameIntegerLiteral;
3182 while (getNextCharAsDigit()) {
3185 // if ((!dotPrefix) && (getNextChar('l', 'L') >= 0))
3186 // return TokenNameLongLiteral;
3188 if ((!dotPrefix) && (getNextChar('.'))) { //decimal part that can be empty
3189 while (getNextCharAsDigit()) {
3194 //if floating is true both exponant and suffix may be optional
3196 if (getNextChar('e', 'E') >= 0) {
3198 // consume next character
3199 unicodeAsBackSlash = false;
3200 if (((currentCharacter = source[currentPosition++]) == '\\')
3201 && (source[currentPosition] == 'u')) {
3202 getNextUnicodeChar();
3204 if (withoutUnicodePtr != 0) {
3205 withoutUnicodeBuffer[++withoutUnicodePtr] = currentCharacter;
3209 if ((currentCharacter == '-')
3210 || (currentCharacter == '+')) { // consume next character
3211 unicodeAsBackSlash = false;
3212 if (((currentCharacter = source[currentPosition++]) == '\\')
3213 && (source[currentPosition] == 'u')) {
3214 getNextUnicodeChar();
3216 if (withoutUnicodePtr != 0) {
3217 withoutUnicodeBuffer[++withoutUnicodePtr] = currentCharacter;
3221 if (!Character.isDigit(currentCharacter))
3222 throw new InvalidInputException(INVALID_FLOAT);
3223 while (getNextCharAsDigit()) {
3227 if (getNextChar('d', 'D') >= 0)
3228 return TokenNameDoubleLiteral;
3229 // if (getNextChar('f', 'F') >= 0)
3230 // return TokenNameFloatingPointLiteral;
3232 //the long flag has been tested before
3234 return floating ? TokenNameDoubleLiteral : TokenNameIntegerLiteral;
3237 * Search the line number corresponding to a specific position
3240 public final int getLineNumber(int position) {
3242 if (lineEnds == null)
3244 int length = linePtr + 1;
3247 int g = 0, d = length - 1;
3251 if (position < lineEnds[m]) {
3253 } else if (position > lineEnds[m]) {
3259 if (position < lineEnds[m]) {
3265 public void setPHPMode(boolean mode) {
3269 public final void setSource(char[] source) {
3270 //the source-buffer is set to sourceString
3272 if (source == null) {
3273 this.source = new char[0];
3275 this.source = source;
3278 initialPosition = currentPosition = 0;
3279 containsAssertKeyword = false;
3280 withoutUnicodeBuffer = new char[this.source.length];
3284 public String toString() {
3285 if (startPosition == source.length)
3286 return "EOF\n\n" + new String(source); //$NON-NLS-1$
3287 if (currentPosition > source.length)
3288 return "behind the EOF :-( ....\n\n" + new String(source); //$NON-NLS-1$
3290 char front[] = new char[startPosition];
3291 System.arraycopy(source, 0, front, 0, startPosition);
3293 int middleLength = (currentPosition - 1) - startPosition + 1;
3295 if (middleLength > -1) {
3296 middle = new char[middleLength];
3297 System.arraycopy(source, startPosition, middle, 0, middleLength);
3299 middle = new char[0];
3302 char end[] = new char[source.length - (currentPosition - 1)];
3305 (currentPosition - 1) + 1,
3308 source.length - (currentPosition - 1) - 1);
3310 return new String(front) + "\n===============================\nStarts here -->" //$NON-NLS-1$
3311 + new String(middle) + "<-- Ends here\n===============================\n" //$NON-NLS-1$
3314 public final String toStringAction(int act) {
3316 case TokenNameERROR :
3317 return "ScannerError(" + new String(getCurrentTokenSource()) + ")"; //$NON-NLS-1$
3318 case TokenNameStopPHP :
3319 return "StopPHP(" + new String(getCurrentTokenSource()) + ")"; //$NON-NLS-1$ //$NON-NLS-2$
3320 case TokenNameIdentifier :
3321 return "Identifier(" + new String(getCurrentTokenSource()) + ")"; //$NON-NLS-1$ //$NON-NLS-2$
3322 case TokenNameVariable :
3323 return "Variable(" + new String(getCurrentTokenSource()) + ")"; //$NON-NLS-1$ //$NON-NLS-2$
3325 return "as"; //$NON-NLS-1$
3326 case TokenNamebreak :
3327 return "break"; //$NON-NLS-1$
3328 case TokenNamecase :
3329 return "case"; //$NON-NLS-1$
3330 case TokenNameclass :
3331 return "class"; //$NON-NLS-1$
3332 case TokenNamecontinue :
3333 return "continue"; //$NON-NLS-1$
3334 case TokenNamedefault :
3335 return "default"; //$NON-NLS-1$
3336 case TokenNamedefine :
3337 return "define"; //$NON-NLS-1$
3339 return "do"; //$NON-NLS-1$
3340 case TokenNameecho :
3341 return "echo"; //$NON-NLS-1$
3342 case TokenNameelse :
3343 return "else"; //$NON-NLS-1$
3344 case TokenNameelseif :
3345 return "elseif"; //$NON-NLS-1$
3346 case TokenNameendfor :
3347 return "endfor"; //$NON-NLS-1$
3348 case TokenNameendforeach :
3349 return "endforeach"; //$NON-NLS-1$
3350 case TokenNameendif :
3351 return "endif"; //$NON-NLS-1$
3352 case TokenNameendswitch :
3353 return "endswitch"; //$NON-NLS-1$
3354 case TokenNameendwhile :
3355 return "endwhile"; //$NON-NLS-1$
3356 case TokenNameextends :
3357 return "extends"; //$NON-NLS-1$
3358 case TokenNamefalse :
3359 return "false"; //$NON-NLS-1$
3361 return "for"; //$NON-NLS-1$
3362 case TokenNameforeach :
3363 return "foreach"; //$NON-NLS-1$
3364 case TokenNamefunction :
3365 return "function"; //$NON-NLS-1$
3366 case TokenNameglobal :
3367 return "global"; //$NON-NLS-1$
3369 return "if"; //$NON-NLS-1$
3370 case TokenNameinclude :
3371 return "include"; //$NON-NLS-1$
3372 case TokenNameinclude_once :
3373 return "include_once"; //$NON-NLS-1$
3374 case TokenNamelist :
3375 return "list"; //$NON-NLS-1$
3377 return "new"; //$NON-NLS-1$
3378 case TokenNamenull :
3379 return "null"; //$NON-NLS-1$
3380 case TokenNameprint :
3381 return "print"; //$NON-NLS-1$
3382 case TokenNamerequire :
3383 return "require"; //$NON-NLS-1$
3384 case TokenNamerequire_once :
3385 return "require_once"; //$NON-NLS-1$
3386 case TokenNamereturn :
3387 return "return"; //$NON-NLS-1$
3388 case TokenNamestatic :
3389 return "static"; //$NON-NLS-1$
3390 case TokenNameswitch :
3391 return "switch"; //$NON-NLS-1$
3392 case TokenNametrue :
3393 return "true"; //$NON-NLS-1$
3395 return "var"; //$NON-NLS-1$
3396 case TokenNamewhile :
3397 return "while"; //$NON-NLS-1$
3398 case TokenNameIntegerLiteral :
3399 return "Integer(" + new String(getCurrentTokenSource()) + ")"; //$NON-NLS-1$ //$NON-NLS-2$
3400 case TokenNameDoubleLiteral :
3401 return "Double(" + new String(getCurrentTokenSource()) + ")"; //$NON-NLS-1$ //$NON-NLS-2$
3402 case TokenNameStringLiteral :
3403 return "String(" + new String(getCurrentTokenSource()) + ")"; //$NON-NLS-1$ //$NON-NLS-2$
3404 case TokenNameStringConstant :
3405 return "StringConstant(" + new String(getCurrentTokenSource()) + ")"; //$NON-NLS-1$ //$NON-NLS-2$
3406 case TokenNameStringInterpolated :
3407 return "StringInterpolated(" + new String(getCurrentTokenSource()) + ")"; //$NON-NLS-1$ //$NON-NLS-2$
3408 case TokenNameHEREDOC :
3409 return "HEREDOC(" + new String(getCurrentTokenSource()) + ")"; //$NON-NLS-1$
3411 case TokenNamePLUS_PLUS :
3412 return "++"; //$NON-NLS-1$
3413 case TokenNameMINUS_MINUS :
3414 return "--"; //$NON-NLS-1$
3415 case TokenNameEQUAL_EQUAL :
3416 return "=="; //$NON-NLS-1$
3417 case TokenNameEQUAL_GREATER :
3418 return "=>"; //$NON-NLS-1$
3419 case TokenNameLESS_EQUAL :
3420 return "<="; //$NON-NLS-1$
3421 case TokenNameGREATER_EQUAL :
3422 return ">="; //$NON-NLS-1$
3423 case TokenNameNOT_EQUAL :
3424 return "!="; //$NON-NLS-1$
3425 case TokenNameLEFT_SHIFT :
3426 return "<<"; //$NON-NLS-1$
3427 case TokenNameRIGHT_SHIFT :
3428 return ">>"; //$NON-NLS-1$
3429 case TokenNamePLUS_EQUAL :
3430 return "+="; //$NON-NLS-1$
3431 case TokenNameMINUS_EQUAL :
3432 return "-="; //$NON-NLS-1$
3433 case TokenNameMULTIPLY_EQUAL :
3434 return "*="; //$NON-NLS-1$
3435 case TokenNameDIVIDE_EQUAL :
3436 return "/="; //$NON-NLS-1$
3437 case TokenNameAND_EQUAL :
3438 return "&="; //$NON-NLS-1$
3439 case TokenNameOR_EQUAL :
3440 return "|="; //$NON-NLS-1$
3441 case TokenNameXOR_EQUAL :
3442 return "^="; //$NON-NLS-1$
3443 case TokenNameREMAINDER_EQUAL :
3444 return "%="; //$NON-NLS-1$
3445 case TokenNameLEFT_SHIFT_EQUAL :
3446 return "<<="; //$NON-NLS-1$
3447 case TokenNameRIGHT_SHIFT_EQUAL :
3448 return ">>="; //$NON-NLS-1$
3449 case TokenNameOR_OR :
3450 return "||"; //$NON-NLS-1$
3451 case TokenNameAND_AND :
3452 return "&&"; //$NON-NLS-1$
3453 case TokenNamePLUS :
3454 return "+"; //$NON-NLS-1$
3455 case TokenNameMINUS :
3456 return "-"; //$NON-NLS-1$
3457 case TokenNameMINUS_GREATER :
3460 return "!"; //$NON-NLS-1$
3461 case TokenNameREMAINDER :
3462 return "%"; //$NON-NLS-1$
3464 return "^"; //$NON-NLS-1$
3466 return "&"; //$NON-NLS-1$
3467 case TokenNameMULTIPLY :
3468 return "*"; //$NON-NLS-1$
3470 return "|"; //$NON-NLS-1$
3471 case TokenNameTWIDDLE :
3472 return "~"; //$NON-NLS-1$
3473 case TokenNameTWIDDLE_EQUAL :
3474 return "~="; //$NON-NLS-1$
3475 case TokenNameDIVIDE :
3476 return "/"; //$NON-NLS-1$
3477 case TokenNameGREATER :
3478 return ">"; //$NON-NLS-1$
3479 case TokenNameLESS :
3480 return "<"; //$NON-NLS-1$
3481 case TokenNameLPAREN :
3482 return "("; //$NON-NLS-1$
3483 case TokenNameRPAREN :
3484 return ")"; //$NON-NLS-1$
3485 case TokenNameLBRACE :
3486 return "{"; //$NON-NLS-1$
3487 case TokenNameRBRACE :
3488 return "}"; //$NON-NLS-1$
3489 case TokenNameLBRACKET :
3490 return "["; //$NON-NLS-1$
3491 case TokenNameRBRACKET :
3492 return "]"; //$NON-NLS-1$
3493 case TokenNameSEMICOLON :
3494 return ";"; //$NON-NLS-1$
3495 case TokenNameQUESTION :
3496 return "?"; //$NON-NLS-1$
3497 case TokenNameCOLON :
3498 return ":"; //$NON-NLS-1$
3499 case TokenNameCOMMA :
3500 return ","; //$NON-NLS-1$
3502 return "."; //$NON-NLS-1$
3503 case TokenNameEQUAL :
3504 return "="; //$NON-NLS-1$
3507 case TokenNameDOLLAR_LBRACE :
3510 return "EOF"; //$NON-NLS-1$
3512 return "not-a-token(" + (new Integer(act)) + ") " + new String(getCurrentTokenSource()); //$NON-NLS-1$
3517 boolean tokenizeComments,
3518 boolean tokenizeWhiteSpace,
3519 boolean checkNonExternalizedStringLiterals) {
3523 checkNonExternalizedStringLiterals,
3528 boolean tokenizeComments,
3529 boolean tokenizeWhiteSpace,
3530 boolean checkNonExternalizedStringLiterals,
3531 boolean assertMode) {
3532 this.eofPosition = Integer.MAX_VALUE;
3533 this.tokenizeComments = tokenizeComments;
3534 this.tokenizeWhiteSpace = tokenizeWhiteSpace;
3535 this.checkNonExternalizedStringLiterals =
3536 checkNonExternalizedStringLiterals;
3537 this.assertMode = assertMode;
3540 private void checkNonExternalizeString() throws InvalidInputException {
3541 if (currentLine == null)
3543 parseTags(currentLine);
3546 private void parseTags(NLSLine line) throws InvalidInputException {
3547 String s = new String(getCurrentTokenSource());
3548 int pos = s.indexOf(TAG_PREFIX);
3549 int lineLength = line.size();
3551 int start = pos + TAG_PREFIX_LENGTH;
3552 int end = s.indexOf(TAG_POSTFIX, start);
3553 String index = s.substring(start, end);
3556 i = Integer.parseInt(index) - 1;
3557 // Tags are one based not zero based.
3558 } catch (NumberFormatException e) {
3559 i = -1; // we don't want to consider this as a valid NLS tag
3561 if (line.exists(i)) {
3564 pos = s.indexOf(TAG_PREFIX, start);
3567 this.nonNLSStrings = new StringLiteral[lineLength];
3568 int nonNLSCounter = 0;
3569 for (Iterator iterator = line.iterator(); iterator.hasNext();) {
3570 StringLiteral literal = (StringLiteral) iterator.next();
3571 if (literal != null) {
3572 this.nonNLSStrings[nonNLSCounter++] = literal;
3575 if (nonNLSCounter == 0) {
3576 this.nonNLSStrings = null;
3580 this.wasNonExternalizedStringLiteral = true;
3581 if (nonNLSCounter != lineLength) {
3585 (this.nonNLSStrings = new StringLiteral[nonNLSCounter]),