blob: c75f888ec69634027f82c716243d347148e11a3d [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2000, 2010 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
* $Id: PublicScanner.java 23137 2009-12-04 20:03:06Z stephan $
*
* Contributors:
* IBM Corporation - initial API and implementation
* Fraunhofer FIRST - extended API and implementation
* Technical University Berlin - extended API and implementation
*******************************************************************************/
package org.eclipse.jdt.internal.core.util;
import org.eclipse.jdt.core.compiler.CharOperation;
import org.eclipse.jdt.core.compiler.IScanner;
import org.eclipse.jdt.core.compiler.ITerminalSymbols;
import org.eclipse.jdt.core.compiler.InvalidInputException;
import org.eclipse.jdt.internal.compiler.CompilationResult;
import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;
import org.eclipse.jdt.internal.compiler.parser.NLSTag;
import org.eclipse.jdt.internal.compiler.parser.ScannerHelper;
import org.eclipse.jdt.internal.compiler.util.Util;
public class PublicScanner implements IScanner, ITerminalSymbols {
//public int newIdentCount = 0;
/* APIs ares
- getNextToken() which return the current type of the token
(this value is not memorized by the scanner)
- getCurrentTokenSource() which provides with the token "REAL" source
(aka all unicode have been transformed into a correct char)
- sourceStart gives the position into the stream
- currentPosition-1 gives the sourceEnd position into the stream
*/
public long sourceLevel;
public long complianceLevel;
// 1.4 feature
public boolean useAssertAsAnIndentifier = false;
//flag indicating if processed source contains occurrences of keyword assert
public boolean containsAssertKeyword = false;
// 1.5 feature
public boolean useEnumAsAnIndentifier = false;
//{ObjectTeams: the scanner is now quite stateful:
// a master switch to turn off all OT keywords:
public boolean parsePureJavaOnly = false;
// experimental switch, set to true if you encounter problems with the scanner:
public boolean parseOTJonly = true;
// general switch for std-Java vs. OT/J
protected boolean _isOTSource = this.parseOTJonly; // initialized also in setSource().
/** Fully enable OT/J keywords. */
public void enterOTSource() {
this._isOTSource = true;
this._teamKeywordSeen = false; // not needed any more
}
// within the body of a base predicate "base" is not a keyword
protected boolean _forceBaseIsIdentifier = false;
// seen 'team' but no 'class'/'interface' yet -> 'base' could still be an imported package name.
protected boolean _teamKeywordSeen = false;
// directly after 'import' 'base' is always a keyword/modifier:
protected boolean _atStartOfImport = false;
public void forceBaseIsIdentifier() {
this._forceBaseIsIdentifier = true;
}
public void restoreBaseKeyword() {
this._forceBaseIsIdentifier = false;
}
protected boolean baseIsKeyword(boolean atStartOfImport) {
if (this.parsePureJavaOnly)
return false;
// "base" keyword may appear before 'class' header of containing
// team/role has been consumed.
if (this.currentCharacter == '.')
atStartOfImport = false;
return (this._isOTSource || atStartOfImport) && !this._forceBaseIsIdentifier;
}
// remember if the previous token was a callin/callout symbol ...
protected boolean _calloutSeen = false;
protected boolean _callinSeen = false;
// ... or the "precedence" keyword
protected boolean _precedenceSeen = false;
// after a '.' even 'team' can be an identifier:
private int _dotSeen = 0; // 0: no, 1: previos, 2: this token
public void resetOTFlags() {
this._isOTSource = this.parseOTJonly;
this._teamKeywordSeen = false;
this._forceBaseIsIdentifier = false;
this._callinSeen = false;
this._calloutSeen = false;
}
/**
* Check whether a given terminal token is currently enabled.
* Some keywords can be disabled:
* (base) as callin playedBy precedence tsuper when with
* Only within a join point query:
* # .. elementof
* Some keyworkds can only be disabled by parsePureJavaOnly:
* team readonly(?) within
*/
public boolean isTokenEnabled(int sym) {
switch (sym) {
case TokenNameteam:
case TokenNamewithin:
return !this.parsePureJavaOnly;
// since the 'readonly' keyword is not yet supported don't enforce it in non-OT code:
case TokenNamereadonly:
return this._isOTSource;
case TokenNamebase:
return baseIsKeyword(false);
case TokenNameas:
case TokenNameBINDIN:
case TokenNameBINDOUT:
case TokenNamecallin:
case TokenNameplayedBy:
case TokenNameprecedence:
case TokenNametsuper:
case TokenNamewhen:
case TokenNamewith:
return this._isOTSource;
}
return true;
}
// SH}
public boolean recordLineSeparator = false;
public char currentCharacter;
public int startPosition;
public int currentPosition;
public int initialPosition, eofPosition;
// after this position eof are generated instead of real token from the source
public boolean skipComments = false;
public boolean tokenizeComments = false;
public boolean tokenizeWhiteSpace = false;
//source should be viewed as a window (aka a part)
//of a entire very large stream
public char source[];
//unicode support
public char[] withoutUnicodeBuffer;
public int withoutUnicodePtr; //when == 0 ==> no unicode in the current token
public boolean unicodeAsBackSlash = false;
public boolean scanningFloatLiteral = false;
//support for /** comments
public final static int COMMENT_ARRAYS_SIZE = 30;
public int[] commentStops = new int[COMMENT_ARRAYS_SIZE];
public int[] commentStarts = new int[COMMENT_ARRAYS_SIZE];
public int[] commentTagStarts = new int[COMMENT_ARRAYS_SIZE];
public int commentPtr = -1; // no comment test with commentPtr value -1
protected int lastCommentLinePosition = -1;
// task tag support
public char[][] foundTaskTags = null;
public char[][] foundTaskMessages;
public char[][] foundTaskPriorities = null;
public int[][] foundTaskPositions;
public int foundTaskCount = 0;
public char[][] taskTags = null;
public char[][] taskPriorities = null;
public boolean isTaskCaseSensitive = true;
//diet parsing support - jump over some method body when requested
public boolean diet = false;
//support for the poor-line-debuggers ....
//remember the position of the cr/lf
public int[] lineEnds = new int[250];
public int linePtr = -1;
public boolean wasAcr = false;
public static final String END_OF_SOURCE = "End_Of_Source"; //$NON-NLS-1$
public static final String INVALID_HEXA = "Invalid_Hexa_Literal"; //$NON-NLS-1$
public static final String INVALID_OCTAL = "Invalid_Octal_Literal"; //$NON-NLS-1$
public static final String INVALID_CHARACTER_CONSTANT = "Invalid_Character_Constant"; //$NON-NLS-1$
public static final String INVALID_ESCAPE = "Invalid_Escape"; //$NON-NLS-1$
public static final String INVALID_INPUT = "Invalid_Input"; //$NON-NLS-1$
public static final String INVALID_UNICODE_ESCAPE = "Invalid_Unicode_Escape"; //$NON-NLS-1$
public static final String INVALID_FLOAT = "Invalid_Float_Literal"; //$NON-NLS-1$
public static final String INVALID_LOW_SURROGATE = "Invalid_Low_Surrogate"; //$NON-NLS-1$
public static final String INVALID_HIGH_SURROGATE = "Invalid_High_Surrogate"; //$NON-NLS-1$
public static final String NULL_SOURCE_STRING = "Null_Source_String"; //$NON-NLS-1$
public static final String UNTERMINATED_STRING = "Unterminated_String"; //$NON-NLS-1$
public static final String UNTERMINATED_COMMENT = "Unterminated_Comment"; //$NON-NLS-1$
public static final String INVALID_CHAR_IN_STRING = "Invalid_Char_In_String"; //$NON-NLS-1$
public static final String INVALID_DIGIT = "Invalid_Digit"; //$NON-NLS-1$
private static final int[] EMPTY_LINE_ENDS = Util.EMPTY_INT_ARRAY;
//----------------optimized identifier managment------------------
static final char[] charArray_a = new char[] {'a'},
charArray_b = new char[] {'b'},
charArray_c = new char[] {'c'},
charArray_d = new char[] {'d'},
charArray_e = new char[] {'e'},
charArray_f = new char[] {'f'},
charArray_g = new char[] {'g'},
charArray_h = new char[] {'h'},
charArray_i = new char[] {'i'},
charArray_j = new char[] {'j'},
charArray_k = new char[] {'k'},
charArray_l = new char[] {'l'},
charArray_m = new char[] {'m'},
charArray_n = new char[] {'n'},
charArray_o = new char[] {'o'},
charArray_p = new char[] {'p'},
charArray_q = new char[] {'q'},
charArray_r = new char[] {'r'},
charArray_s = new char[] {'s'},
charArray_t = new char[] {'t'},
charArray_u = new char[] {'u'},
charArray_v = new char[] {'v'},
charArray_w = new char[] {'w'},
charArray_x = new char[] {'x'},
charArray_y = new char[] {'y'},
charArray_z = new char[] {'z'};
static final char[] initCharArray =
new char[] {'\u0000', '\u0000', '\u0000', '\u0000', '\u0000', '\u0000'};
static final int TableSize = 30, InternalTableSize = 6; //30*6 =210 entries
public static final int OptimizedLength = 7;
//{ObjectTeams: really static:
public static final char[][][][] charArray_length;
// SH}
// support for detecting non-externalized string literals
public static final char[] TAG_PREFIX= "//$NON-NLS-".toCharArray(); //$NON-NLS-1$
public static final int TAG_PREFIX_LENGTH= TAG_PREFIX.length;
public static final char TAG_POSTFIX= '$';
public static final int TAG_POSTFIX_LENGTH= 1;
private NLSTag[] nlsTags = null;
protected int nlsTagsPtr;
public boolean checkNonExternalizedStringLiterals;
protected int lastPosition;
// generic support
public boolean returnOnlyGreater = false;
//{ObjectTeams: really static:
static int i,j,k; // fields so IBM JVM has no chance to optimize out wrongly
static {
// predictable initialization:
charArray_length =
new char[OptimizedLength][TableSize][InternalTableSize][];
for (i = 0; i < 6; i++) {
for (j = 0; j < TableSize; j++) {
for (k = 0; k < InternalTableSize; k++) {
// debug:
//System.out.print("i="+i+", j="+j+", k="+k+"; O="+OptimizedLength+", T="+TableSize+", I="+InternalTableSize);
//System.out.print(", l0="+charArray_length.length);
//System.out.print(", l1="+charArray_length[i].length);
//System.out.println(", l2="+charArray_length[i][j].length);
charArray_length[i][j][k] = initCharArray;
}
}
}
}
// SH}
/*static*/ int newEntry2 = 0,
newEntry3 = 0,
newEntry4 = 0,
newEntry5 = 0,
newEntry6 = 0;
public boolean insideRecovery = false;
public static final int RoundBracket = 0;
public static final int SquareBracket = 1;
public static final int CurlyBracket = 2;
public static final int BracketKinds = 3;
// extended unicode support
public static final int LOW_SURROGATE_MIN_VALUE = 0xDC00;
public static final int HIGH_SURROGATE_MIN_VALUE = 0xD800;
public static final int HIGH_SURROGATE_MAX_VALUE = 0xDBFF;
public static final int LOW_SURROGATE_MAX_VALUE = 0xDFFF;
public PublicScanner() {
this(false /*comment*/, false /*whitespace*/, false /*nls*/, ClassFileConstants.JDK1_3 /*sourceLevel*/, null/*taskTag*/, null/*taskPriorities*/, true /*taskCaseSensitive*/);
}
public PublicScanner(
boolean tokenizeComments,
boolean tokenizeWhiteSpace,
boolean checkNonExternalizedStringLiterals,
long sourceLevel,
long complianceLevel,
char[][] taskTags,
char[][] taskPriorities,
boolean isTaskCaseSensitive) {
this.eofPosition = Integer.MAX_VALUE;
this.tokenizeComments = tokenizeComments;
this.tokenizeWhiteSpace = tokenizeWhiteSpace;
this.sourceLevel = sourceLevel;
this.complianceLevel = complianceLevel;
this.checkNonExternalizedStringLiterals = checkNonExternalizedStringLiterals;
if (taskTags != null) {
int length = taskTags.length;
if (taskPriorities != null) {
int[] initialIndexes = new int[length];
for (int i = 0; i < length; i++) {
initialIndexes[i] = i;
}
Util.reverseQuickSort(taskTags, 0, taskTags.length - 1, initialIndexes);
char[][] temp = new char[length][];
for (int i = 0; i < length; i++) {
temp[i] = taskPriorities[initialIndexes[i]];
}
this.taskPriorities = temp;
} else {
Util.reverseQuickSort(taskTags, 0, taskTags.length - 1);
}
this.taskTags = taskTags;
this.isTaskCaseSensitive = isTaskCaseSensitive;
}
}
public PublicScanner(
boolean tokenizeComments,
boolean tokenizeWhiteSpace,
boolean checkNonExternalizedStringLiterals,
long sourceLevel,
char[][] taskTags,
char[][] taskPriorities,
boolean isTaskCaseSensitive) {
this(
tokenizeComments,
tokenizeWhiteSpace,
checkNonExternalizedStringLiterals,
sourceLevel,
sourceLevel,
taskTags,
taskPriorities,
isTaskCaseSensitive);
}
public final boolean atEnd() {
// This code is not relevant if source is
// Only a part of the real stream input
return this.eofPosition <= this.currentPosition;
}
// chech presence of task: tags
// TODO (frederic) see if we need to take unicode characters into account...
public void checkTaskTag(int commentStart, int commentEnd) throws InvalidInputException {
char[] src = this.source;
// only look for newer task: tags
if (this.foundTaskCount > 0
&& this.foundTaskPositions[this.foundTaskCount - 1][0] >= commentStart) {
return;
}
int foundTaskIndex = this.foundTaskCount;
char previous = src[commentStart+1]; // should be '*' or '/'
for (
int i = commentStart + 2; i < commentEnd && i < this.eofPosition; i++) {
char[] tag = null;
char[] priority = null;
// check for tag occurrence only if not ambiguous with javadoc tag
if (previous != '@') {
nextTag : for (int itag = 0; itag < this.taskTags.length; itag++) {
tag = this.taskTags[itag];
int tagLength = tag.length;
if (tagLength == 0) continue nextTag;
// ensure tag is not leaded with letter if tag starts with a letter
if (ScannerHelper.isJavaIdentifierStart(tag[0])) {
if (ScannerHelper.isJavaIdentifierPart(previous)) {
continue nextTag;
}
}
for (int t = 0; t < tagLength; t++) {
char sc, tc;
int x = i+t;
if (x >= this.eofPosition || x >= commentEnd) continue nextTag;
// case sensitive check
if ((sc = src[i + t]) != (tc = tag[t])) {
// case insensitive check
if (this.isTaskCaseSensitive || (ScannerHelper.toLowerCase(sc) != ScannerHelper.toLowerCase(tc))) {
continue nextTag;
}
}
}
// ensure tag is not followed with letter if tag finishes with a letter
if (i+tagLength < commentEnd && ScannerHelper.isJavaIdentifierPart(src[i+tagLength-1])) {
if (ScannerHelper.isJavaIdentifierPart(src[i + tagLength]))
continue nextTag;
}
if (this.foundTaskTags == null) {
this.foundTaskTags = new char[5][];
this.foundTaskMessages = new char[5][];
this.foundTaskPriorities = new char[5][];
this.foundTaskPositions = new int[5][];
} else if (this.foundTaskCount == this.foundTaskTags.length) {
System.arraycopy(this.foundTaskTags, 0, this.foundTaskTags = new char[this.foundTaskCount * 2][], 0, this.foundTaskCount);
System.arraycopy(this.foundTaskMessages, 0, this.foundTaskMessages = new char[this.foundTaskCount * 2][], 0, this.foundTaskCount);
System.arraycopy(this.foundTaskPriorities, 0, this.foundTaskPriorities = new char[this.foundTaskCount * 2][], 0, this.foundTaskCount);
System.arraycopy(this.foundTaskPositions, 0, this.foundTaskPositions = new int[this.foundTaskCount * 2][], 0, this.foundTaskCount);
}
priority = this.taskPriorities != null && itag < this.taskPriorities.length
? this.taskPriorities[itag]
: null;
this.foundTaskTags[this.foundTaskCount] = tag;
this.foundTaskPriorities[this.foundTaskCount] = priority;
this.foundTaskPositions[this.foundTaskCount] = new int[] { i, i + tagLength - 1 };
this.foundTaskMessages[this.foundTaskCount] = CharOperation.NO_CHAR;
this.foundTaskCount++;
i += tagLength - 1; // will be incremented when looping
break nextTag;
}
}
previous = src[i];
}
boolean containsEmptyTask = false;
for (int i = foundTaskIndex; i < this.foundTaskCount; i++) {
// retrieve message start and end positions
int msgStart = this.foundTaskPositions[i][0] + this.foundTaskTags[i].length;
int max_value = i + 1 < this.foundTaskCount
? this.foundTaskPositions[i + 1][0] - 1
: commentEnd - 1;
// at most beginning of next task
if (max_value < msgStart) {
max_value = msgStart; // would only occur if tag is before EOF.
}
int end = -1;
char c;
for (int j = msgStart; j < max_value; j++) {
if ((c = src[j]) == '\n' || c == '\r') {
end = j - 1;
break;
}
}
if (end == -1) {
for (int j = max_value; j > msgStart; j--) {
if ((c = src[j]) == '*') {
end = j - 1;
break;
}
}
if (end == -1)
end = max_value;
}
if (msgStart == end) {
// if the description is empty, we might want to see if two tags are not sharing the same message
// see https://bugs.eclipse.org/bugs/show_bug.cgi?id=110797
containsEmptyTask = true;
continue;
}
// trim the message
// we don't trim the beginning of the message to be able to show it after the task tag
while (CharOperation.isWhitespace(src[end]) && msgStart <= end)
end--;
// update the end position of the task
this.foundTaskPositions[i][1] = end;
// get the message source
final int messageLength = end - msgStart + 1;
char[] message = new char[messageLength];
System.arraycopy(src, msgStart, message, 0, messageLength);
this.foundTaskMessages[i] = message;
}
if (containsEmptyTask) {
for (int i = foundTaskIndex, max = this.foundTaskCount; i < max; i++) {
if (this.foundTaskMessages[i].length == 0) {
loop: for (int j = i + 1; j < max; j++) {
if (this.foundTaskMessages[j].length != 0) {
this.foundTaskMessages[i] = this.foundTaskMessages[j];
this.foundTaskPositions[i][1] = this.foundTaskPositions[j][1];
break loop;
}
}
}
}
}
}
public char[] getCurrentIdentifierSource() {
//return the token REAL source (aka unicodes are precomputed)
char[] result;
if (this.withoutUnicodePtr != 0) {
//0 is used as a fast test flag so the real first char is in position 1
System.arraycopy(
this.withoutUnicodeBuffer,
1,
result = new char[this.withoutUnicodePtr],
0,
this.withoutUnicodePtr);
} else {
int length = this.currentPosition - this.startPosition;
if (length == this.eofPosition) return this.source;
switch (length) { // see OptimizedLength
case 1 :
return optimizedCurrentTokenSource1();
case 2 :
return optimizedCurrentTokenSource2();
case 3 :
return optimizedCurrentTokenSource3();
case 4 :
return optimizedCurrentTokenSource4();
case 5 :
return optimizedCurrentTokenSource5();
case 6 :
return optimizedCurrentTokenSource6();
}
//no optimization
System.arraycopy(this.source, this.startPosition, result = new char[length], 0, length);
}
//newIdentCount++;
return result;
}
public int getCurrentTokenEndPosition(){
return this.currentPosition - 1;
}
public char[] getCurrentTokenSource() {
// Return the token REAL source (aka unicodes are precomputed)
char[] result;
if (this.withoutUnicodePtr != 0)
// 0 is used as a fast test flag so the real first char is in position 1
System.arraycopy(
this.withoutUnicodeBuffer,
1,
result = new char[this.withoutUnicodePtr],
0,
this.withoutUnicodePtr);
else {
int length;
System.arraycopy(
this.source,
this.startPosition,
result = new char[length = this.currentPosition - this.startPosition],
0,
length);
}
return result;
}
public final String getCurrentTokenString() {
// Return current token as a string
if (this.withoutUnicodePtr != 0) {
// 0 is used as a fast test flag so the real first char is in position 1
return new String(
this.withoutUnicodeBuffer,
1,
this.withoutUnicodePtr);
}
return new String(
this.source,
this.startPosition,
this.currentPosition - this.startPosition);
}
public char[] getCurrentTokenSourceString() {
//return the token REAL source (aka unicodes are precomputed).
//REMOVE the two " that are at the beginning and the end.
char[] result;
if (this.withoutUnicodePtr != 0)
//0 is used as a fast test flag so the real first char is in position 1
System.arraycopy(this.withoutUnicodeBuffer, 2,
//2 is 1 (real start) + 1 (to jump over the ")
result = new char[this.withoutUnicodePtr - 2], 0, this.withoutUnicodePtr - 2);
else {
int length;
System.arraycopy(
this.source,
this.startPosition + 1,
result = new char[length = this.currentPosition - this.startPosition - 2],
0,
length);
}
return result;
}
public final String getCurrentStringLiteral() {
//return the token REAL source (aka unicodes are precomputed).
//REMOVE the two " that are at the beginning and the end.
if (this.withoutUnicodePtr != 0)
//0 is used as a fast test flag so the real first char is in position 1
//2 is 1 (real start) + 1 (to jump over the ")
return new String(this.withoutUnicodeBuffer, 2, this.withoutUnicodePtr - 2);
else {
return new String(this.source, this.startPosition + 1, this.currentPosition - this.startPosition - 2);
}
}
public final char[] getRawTokenSource() {
int length = this.currentPosition - this.startPosition;
char[] tokenSource = new char[length];
System.arraycopy(this.source, this.startPosition, tokenSource, 0, length);
return tokenSource;
}
public final char[] getRawTokenSourceEnd() {
int length = this.eofPosition - this.currentPosition - 1;
char[] sourceEnd = new char[length];
System.arraycopy(this.source, this.currentPosition, sourceEnd, 0, length);
return sourceEnd;
}
public int getCurrentTokenStartPosition(){
return this.startPosition;
}
/*
* Search the source position corresponding to the end of a given line number
*
* Line numbers are 1-based, and relative to the scanner initialPosition.
* Character positions are 0-based.
*
* In case the given line number is inconsistent, answers -1.
*/
public final int getLineEnd(int lineNumber) {
if (this.lineEnds == null || this.linePtr == -1)
return -1;
if (lineNumber > this.lineEnds.length+1)
return -1;
if (lineNumber <= 0)
return -1;
if (lineNumber == this.lineEnds.length + 1)
return this.eofPosition;
return this.lineEnds[lineNumber-1]; // next line start one character behind the lineEnd of the previous line
}
public final int[] getLineEnds() {
//return a bounded copy of this.lineEnds
if (this.linePtr == -1) {
return EMPTY_LINE_ENDS;
}
int[] copy;
System.arraycopy(this.lineEnds, 0, copy = new int[this.linePtr + 1], 0, this.linePtr + 1);
return copy;
}
/**
* Search the source position corresponding to the beginning of a given line number
*
* Line numbers are 1-based, and relative to the scanner initialPosition.
* Character positions are 0-based.
*
* e.g. getLineStart(1) --> 0 indicates that the first line starts at character 0.
*
* In case the given line number is inconsistent, answers -1.
*
* @param lineNumber int
* @return int
*/
public final int getLineStart(int lineNumber) {
if (this.lineEnds == null || this.linePtr == -1)
return -1;
if (lineNumber > this.lineEnds.length + 1)
return -1;
if (lineNumber <= 0)
return -1;
if (lineNumber == 1)
return this.initialPosition;
return this.lineEnds[lineNumber-2]+1; // next line start one character behind the lineEnd of the previous line
}
public final int getNextChar() {
try {
if (((this.currentCharacter = this.source[this.currentPosition++]) == '\\')
&& (this.source[this.currentPosition] == 'u')) {
getNextUnicodeChar();
} else {
this.unicodeAsBackSlash = false;
if (this.withoutUnicodePtr != 0) {
unicodeStore();
}
}
return this.currentCharacter;
} catch (IndexOutOfBoundsException e) {
return -1;
} catch(InvalidInputException e) {
return -1;
}
}
public final int getNextCharWithBoundChecks() {
if (this.currentPosition >= this.eofPosition) {
return -1;
}
this.currentCharacter = this.source[this.currentPosition++];
if (this.currentPosition >= this.eofPosition) {
this.unicodeAsBackSlash = false;
if (this.withoutUnicodePtr != 0) {
unicodeStore();
}
return this.currentCharacter;
}
if (this.currentCharacter == '\\' && this.source[this.currentPosition] == 'u') {
try {
getNextUnicodeChar();
} catch (InvalidInputException e) {
return -1;
}
} else {
this.unicodeAsBackSlash = false;
if (this.withoutUnicodePtr != 0) {
unicodeStore();
}
}
return this.currentCharacter;
}
public final boolean getNextChar(char testedChar) {
//BOOLEAN
//handle the case of unicode.
//when a unicode appears then we must use a buffer that holds char internal values
//At the end of this method currentCharacter holds the new visited char
//and currentPosition points right next after it
//Both previous lines are true if the currentCharacter is == to the testedChar
//On false, no side effect has occured.
//ALL getNextChar.... ARE OPTIMIZED COPIES
if (this.currentPosition >= this.eofPosition) { // handle the obvious case upfront
this.unicodeAsBackSlash = false;
return false;
}
int temp = this.currentPosition;
try {
if (((this.currentCharacter = this.source[this.currentPosition++]) == '\\')
&& (this.source[this.currentPosition] == 'u')) {
getNextUnicodeChar();
if (this.currentCharacter != testedChar) {
this.currentPosition = temp;
this.withoutUnicodePtr--;
return false;
}
return true;
} //-------------end unicode traitement--------------
else {
if (this.currentCharacter != testedChar) {
this.currentPosition = temp;
return false;
}
this.unicodeAsBackSlash = false;
if (this.withoutUnicodePtr != 0)
unicodeStore();
return true;
}
} catch (IndexOutOfBoundsException e) {
this.unicodeAsBackSlash = false;
this.currentPosition = temp;
return false;
} catch(InvalidInputException e) {
this.unicodeAsBackSlash = false;
this.currentPosition = temp;
return false;
}
}
public final int getNextChar(char testedChar1, char testedChar2) {
//INT 0 : testChar1 \\\\///\\\\ 1 : testedChar2 \\\\///\\\\ -1 : others
//test can be done with (x==0) for the first and (x>0) for the second
//handle the case of unicode.
//when a unicode appears then we must use a buffer that holds char internal values
//At the end of this method currentCharacter holds the new visited char
//and currentPosition points right next after it
//Both previous lines are true if the currentCharacter is == to the testedChar1/2
//On false, no side effect has occured.
//ALL getNextChar.... ARE OPTIMIZED COPIES
if (this.currentPosition >= this.eofPosition) // handle the obvious case upfront
return -1;
int temp = this.currentPosition;
try {
int result;
if (((this.currentCharacter = this.source[this.currentPosition++]) == '\\')
&& (this.source[this.currentPosition] == 'u')) {
getNextUnicodeChar();
if (this.currentCharacter == testedChar1) {
result = 0;
} else if (this.currentCharacter == testedChar2) {
result = 1;
} else {
this.currentPosition = temp;
this.withoutUnicodePtr--;
result = -1;
}
return result;
} else {
if (this.currentCharacter == testedChar1) {
result = 0;
} else if (this.currentCharacter == testedChar2) {
result = 1;
} else {
this.currentPosition = temp;
return -1;
}
if (this.withoutUnicodePtr != 0)
unicodeStore();
return result;
}
} catch (IndexOutOfBoundsException e) {
this.currentPosition = temp;
return -1;
} catch(InvalidInputException e) {
this.currentPosition = temp;
return -1;
}
}
public final boolean getNextCharAsDigit() throws InvalidInputException {
//BOOLEAN
//handle the case of unicode.
//when a unicode appears then we must use a buffer that holds char internal values
//At the end of this method currentCharacter holds the new visited char
//and currentPosition points right next after it
//Both previous lines are true if the currentCharacter is a digit
//On false, no side effect has occured.
//ALL getNextChar.... ARE OPTIMIZED COPIES
if (this.currentPosition >= this.eofPosition) // handle the obvious case upfront
return false;
int temp = this.currentPosition;
try {
if (((this.currentCharacter = this.source[this.currentPosition++]) == '\\')
&& (this.source[this.currentPosition] == 'u')) {
getNextUnicodeChar();
if (!ScannerHelper.isDigit(this.currentCharacter)) {
this.currentPosition = temp;
this.withoutUnicodePtr--;
return false;
}
return true;
} else {
if (!ScannerHelper.isDigit(this.currentCharacter)) {
this.currentPosition = temp;
return false;
}
if (this.withoutUnicodePtr != 0)
unicodeStore();
return true;
}
} catch (IndexOutOfBoundsException e) {
this.currentPosition = temp;
return false;
} catch(InvalidInputException e) {
this.currentPosition = temp;
return false;
}
}
public final boolean getNextCharAsDigit(int radix) {
//BOOLEAN
//handle the case of unicode.
//when a unicode appears then we must use a buffer that holds char internal values
//At the end of this method currentCharacter holds the new visited char
//and currentPosition points right next after it
//Both previous lines are true if the currentCharacter is a digit base on radix
//On false, no side effect has occured.
//ALL getNextChar.... ARE OPTIMIZED COPIES
if (this.currentPosition >= this.eofPosition) // handle the obvious case upfront
return false;
int temp = this.currentPosition;
try {
if (((this.currentCharacter = this.source[this.currentPosition++]) == '\\')
&& (this.source[this.currentPosition] == 'u')) {
getNextUnicodeChar();
if (ScannerHelper.digit(this.currentCharacter, radix) == -1) {
this.currentPosition = temp;
this.withoutUnicodePtr--;
return false;
}
return true;
} else {
if (ScannerHelper.digit(this.currentCharacter, radix) == -1) {
this.currentPosition = temp;
return false;
}
if (this.withoutUnicodePtr != 0)
unicodeStore();
return true;
}
} catch (IndexOutOfBoundsException e) {
this.currentPosition = temp;
return false;
} catch(InvalidInputException e) {
this.currentPosition = temp;
return false;
}
}
public boolean getNextCharAsJavaIdentifierPartWithBoundCheck() {
//BOOLEAN
//handle the case of unicode.
//when a unicode appears then we must use a buffer that holds char internal values
//At the end of this method currentCharacter holds the new visited char
//and currentPosition points right next after it
//Both previous lines are true if the currentCharacter is a JavaIdentifierPart
//On false, no side effect has occured.
//ALL getNextChar.... ARE OPTIMIZED COPIES
int pos = this.currentPosition;
if (pos >= this.eofPosition) // handle the obvious case upfront
return false;
int temp2 = this.withoutUnicodePtr;
try {
boolean unicode = false;
this.currentCharacter = this.source[this.currentPosition++];
if (this.currentPosition < this.eofPosition) {
if (this.currentCharacter == '\\' && this.source[this.currentPosition] == 'u') {
getNextUnicodeChar();
unicode = true;
}
}
char c = this.currentCharacter;
boolean isJavaIdentifierPart = false;
if (c >= HIGH_SURROGATE_MIN_VALUE && c <= HIGH_SURROGATE_MAX_VALUE) {
if (this.complianceLevel < ClassFileConstants.JDK1_5) {
this.currentPosition = pos;
this.withoutUnicodePtr = temp2;
return false;
}
// Unicode 4 detection
char low = (char) getNextCharWithBoundChecks();
if (low < LOW_SURROGATE_MIN_VALUE || low > LOW_SURROGATE_MAX_VALUE) {
// illegal low surrogate
this.currentPosition = pos;
this.withoutUnicodePtr = temp2;
return false;
}
isJavaIdentifierPart = ScannerHelper.isJavaIdentifierPart(c, low);
}
else if (c >= LOW_SURROGATE_MIN_VALUE && c <= LOW_SURROGATE_MAX_VALUE) {
this.currentPosition = pos;
this.withoutUnicodePtr = temp2;
return false;
} else {
isJavaIdentifierPart = ScannerHelper.isJavaIdentifierPart(c);
}
if (unicode) {
if (!isJavaIdentifierPart) {
this.currentPosition = pos;
this.withoutUnicodePtr = temp2;
return false;
}
return true;
} else {
if (!isJavaIdentifierPart) {
this.currentPosition = pos;
return false;
}
if (this.withoutUnicodePtr != 0)
unicodeStore();
return true;
}
} catch(InvalidInputException e) {
this.currentPosition = pos;
this.withoutUnicodePtr = temp2;
return false;
}
}
public boolean getNextCharAsJavaIdentifierPart() {
//BOOLEAN
//handle the case of unicode.
//when a unicode appears then we must use a buffer that holds char internal values
//At the end of this method currentCharacter holds the new visited char
//and currentPosition points right next after it
//Both previous lines are true if the currentCharacter is a JavaIdentifierPart
//On false, no side effect has occured.
//ALL getNextChar.... ARE OPTIMIZED COPIES
int pos;
if ((pos = this.currentPosition) >= this.eofPosition) // handle the obvious case upfront
return false;
int temp2 = this.withoutUnicodePtr;
try {
boolean unicode = false;
if (((this.currentCharacter = this.source[this.currentPosition++]) == '\\')
&& (this.source[this.currentPosition] == 'u')) {
getNextUnicodeChar();
unicode = true;
}
char c = this.currentCharacter;
boolean isJavaIdentifierPart = false;
if (c >= HIGH_SURROGATE_MIN_VALUE && c <= HIGH_SURROGATE_MAX_VALUE) {
if (this.complianceLevel < ClassFileConstants.JDK1_5) {
this.currentPosition = pos;
this.withoutUnicodePtr = temp2;
return false;
}
// Unicode 4 detection
char low = (char) getNextChar();
if (low < LOW_SURROGATE_MIN_VALUE || low > LOW_SURROGATE_MAX_VALUE) {
// illegal low surrogate
this.currentPosition = pos;
this.withoutUnicodePtr = temp2;
return false;
}
isJavaIdentifierPart = ScannerHelper.isJavaIdentifierPart(c, low);
}
else if (c >= LOW_SURROGATE_MIN_VALUE && c <= LOW_SURROGATE_MAX_VALUE) {
this.currentPosition = pos;
this.withoutUnicodePtr = temp2;
return false;
} else {
isJavaIdentifierPart = ScannerHelper.isJavaIdentifierPart(c);
}
if (unicode) {
if (!isJavaIdentifierPart) {
this.currentPosition = pos;
this.withoutUnicodePtr = temp2;
return false;
}
return true;
} else {
if (!isJavaIdentifierPart) {
this.currentPosition = pos;
return false;
}
if (this.withoutUnicodePtr != 0)
unicodeStore();
return true;
}
} catch (IndexOutOfBoundsException e) {
this.currentPosition = pos;
this.withoutUnicodePtr = temp2;
return false;
} catch(InvalidInputException e) {
this.currentPosition = pos;
this.withoutUnicodePtr = temp2;
return false;
}
}
/*
* External API in JavaConventions.
* This is used to optimize the case where the scanner is used to scan a single identifier.
* In this case, the AIOOBE is slower to handle than a bound check
*/
public int scanIdentifier() throws InvalidInputException {
int whiteStart = 0;
while (true) { //loop for jumping over comments
this.withoutUnicodePtr = 0;
//start with a new token (even comment written with unicode )
// ---------Consume white space and handles startPosition---------
whiteStart = this.currentPosition;
boolean isWhiteSpace, hasWhiteSpaces = false;
int offset;
int unicodePtr;
boolean checkIfUnicode = false;
do {
unicodePtr = this.withoutUnicodePtr;
offset = this.currentPosition;
this.startPosition = this.currentPosition;
if (this.currentPosition < this.eofPosition) {
this.currentCharacter = this.source[this.currentPosition++];
checkIfUnicode = this.currentPosition < this.eofPosition
&& this.currentCharacter == '\\'
&& this.source[this.currentPosition] == 'u';
} else if (this.tokenizeWhiteSpace && (whiteStart != this.currentPosition - 1)) {
// reposition scanner in case we are interested by spaces as tokens
this.currentPosition--;
this.startPosition = whiteStart;
return TokenNameWHITESPACE;
} else {
return TokenNameEOF;
}
if (checkIfUnicode) {
isWhiteSpace = jumpOverUnicodeWhiteSpace();
offset = this.currentPosition - offset;
} else {
offset = this.currentPosition - offset;
// inline version of:
//isWhiteSpace =
// (this.currentCharacter == ' ') || ScannerHelper.isWhitespace(this.currentCharacter);
switch (this.currentCharacter) {
case 10 : /* \ u000a: LINE FEED */
case 12 : /* \ u000c: FORM FEED */
case 13 : /* \ u000d: CARRIAGE RETURN */
case 32 : /* \ u0020: SPACE */
case 9 : /* \ u0009: HORIZONTAL TABULATION */
isWhiteSpace = true;
break;
default :
isWhiteSpace = false;
}
}
if (isWhiteSpace) {
hasWhiteSpaces = true;
}
} while (isWhiteSpace);
if (hasWhiteSpaces) {
if (this.tokenizeWhiteSpace) {
// reposition scanner in case we are interested by spaces as tokens
this.currentPosition-=offset;
this.startPosition = whiteStart;
if (checkIfUnicode) {
this.withoutUnicodePtr = unicodePtr;
}
return TokenNameWHITESPACE;
} else if (checkIfUnicode) {
this.withoutUnicodePtr = 0;
unicodeStore();
} else {
this.withoutUnicodePtr = 0;
}
}
char c = this.currentCharacter;
if (c < ScannerHelper.MAX_OBVIOUS) {
if ((ScannerHelper.OBVIOUS_IDENT_CHAR_NATURES[c] & ScannerHelper.C_IDENT_START) != 0) {
return scanIdentifierOrKeywordWithBoundCheck();
}
return TokenNameERROR;
}
boolean isJavaIdStart;
if (c >= HIGH_SURROGATE_MIN_VALUE && c <= HIGH_SURROGATE_MAX_VALUE) {
if (this.complianceLevel < ClassFileConstants.JDK1_5) {
throw new InvalidInputException(INVALID_UNICODE_ESCAPE);
}
// Unicode 4 detection
char low = (char) getNextCharWithBoundChecks();
if (low < LOW_SURROGATE_MIN_VALUE || low > LOW_SURROGATE_MAX_VALUE) {
// illegal low surrogate
throw new InvalidInputException(INVALID_LOW_SURROGATE);
}
isJavaIdStart = ScannerHelper.isJavaIdentifierStart(c, low);
} else if (c >= LOW_SURROGATE_MIN_VALUE && c <= LOW_SURROGATE_MAX_VALUE) {
if (this.complianceLevel < ClassFileConstants.JDK1_5) {
throw new InvalidInputException(INVALID_UNICODE_ESCAPE);
}
throw new InvalidInputException(INVALID_HIGH_SURROGATE);
} else {
// optimized case already checked
isJavaIdStart = Character.isJavaIdentifierStart(c);
}
if (isJavaIdStart)
return scanIdentifierOrKeywordWithBoundCheck();
return TokenNameERROR;
}
}
public int getNextToken() throws InvalidInputException {
//{ObjectTeams: support '.' 'team':
if (this._dotSeen > 0)
this._dotSeen--; // "aging"
// SH}
this.wasAcr = false;
if (this.diet) {
jumpOverMethodBody();
this.diet = false;
return this.currentPosition > this.eofPosition ? TokenNameEOF : TokenNameRBRACE;
}
int whiteStart = 0;
try {
while (true) { //loop for jumping over comments
this.withoutUnicodePtr = 0;
//start with a new token (even comment written with unicode )
// ---------Consume white space and handles startPosition---------
whiteStart = this.currentPosition;
boolean isWhiteSpace, hasWhiteSpaces = false;
int offset;
int unicodePtr;
boolean checkIfUnicode = false;
do {
unicodePtr = this.withoutUnicodePtr;
offset = this.currentPosition;
this.startPosition = this.currentPosition;
try {
checkIfUnicode = ((this.currentCharacter = this.source[this.currentPosition++]) == '\\')
&& (this.source[this.currentPosition] == 'u');
} catch(IndexOutOfBoundsException e) {
if (this.tokenizeWhiteSpace && (whiteStart != this.currentPosition - 1)) {
// reposition scanner in case we are interested by spaces as tokens
this.currentPosition--;
this.startPosition = whiteStart;
return TokenNameWHITESPACE;
}
if (this.currentPosition > this.eofPosition)
return TokenNameEOF;
}
if (this.currentPosition > this.eofPosition) {
if (this.tokenizeWhiteSpace && (whiteStart != this.currentPosition - 1)) {
this.currentPosition--;
// reposition scanner in case we are interested by spaces as tokens
this.startPosition = whiteStart;
return TokenNameWHITESPACE;
}
return TokenNameEOF;
}
if (checkIfUnicode) {
isWhiteSpace = jumpOverUnicodeWhiteSpace();
offset = this.currentPosition - offset;
} else {
offset = this.currentPosition - offset;
if ((this.currentCharacter == '\r') || (this.currentCharacter == '\n')) {
if (this.recordLineSeparator) {
pushLineSeparator();
}
}
// inline version of:
//isWhiteSpace =
// (this.currentCharacter == ' ') || ScannerHelper.isWhitespace(this.currentCharacter);
switch (this.currentCharacter) {
case 10 : /* \ u000a: LINE FEED */
case 12 : /* \ u000c: FORM FEED */
case 13 : /* \ u000d: CARRIAGE RETURN */
case 32 : /* \ u0020: SPACE */
case 9 : /* \ u0009: HORIZONTAL TABULATION */
isWhiteSpace = true;
break;
default :
isWhiteSpace = false;
}
}
if (isWhiteSpace) {
hasWhiteSpaces = true;
}
} while (isWhiteSpace);
if (hasWhiteSpaces) {
if (this.tokenizeWhiteSpace) {
// reposition scanner in case we are interested by spaces as tokens
this.currentPosition-=offset;
this.startPosition = whiteStart;
if (checkIfUnicode) {
this.withoutUnicodePtr = unicodePtr;
}
return TokenNameWHITESPACE;
} else if (checkIfUnicode) {
this.withoutUnicodePtr = 0;
unicodeStore();
} else {
this.withoutUnicodePtr = 0;
}
}
// ---------Identify the next token-------------
switch (this.currentCharacter) {
case '@' :
/* if (this.sourceLevel >= ClassFileConstants.JDK1_5) {
return TokenNameAT;
} else {
return TokenNameERROR;
}*/
return TokenNameAT;
case '(' :
return TokenNameLPAREN;
case ')' :
return TokenNameRPAREN;
case '{' :
return TokenNameLBRACE;
case '}' :
return TokenNameRBRACE;
case '[' :
return TokenNameLBRACKET;
case ']' :
return TokenNameRBRACKET;
case ';' :
return TokenNameSEMICOLON;
case ',' :
return TokenNameCOMMA;
case '.' :
if (getNextCharAsDigit()) {
return scanNumber(true);
}
int temp = this.currentPosition;
if (getNextChar('.')) {
if (getNextChar('.')) {
return TokenNameELLIPSIS;
} else {
this.currentPosition = temp;
return TokenNameDOT;
}
} else {
//{ObjectTeams: record the one '.':
this._dotSeen = 2; // now
// SH}
this.currentPosition = temp;
return TokenNameDOT;
}
case '+' :
{
int test;
if ((test = getNextChar('+', '=')) == 0)
return TokenNamePLUS_PLUS;
if (test > 0)
return TokenNamePLUS_EQUAL;
return TokenNamePLUS;
}
case '-' :
{
int test;
if ((test = getNextChar('-', '=')) == 0)
return TokenNameMINUS_MINUS;
if (test > 0)
return TokenNameMINUS_EQUAL;
//{ObjectTeams: check for callout binding after '-' tokens
else {
if (test < 0 && this._isOTSource)
if (getNextChar('>')) {
this._calloutSeen = true;
return TokenNameBINDOUT;
}
}
// Markus Witte}
return TokenNameMINUS;
}
case '~' :
return TokenNameTWIDDLE;
case '!' :
if (getNextChar('='))
return TokenNameNOT_EQUAL;
return TokenNameNOT;
case '*' :
if (getNextChar('='))
return TokenNameMULTIPLY_EQUAL;
return TokenNameMULTIPLY;
case '%' :
if (getNextChar('='))
return TokenNameREMAINDER_EQUAL;
return TokenNameREMAINDER;
case '<' :
{
int test;
if ((test = getNextChar('=', '<')) == 0)
return TokenNameLESS_EQUAL;
if (test > 0) {
if (getNextChar('='))
return TokenNameLEFT_SHIFT_EQUAL;
return TokenNameLEFT_SHIFT;
}
//{ObjectTeams: check for callin binding after '<' tokens
else {
if (test < 0 && this._isOTSource)
if (getNextChar('-')) {
this._callinSeen = true;
return TokenNameBINDIN;
}
}
// Markus Witte}
return TokenNameLESS;
}
case '>' :
{
int test;
if (this.returnOnlyGreater) {
return TokenNameGREATER;
}
if ((test = getNextChar('=', '>')) == 0)
return TokenNameGREATER_EQUAL;
if (test > 0) {
if ((test = getNextChar('=', '>')) == 0)
return TokenNameRIGHT_SHIFT_EQUAL;
if (test > 0) {
if (getNextChar('='))
return TokenNameUNSIGNED_RIGHT_SHIFT_EQUAL;
return TokenNameUNSIGNED_RIGHT_SHIFT;
}
return TokenNameRIGHT_SHIFT;
}
return TokenNameGREATER;
}
case '=' :
//{ObjectTeams: check for callout override after '=' tokens
/* @original
if (getNextChar('='))
return TokenNameEQUAL_EQUAL;
return TokenNameEQUAL;
*/
{
int test;
if ((test = getNextChar('=', '>')) == 0)
return TokenNameEQUAL_EQUAL;
if (test > 0) {
this._calloutSeen = true;
return TokenNameCALLOUT_OVERRIDE;
} else {
return TokenNameEQUAL;
}
}
// Markus Witte}
case '&' :
{
int test;
if ((test = getNextChar('&', '=')) == 0)
return TokenNameAND_AND;
if (test > 0)
return TokenNameAND_EQUAL;
return TokenNameAND;
}
case '|' :
{
int test;
if ((test = getNextChar('|', '=')) == 0)
return TokenNameOR_OR;
if (test > 0)
return TokenNameOR_EQUAL;
return TokenNameOR;
}
case '^' :
if (getNextChar('='))
return TokenNameXOR_EQUAL;
return TokenNameXOR;
case '?' :
return TokenNameQUESTION;
case ':' :
return TokenNameCOLON;
case '\'' :
{
int test;
if ((test = getNextChar('\n', '\r')) == 0) {
throw new InvalidInputException(INVALID_CHARACTER_CONSTANT);
}
if (test > 0) {
// relocate if finding another quote fairly close: thus unicode '/u000D' will be fully consumed
for (int lookAhead = 0; lookAhead < 3; lookAhead++) {
if (this.currentPosition + lookAhead == this.eofPosition)
break;
if (this.source[this.currentPosition + lookAhead] == '\n')
break;
if (this.source[this.currentPosition + lookAhead] == '\'') {
this.currentPosition += lookAhead + 1;
break;
}
}
throw new InvalidInputException(INVALID_CHARACTER_CONSTANT);
}
}
if (getNextChar('\'')) {
// relocate if finding another quote fairly close: thus unicode '/u000D' will be fully consumed
for (int lookAhead = 0; lookAhead < 3; lookAhead++) {
if (this.currentPosition + lookAhead == this.eofPosition)
break;
if (this.source[this.currentPosition + lookAhead] == '\n')
break;
if (this.source[this.currentPosition + lookAhead] == '\'') {
this.currentPosition += lookAhead + 1;
break;
}
}
throw new InvalidInputException(INVALID_CHARACTER_CONSTANT);
}
if (getNextChar('\\')) {
if (this.unicodeAsBackSlash) {
// consume next character
this.unicodeAsBackSlash = false;
if (((this.currentCharacter = this.source[this.currentPosition++]) == '\\') && (this.source[this.currentPosition] == 'u')) {
getNextUnicodeChar();
} else {
if (this.withoutUnicodePtr != 0) {
unicodeStore();
}
}
} else {
this.currentCharacter = this.source[this.currentPosition++];
}
scanEscapeCharacter();
} else { // consume next character
this.unicodeAsBackSlash = false;
checkIfUnicode = false;
try {
checkIfUnicode = ((this.currentCharacter = this.source[this.currentPosition++]) == '\\')
&& (this.source[this.currentPosition] == 'u');
} catch(IndexOutOfBoundsException e) {
this.currentPosition--;
throw new InvalidInputException(INVALID_CHARACTER_CONSTANT);
}
if (checkIfUnicode) {
getNextUnicodeChar();
} else {
if (this.withoutUnicodePtr != 0) {
unicodeStore();
}
}
}
if (getNextChar('\''))
return TokenNameCharacterLiteral;
// relocate if finding another quote fairly close: thus unicode '/u000D' will be fully consumed
for (int lookAhead = 0; lookAhead < 20; lookAhead++) {
if (this.currentPosition + lookAhead == this.eofPosition)
break;
if (this.source[this.currentPosition + lookAhead] == '\n')
break;
if (this.source[this.currentPosition + lookAhead] == '\'') {
this.currentPosition += lookAhead + 1;
break;
}
}
throw new InvalidInputException(INVALID_CHARACTER_CONSTANT);
case '"' :
try {
// consume next character
this.unicodeAsBackSlash = false;
boolean isUnicode = false;
if (((this.currentCharacter = this.source[this.currentPosition++]) == '\\')
&& (this.source[this.currentPosition] == 'u')) {
getNextUnicodeChar();
isUnicode = true;
} else {
if (this.withoutUnicodePtr != 0) {
unicodeStore();
}
}
while (this.currentCharacter != '"') {
if (this.currentPosition >= this.eofPosition) {
throw new InvalidInputException(UNTERMINATED_STRING);
}
/**** \r and \n are not valid in string literals ****/
if ((this.currentCharacter == '\n') || (this.currentCharacter == '\r')) {
// relocate if finding another quote fairly close: thus unicode '/u000D' will be fully consumed
if (isUnicode) {
int start = this.currentPosition;
for (int lookAhead = 0; lookAhead < 50; lookAhead++) {
if (this.currentPosition >= this.eofPosition) {
this.currentPosition = start;
break;
}
if (((this.currentCharacter = this.source[this.currentPosition++]) == '\\') && (this.source[this.currentPosition] == 'u')) {
isUnicode = true;
getNextUnicodeChar();
} else {
isUnicode = false;
}
if (!isUnicode && this.currentCharacter == '\n') {
this.currentPosition--; // set current position on new line character
break;
}
if (this.currentCharacter == '\"') {
throw new InvalidInputException(INVALID_CHAR_IN_STRING);
}
}
} else {
this.currentPosition--; // set current position on new line character
}
throw new InvalidInputException(INVALID_CHAR_IN_STRING);
}
if (this.currentCharacter == '\\') {
if (this.unicodeAsBackSlash) {
this.withoutUnicodePtr--;
// consume next character
this.unicodeAsBackSlash = false;
if (((this.currentCharacter = this.source[this.currentPosition++]) == '\\') && (this.source[this.currentPosition] == 'u')) {
getNextUnicodeChar();
isUnicode = true;
this.withoutUnicodePtr--;
} else {
isUnicode = false;
}
} else {
if (this.withoutUnicodePtr == 0) {
unicodeInitializeBuffer(this.currentPosition - this.startPosition);
}
this.withoutUnicodePtr --;
this.currentCharacter = this.source[this.currentPosition++];
}
// we need to compute the escape character in a separate buffer
scanEscapeCharacter();
if (this.withoutUnicodePtr != 0) {
unicodeStore();
}
}
// consume next character
this.unicodeAsBackSlash = false;
if (((this.currentCharacter = this.source[this.currentPosition++]) == '\\')
&& (this.source[this.currentPosition] == 'u')) {
getNextUnicodeChar();
isUnicode = true;
} else {
isUnicode = false;
if (this.withoutUnicodePtr != 0) {
unicodeStore();
}
}
}
} catch (IndexOutOfBoundsException e) {
this.currentPosition--;
throw new InvalidInputException(UNTERMINATED_STRING);
} catch (InvalidInputException e) {
if (e.getMessage().equals(INVALID_ESCAPE)) {
// relocate if finding another quote fairly close: thus unicode '/u000D' will be fully consumed
for (int lookAhead = 0; lookAhead < 50; lookAhead++) {
if (this.currentPosition + lookAhead == this.eofPosition)
break;
if (this.source[this.currentPosition + lookAhead] == '\n')
break;
if (this.source[this.currentPosition + lookAhead] == '\"') {
this.currentPosition += lookAhead + 1;
break;
}
}
}
throw e; // rethrow
}
return TokenNameStringLiteral;
case '/' :
if (!this.skipComments) {
int test = getNextChar('/', '*');
if (test == 0) { //line comment
this.lastCommentLinePosition = this.currentPosition;
try { //get the next char
if (((this.currentCharacter = this.source[this.currentPosition++]) == '\\')
&& (this.source[this.currentPosition] == 'u')) {
getNextUnicodeChar();
}
//handle the \\u case manually into comment
if (this.currentCharacter == '\\') {
if (this.source[this.currentPosition] == '\\')
this.currentPosition++;
} //jump over the \\
boolean isUnicode = false;
while (this.currentCharacter != '\r' && this.currentCharacter != '\n') {
if (this.currentPosition >= this.eofPosition) {
this.lastCommentLinePosition = this.currentPosition;
this.currentPosition ++;
// this avoids duplicating the code in the catch(IndexOutOfBoundsException e)
throw new IndexOutOfBoundsException();
}
this.lastCommentLinePosition = this.currentPosition;
//get the next char
isUnicode = false;
if (((this.currentCharacter = this.source[this.currentPosition++]) == '\\')
&& (this.source[this.currentPosition] == 'u')) {
getNextUnicodeChar();
isUnicode = true;
}
//handle the \\u case manually into comment
if (this.currentCharacter == '\\') {
if (this.source[this.currentPosition] == '\\')
this.currentPosition++;
} //jump over the \\
}
/*
* We need to completely consume the line break
*/
if (this.currentCharacter == '\r'
&& this.eofPosition > this.currentPosition) {
if (this.source[this.currentPosition] == '\n') {
this.currentPosition++;
this.currentCharacter = '\n';
} else if ((this.source[this.currentPosition] == '\\')
&& (this.source[this.currentPosition + 1] == 'u')) {
getNextUnicodeChar();
isUnicode = true;
}
}
recordComment(TokenNameCOMMENT_LINE);
if (this.taskTags != null) checkTaskTag(this.startPosition, this.currentPosition);
if ((this.currentCharacter == '\r') || (this.currentCharacter == '\n')) {
if (this.checkNonExternalizedStringLiterals &&
this.lastPosition < this.currentPosition) {
parseTags();
}
if (this.recordLineSeparator) {
if (isUnicode) {
pushUnicodeLineSeparator();
} else {
pushLineSeparator();
}
}
}
if (this.tokenizeComments) {
return TokenNameCOMMENT_LINE;
}
} catch (IndexOutOfBoundsException e) {
this.currentPosition--;
recordComment(TokenNameCOMMENT_LINE);
if (this.taskTags != null) checkTaskTag(this.startPosition, this.currentPosition);
if (this.checkNonExternalizedStringLiterals &&
this.lastPosition < this.currentPosition) {
parseTags();
}
if (this.tokenizeComments) {
return TokenNameCOMMENT_LINE;
} else {
this.currentPosition++;
}
}
break;
}
if (test > 0) { //traditional and javadoc comment
try { //get the next char
boolean isJavadoc = false, star = false;
boolean isUnicode = false;
int previous;
// consume next character
this.unicodeAsBackSlash = false;
if (((this.currentCharacter = this.source[this.currentPosition++]) == '\\')
&& (this.source[this.currentPosition] == 'u')) {
getNextUnicodeChar();
isUnicode = true;
} else {
isUnicode = false;
if (this.withoutUnicodePtr != 0) {
unicodeStore();
}
}
if (this.currentCharacter == '*') {
isJavadoc = true;
star = true;
}
if ((this.currentCharacter == '\r') || (this.currentCharacter == '\n')) {
if (this.recordLineSeparator) {
if (isUnicode) {
pushUnicodeLineSeparator();
} else {
pushLineSeparator();
}
}
}
isUnicode = false;
previous = this.currentPosition;
if (((this.currentCharacter = this.source[this.currentPosition++]) == '\\')
&& (this.source[this.currentPosition] == 'u')) {
//-------------unicode traitement ------------
getNextUnicodeChar();
isUnicode = true;
} else {
isUnicode = false;
}
//handle the \\u case manually into comment
if (this.currentCharacter == '\\') {
if (this.source[this.currentPosition] == '\\')
this.currentPosition++; //jump over the \\
}
// empty comment is not a javadoc /**/
if (this.currentCharacter == '/') {
isJavadoc = false;
}
//loop until end of comment */
int firstTag = 0;
while ((this.currentCharacter != '/') || (!star)) {
if (this.currentPosition >= this.eofPosition) {
throw new InvalidInputException(UNTERMINATED_COMMENT);
}
if ((this.currentCharacter == '\r') || (this.currentCharacter == '\n')) {
if (this.recordLineSeparator) {
if (isUnicode) {
pushUnicodeLineSeparator();
} else {
pushLineSeparator();
}
}
}
switch (this.currentCharacter) {
case '*':
star = true;
break;
case '@':
if (firstTag == 0 && this.isFirstTag()) {
firstTag = previous;
}
//$FALL-THROUGH$ default case to set star to false
default:
star = false;
}
//get next char
previous = this.currentPosition;
if (((this.currentCharacter = this.source[this.currentPosition++]) == '\\')
&& (this.source[this.currentPosition] == 'u')) {
//-------------unicode traitement ------------
getNextUnicodeChar();
isUnicode = true;
} else {
isUnicode = false;
}
//handle the \\u case manually into comment
if (this.currentCharacter == '\\') {
if (this.source[this.currentPosition] == '\\')
this.currentPosition++;
} //jump over the \\
}
int token = isJavadoc ? TokenNameCOMMENT_JAVADOC : TokenNameCOMMENT_BLOCK;
recordComment(token);
this.commentTagStarts[this.commentPtr] = firstTag;
if (this.taskTags != null) checkTaskTag(this.startPosition, this.currentPosition);
if (this.tokenizeComments) {
/*
if (isJavadoc)
return TokenNameCOMMENT_JAVADOC;
return TokenNameCOMMENT_BLOCK;
*/
return token;
}
} catch (IndexOutOfBoundsException e) {
this.currentPosition--;
throw new InvalidInputException(UNTERMINATED_COMMENT);
}
break;
}
}
if (getNextChar('='))
return TokenNameDIVIDE_EQUAL;
return TokenNameDIVIDE;
case '\u001a' :
if (atEnd())
return TokenNameEOF;
//the atEnd may not be <currentPosition == source.length> if source is only some part of a real (external) stream
throw new InvalidInputException("Ctrl-Z"); //$NON-NLS-1$
default :
char c = this.currentCharacter;
if (c < ScannerHelper.MAX_OBVIOUS) {
if ((ScannerHelper.OBVIOUS_IDENT_CHAR_NATURES[c] & ScannerHelper.C_IDENT_START) != 0) {
return scanIdentifierOrKeyword();
} else if ((ScannerHelper.OBVIOUS_IDENT_CHAR_NATURES[c] & ScannerHelper.C_DIGIT) != 0) {
return scanNumber(false);
} else {
return TokenNameERROR;
}
}
boolean isJavaIdStart;
if (c >= HIGH_SURROGATE_MIN_VALUE && c <= HIGH_SURROGATE_MAX_VALUE) {
if (this.complianceLevel < ClassFileConstants.JDK1_5) {
throw new InvalidInputException(INVALID_UNICODE_ESCAPE);
}
// Unicode 4 detection
char low = (char) getNextChar();
if (low < LOW_SURROGATE_MIN_VALUE || low > LOW_SURROGATE_MAX_VALUE) {
// illegal low surrogate
throw new InvalidInputException(INVALID_LOW_SURROGATE);
}
isJavaIdStart = ScannerHelper.isJavaIdentifierStart(c, low);
}
else if (c >= LOW_SURROGATE_MIN_VALUE && c <= LOW_SURROGATE_MAX_VALUE) {
if (this.complianceLevel < ClassFileConstants.JDK1_5) {
throw new InvalidInputException(INVALID_UNICODE_ESCAPE);
}
throw new InvalidInputException(INVALID_HIGH_SURROGATE);
} else {
// optimized case already checked
isJavaIdStart = Character.isJavaIdentifierStart(c);
}
if (isJavaIdStart)
return scanIdentifierOrKeyword();
if (ScannerHelper.isDigit(this.currentCharacter)) {
return scanNumber(false);
}
return TokenNameERROR;
}
}
} //-----------------end switch while try--------------------
catch (IndexOutOfBoundsException e) {
if (this.tokenizeWhiteSpace && (whiteStart != this.currentPosition - 1)) {
// reposition scanner in case we are interested by spaces as tokens
this.currentPosition--;
this.startPosition = whiteStart;
return TokenNameWHITESPACE;
}
}
return TokenNameEOF;
}
public void getNextUnicodeChar()
throws InvalidInputException {
//VOID
//handle the case of unicode.
//when a unicode appears then we must use a buffer that holds char internal values
//At the end of this method currentCharacter holds the new visited char
//and currentPosition points right next after it
//ALL getNextChar.... ARE OPTIMIZED COPIES
int c1 = 0, c2 = 0, c3 = 0, c4 = 0, unicodeSize = 6;
this.currentPosition++;
if (this.currentPosition < this.eofPosition) {
while (this.source[this.currentPosition] == 'u') {
this.currentPosition++;
if (this.currentPosition >= this.eofPosition) {
this.currentPosition--;
throw new InvalidInputException(INVALID_UNICODE_ESCAPE);
}
unicodeSize++;
}
} else {
this.currentPosition--;
throw new InvalidInputException(INVALID_UNICODE_ESCAPE);
}
if ((this.currentPosition + 4) > this.eofPosition) {
this.currentPosition += (this.eofPosition - this.currentPosition);
throw new InvalidInputException(INVALID_UNICODE_ESCAPE);
}
if ((c1 = ScannerHelper.getNumericValue(this.source[this.currentPosition++])) > 15
|| c1 < 0
|| (c2 = ScannerHelper.getNumericValue(this.source[this.currentPosition++])) > 15
|| c2 < 0
|| (c3 = ScannerHelper.getNumericValue(this.source[this.currentPosition++])) > 15
|| c3 < 0
|| (c4 = ScannerHelper.getNumericValue(this.source[this.currentPosition++])) > 15
|| c4 < 0){
throw new InvalidInputException(INVALID_UNICODE_ESCAPE);
}
this.currentCharacter = (char) (((c1 * 16 + c2) * 16 + c3) * 16 + c4);
//need the unicode buffer
if (this.withoutUnicodePtr == 0) {
//buffer all the entries that have been left aside....
unicodeInitializeBuffer(this.currentPosition - unicodeSize - this.startPosition);
}
//fill the buffer with the char
unicodeStore();
this.unicodeAsBackSlash = this.currentCharacter == '\\';
}
public NLSTag[] getNLSTags() {
final int length = this.nlsTagsPtr;
if (length != 0) {
NLSTag[] result = new NLSTag[length];
System.arraycopy(this.nlsTags, 0, result, 0, length);
this.nlsTagsPtr = 0;
return result;
}
return null;
}
public char[] getSource(){
return this.source;
}
protected boolean isFirstTag() {
return true;
}
public final void jumpOverMethodBody() {
this.wasAcr = false;
int found = 1;
try {
while (true) { //loop for jumping over comments
this.withoutUnicodePtr = 0;
// ---------Consume white space and handles startPosition---------
boolean isWhiteSpace;
do {
this.startPosition = this.currentPosition;
if (((this.currentCharacter = this.source[this.currentPosition++]) == '\\')
&& (this.source[this.currentPosition] == 'u')) {
isWhiteSpace = jumpOverUnicodeWhiteSpace();
} else {
if (this.recordLineSeparator
&& ((this.currentCharacter == '\r') || (this.currentCharacter == '\n'))) {
pushLineSeparator();
}
isWhiteSpace = CharOperation.isWhitespace(this.currentCharacter);
}
} while (isWhiteSpace);
// -------consume token until } is found---------
NextToken: switch (this.currentCharacter) {
case '{' :
found++;
break NextToken;
case '}' :
found--;
if (found == 0)
return;
break NextToken;
case '\'' :
{
boolean test;
test = getNextChar('\\');
if (test) {
try {
if (this.unicodeAsBackSlash) {
// consume next character
this.unicodeAsBackSlash = false;
if (((this.currentCharacter = this.source[this.currentPosition++]) == '\\') && (this.source[this.currentPosition] == 'u')) {
getNextUnicodeChar();
} else {
if (this.withoutUnicodePtr != 0) {
unicodeStore();
}
}
} else {
this.currentCharacter = this.source[this.currentPosition++];
}
scanEscapeCharacter();
} catch (InvalidInputException ex) {
// ignore
}
} else {
try { // consume next character
this.unicodeAsBackSlash = false;
if (((this.currentCharacter = this.source[this.currentPosition++]) == '\\')
&& (this.source[this.currentPosition] == 'u')) {
getNextUnicodeChar();
} else {
if (this.withoutUnicodePtr != 0) {
unicodeStore();
}
}
} catch (InvalidInputException ex) {
// ignore
}
}
getNextChar('\'');
break NextToken;
}
case '"' :
try {
try { // consume next character
this.unicodeAsBackSlash = false;
if (((this.currentCharacter = this.source[this.currentPosition++]) == '\\')
&& (this.source[this.currentPosition] == 'u')) {
getNextUnicodeChar();
} else {
if (this.withoutUnicodePtr != 0) {
unicodeStore();
}
}
} catch (InvalidInputException ex) {
// ignore
}
while (this.currentCharacter != '"') {
if (this.currentPosition >= this.eofPosition) {
return;
}
if (this.currentCharacter == '\r'){
if (this.source[this.currentPosition] == '\n') this.currentPosition++;
break NextToken; // the string cannot go further that the line
}
if (this.currentCharacter == '\n'){
break; // the string cannot go further that the line
}
if (this.currentCharacter == '\\') {
try {
if (this.unicodeAsBackSlash) {
// consume next character
this.unicodeAsBackSlash = false;
if (((this.currentCharacter = this.source[this.currentPosition++]) == '\\') && (this.source[this.currentPosition] == 'u')) {
getNextUnicodeChar();
} else {
if (this.withoutUnicodePtr != 0) {
unicodeStore();
}
}
} else {
this.currentCharacter = this.source[this.currentPosition++];
}
scanEscapeCharacter();
} catch (InvalidInputException ex) {
// ignore
}
}
try { // consume next character
this.unicodeAsBackSlash = false;
if (((this.currentCharacter = this.source[this.currentPosition++]) == '\\')
&& (this.source[this.currentPosition] == 'u')) {
getNextUnicodeChar();
} else {
if (this.withoutUnicodePtr != 0) {
unicodeStore();
}
}
} catch (InvalidInputException ex) {
// ignore
}
}
} catch (IndexOutOfBoundsException e) {
return;
}
break NextToken;
case '/' :
{
int test;
if ((test = getNextChar('/', '*')) == 0) { //line comment
try {
this.lastCommentLinePosition = this.currentPosition;
//get the next char
if (((this.currentCharacter = this.source[this.currentPosition++]) == '\\')
&& (this.source[this.currentPosition] == 'u')) {
getNextUnicodeChar();
}
//handle the \\u case manually into comment
if (this.currentCharacter == '\\') {
if (this.source[this.currentPosition] == '\\')
this.currentPosition++;
} //jump over the \\
boolean isUnicode = false;
while (this.currentCharacter != '\r' && this.currentCharacter != '\n') {
if (this.currentPosition >= this.eofPosition) {
this.lastCommentLinePosition = this.currentPosition;
this.currentPosition ++;
// this avoids duplicating the code inside the catch(IndexOutOfBoundsException e) below
throw new IndexOutOfBoundsException();
}
this.lastCommentLinePosition = this.currentPosition;
//get the next char
isUnicode = false;
if (((this.currentCharacter = this.source[this.currentPosition++]) == '\\')
&& (this.source[this.currentPosition] == 'u')) {
isUnicode = true;
getNextUnicodeChar();
}
//handle the \\u case manually into comment
if (this.currentCharacter == '\\') {
if (this.source[this.currentPosition] == '\\')
this.currentPosition++;
} //jump over the \\
}
/*
* We need to completely consume the line break
*/
if (this.currentCharacter == '\r'
&& this.eofPosition > this.currentPosition) {
if (this.source[this.currentPosition] == '\n') {
this.currentPosition++;
this.currentCharacter = '\n';
} else if ((this.source[this.currentPosition] == '\\')
&& (this.source[this.currentPosition + 1] == 'u')) {
isUnicode = true;
getNextUnicodeChar();
}
}
recordComment(TokenNameCOMMENT_LINE);
if (this.recordLineSeparator
&& ((this.currentCharacter == '\r') || (this.currentCharacter == '\n'))) {
if (this.checkNonExternalizedStringLiterals &&
this.lastPosition < this.currentPosition) {
parseTags();
}
if (this.recordLineSeparator) {
if (isUnicode) {
pushUnicodeLineSeparator();
} else {
pushLineSeparator();
}
}
}
} catch (IndexOutOfBoundsException e) {
//an eof will then be generated
this.currentPosition--;
recordComment(TokenNameCOMMENT_LINE);
if (this.checkNonExternalizedStringLiterals &&
this.lastPosition < this.currentPosition) {
parseTags();
}
if (!this.tokenizeComments) {
this.currentPosition++;
}
}
break NextToken;
}
if (test > 0) { //traditional and javadoc comment
boolean isJavadoc = false;
try { //get the next char
boolean star = false;
int previous;
boolean isUnicode = false;
// consume next character
this.unicodeAsBackSlash = false;
if (((this.currentCharacter = this.source[this.currentPosition++]) == '\\')
&& (this.source[this.currentPosition] == 'u')) {
getNextUnicodeChar();
isUnicode = true;
} else {
isUnicode = false;
if (this.withoutUnicodePtr != 0) {
unicodeStore();
}
}
if (this.currentCharacter == '*') {
isJavadoc = true;
star = true;
}
if ((this.currentCharacter == '\r') || (this.currentCharacter == '\n')) {
if (this.recordLineSeparator) {
if (isUnicode) {
pushUnicodeLineSeparator();
} else {
pushLineSeparator();
}
}
}
isUnicode = false;
previous = this.currentPosition;
if (((this.currentCharacter = this.source[this.currentPosition++]) == '\\')
&& (this.source[this.currentPosition] == 'u')) {
getNextUnicodeChar();
isUnicode = true;
} else {
isUnicode = false;
}
//handle the \\u case manually into comment
if (this.currentCharacter == '\\') {
if (this.source[this.currentPosition] == '\\')
this.currentPosition++; //jump over the \\
}
// empty comment is not a javadoc /**/
if (this.currentCharacter == '/') {
isJavadoc = false;
}
//loop until end of comment */
int firstTag = 0;
while ((this.currentCharacter != '/') || (!star)) {
if (this.currentPosition >= this.eofPosition) {
return;
}
if ((this.currentCharacter == '\r') || (this.currentCharacter == '\n')) {
if (this.recordLineSeparator) {
if (isUnicode) {
pushUnicodeLineSeparator();
} else {
pushLineSeparator();
}
}
}
switch (this.currentCharacter) {
case '*':
star = true;
break;
case '@':
if (firstTag == 0 && this.isFirstTag()) {
firstTag = previous;
}
//$FALL-THROUGH$ default case to set star to false
default:
star = false;
}
//get next char
previous = this.currentPosition;
if (((this.currentCharacter = this.source[this.currentPosition++]) == '\\')
&& (this.source[this.currentPosition] == 'u')) {
getNextUnicodeChar();
isUnicode = true;
} else {
isUnicode = false;
}
//handle the \\u case manually into comment
if (this.currentCharacter == '\\') {
if (this.source[this.currentPosition] == '\\')
this.currentPosition++;
} //jump over the \\
}
recordComment(isJavadoc ? TokenNameCOMMENT_JAVADOC : TokenNameCOMMENT_BLOCK);
this.commentTagStarts[this.commentPtr] = firstTag;
} catch (IndexOutOfBoundsException e) {
return;
}
break NextToken;
}
break NextToken;
}
default :
try {
char c = this.currentCharacter;
if (c < ScannerHelper.MAX_OBVIOUS) {
if ((ScannerHelper.OBVIOUS_IDENT_CHAR_NATURES[c] & ScannerHelper.C_IDENT_START) != 0) {
scanIdentifierOrKeyword();
break NextToken;
} else if ((ScannerHelper.OBVIOUS_IDENT_CHAR_NATURES[c] & ScannerHelper.C_DIGIT) != 0) {
scanNumber(false);
break NextToken;
} else {
break NextToken;
}
}
boolean isJavaIdStart;
if (c >= HIGH_SURROGATE_MIN_VALUE && c <= HIGH_SURROGATE_MAX_VALUE) {
if (this.complianceLevel < ClassFileConstants.JDK1_5) {
throw new InvalidInputException(INVALID_UNICODE_ESCAPE);
}
// Unicode 4 detection
char low = (char) getNextChar();
if (low < LOW_SURROGATE_MIN_VALUE || low > LOW_SURROGATE_MAX_VALUE) {
// illegal low surrogate
break NextToken;
}
isJavaIdStart = ScannerHelper.isJavaIdentifierStart(c, low);
} else if (c >= LOW_SURROGATE_MIN_VALUE && c <= LOW_SURROGATE_MAX_VALUE) {
break NextToken;
} else {
// optimized case already checked
isJavaIdStart = Character.isJavaIdentifierStart(c);
}
if (isJavaIdStart) {
scanIdentifierOrKeyword();
break NextToken;
}
// if (ScannerHelper.isDigit(this.currentCharacter)) {
// scanNumber(false);
// break NextToken;
// }
} catch (InvalidInputException ex) {
// ignore
}
}
}
//-----------------end switch while try--------------------
} catch (IndexOutOfBoundsException e) {
// ignore
} catch (InvalidInputException e) {
// ignore
}
return;
}
public final boolean jumpOverUnicodeWhiteSpace() throws InvalidInputException {
//BOOLEAN
//handle the case of unicode. Jump over the next whiteSpace
//making startPosition pointing on the next available char
//On false, the currentCharacter is filled up with a potential
//correct char
this.wasAcr = false;
getNextUnicodeChar();
return CharOperation.isWhitespace(this.currentCharacter);
}
final char[] optimizedCurrentTokenSource1() {
//return always the same char[] build only once
//optimization at no speed cost of 99.5 % of the singleCharIdentifier
char charOne = this.source[this.startPosition];
switch (charOne) {
case 'a' :
return charArray_a;
case 'b' :
return charArray_b;
case 'c' :
return charArray_c;
case 'd' :
return charArray_d;
case 'e' :
return charArray_e;
case 'f' :
return charArray_f;
case 'g' :
return charArray_g;
case 'h' :
return charArray_h;
case 'i' :
return charArray_i;
case 'j' :
return charArray_j;
case 'k' :
return charArray_k;
case 'l' :
return charArray_l;
case 'm' :
return charArray_m;
case 'n' :
return charArray_n;
case 'o' :
return charArray_o;
case 'p' :
return charArray_p;
case 'q' :
return charArray_q;
case 'r' :
return charArray_r;
case 's' :
return charArray_s;
case 't' :
return charArray_t;
case 'u' :
return charArray_u;
case 'v' :
return charArray_v;
case 'w' :
return charArray_w;
case 'x' :
return charArray_x;
case 'y' :
return charArray_y;
case 'z' :
return charArray_z;
default :
return new char[] {charOne};
}
}
final char[] optimizedCurrentTokenSource2() {
//try to return the same char[] build only once
char[] src = this.source;
int start = this.startPosition;
char c0 , c1;
int hash = (((c0=src[start]) << 6) + (c1=src[start+1])) % TableSize;
char[][] table = this.charArray_length[0][hash];
int i = this.newEntry2;
while (++i < InternalTableSize) {
char[] charArray = table[i];
if ((c0 == charArray[0]) && (c1 == charArray[1]))
return charArray;
}
//---------other side---------
i = -1;
int max = this.newEntry2;
while (++i <= max) {
char[] charArray = table[i];
if ((c0 == charArray[0]) && (c1 == charArray[1]))
return charArray;
}
//--------add the entry-------
if (++max >= InternalTableSize) max = 0;
char[] r;
System.arraycopy(src, start, r= new char[2], 0, 2);
//newIdentCount++;
return table[this.newEntry2 = max] = r; //(r = new char[] {c0, c1});
}
final char[] optimizedCurrentTokenSource3() {
//try to return the same char[] build only once
char[] src = this.source;
int start = this.startPosition;
char c0, c1=src[start+1], c2;
int hash = (((c0=src[start])<< 6) + (c2=src[start+2])) % TableSize;
// int hash = ((c0 << 12) + (c1<< 6) + c2) % TableSize;
char[][] table = this.charArray_length[1][hash];
int i = this.newEntry3;
while (++i < InternalTableSize) {
char[] charArray = table[i];
if ((c0 == charArray[0]) && (c1 == charArray[1]) && (c2 == charArray[2]))
return charArray;
}
//---------other side---------
i = -1;
int max = this.newEntry3;
while (++i <= max) {
char[] charArray = table[i];
if ((c0 == charArray[0]) && (c1 == charArray[1]) && (c2 == charArray[2]))
return charArray;
}
//--------add the entry-------
if (++max >= InternalTableSize) max = 0;
char[] r;
System.arraycopy(src, start, r= new char[3], 0, 3);
//newIdentCount++;
return table[this.newEntry3 = max] = r; //(r = new char[] {c0, c1, c2});
}
final char[] optimizedCurrentTokenSource4() {
//try to return the same char[] build only once
char[] src = this.source;
int start = this.startPosition;
char c0, c1 = src[start+1], c2, c3 = src[start+3];
int hash = (((c0=src[start]) << 6) + (c2=src[start+2])) % TableSize;
// int hash = (int) (((((long) c0) << 18) + (c1 << 12) + (c2 << 6) + c3) % TableSize);
char[][] table = this.charArray_length[2][hash];
int i = this.newEntry4;
while (++i < InternalTableSize) {
char[] charArray = table[i];
if ((c0 == charArray[0])
&& (c1 == charArray[1])
&& (c2 == charArray[2])
&& (c3 == charArray[3]))
return charArray;
}
//---------other side---------
i = -1;
int max = this.newEntry4;
while (++i <= max) {
char[] charArray = table[i];
if ((c0 == charArray[0])
&& (c1 == charArray[1])
&& (c2 == charArray[2])
&& (c3 == charArray[3]))
return charArray;
}
//--------add the entry-------
if (++max >= InternalTableSize) max = 0;
char[] r;
System.arraycopy(src, start, r= new char[4], 0, 4);
//newIdentCount++;
return table[this.newEntry4 = max] = r; //(r = new char[] {c0, c1, c2, c3});
}
final char[] optimizedCurrentTokenSource5() {
//try to return the same char[] build only once
char[] src = this.source;
int start = this.startPosition;
char c0, c1 = src[start+1], c2, c3 = src[start+3], c4;
int hash = (((c0=src[start]) << 12) +((c2=src[start+2]) << 6) + (c4=src[start+4])) % TableSize;
// int hash = (int) (((((long) c0) << 24) + (((long) c1) << 18) + (c2 << 12) + (c3 << 6) + c4) % TableSize);
char[][] table = this.charArray_length[3][hash];
int i = this.newEntry5;
while (++i < InternalTableSize) {
char[] charArray = table[i];
if ((c0 == charArray[0])
&& (c1 == charArray[1])
&& (c2 == charArray[2])
&& (c3 == charArray[3])
&& (c4 == charArray[4]))
return charArray;
}
//---------other side---------
i = -1;
int max = this.newEntry5;
while (++i <= max) {
char[] charArray = table[i];
if ((c0 == charArray[0])
&& (c1 == charArray[1])
&& (c2 == charArray[2])
&& (c3 == charArray[3])
&& (c4 == charArray[4]))
return charArray;
}
//--------add the entry-------
if (++max >= InternalTableSize) max = 0;
char[] r;
System.arraycopy(src, start, r= new char[5], 0, 5);
//newIdentCount++;
return table[this.newEntry5 = max] = r; //(r = new char[] {c0, c1, c2, c3, c4});
}
final char[] optimizedCurrentTokenSource6() {
//try to return the same char[] build only once
char[] src = this.source;
int start = this.startPosition;
char c0, c1 = src[start+1], c2, c3 = src[start+3], c4, c5 = src[start+5];
int hash = (((c0=src[start]) << 12) +((c2=src[start+2]) << 6) + (c4=src[start+4])) % TableSize;
// int hash = (int)(((((long) c0) << 32) + (((long) c1) << 24) + (((long) c2) << 18) + (c3 << 12) + (c4 << 6) + c5) % TableSize);
char[][] table = this.charArray_length[4][hash];
int i = this.newEntry6;
while (++i < InternalTableSize) {
char[] charArray = table[i];
if ((c0 == charArray[0])
&& (c1 == charArray[1])
&& (c2 == charArray[2])
&& (c3 == charArray[3])
&& (c4 == charArray[4])
&& (c5 == charArray[5]))
return charArray;
}
//---------other side---------
i = -1;
int max = this.newEntry6;
while (++i <= max) {
char[] charArray = table[i];
if ((c0 == charArray[0])
&& (c1 == charArray[1])
&& (c2 == charArray[2])
&& (c3 == charArray[3])
&& (c4 == charArray[4])
&& (c5 == charArray[5]))
return charArray;
}
//--------add the entry-------
if (++max >= InternalTableSize) max = 0;
char[] r;
System.arraycopy(src, start, r= new char[6], 0, 6);
//newIdentCount++;
return table[this.newEntry6 = max] = r; //(r = new char[] {c0, c1, c2, c3, c4, c5});
}
private void parseTags() {
int position = 0;
final int currentStartPosition = this.startPosition;
final int currentLinePtr = this.linePtr;
if (currentLinePtr >= 0) {
position = this.lineEnds[currentLinePtr] + 1;
}
while (ScannerHelper.isWhitespace(this.source[position])) {
position++;
}
if (currentStartPosition == position) {
// the whole line is commented out
return;
}
char[] s = null;
int sourceEnd = this.currentPosition;
int sourceStart = currentStartPosition;
int sourceDelta = 0;
if (this.withoutUnicodePtr != 0) {
// 0 is used as a fast test flag so the real first char is in position 1
System.arraycopy(
this.withoutUnicodeBuffer,
1,
s = new char[this.withoutUnicodePtr],
0,
this.withoutUnicodePtr);
sourceEnd = this.withoutUnicodePtr;
sourceStart = 1;
sourceDelta = currentStartPosition;
} else {
s = this.source;
}
int pos = CharOperation.indexOf(TAG_PREFIX, s, true, sourceStart, sourceEnd);
if (pos != -1) {
if (this.nlsTags == null) {
this.nlsTags = new NLSTag[10];
this.nlsTagsPtr = 0;
}
while (pos != -1) {
int start = pos + TAG_PREFIX_LENGTH;
int end = CharOperation.indexOf(TAG_POSTFIX, s, start, sourceEnd);
if (end != -1) {
NLSTag currentTag = null;
final int currentLine = currentLinePtr + 1;
try {
currentTag = new NLSTag(pos + sourceDelta, end + sourceDelta, currentLine, extractInt(s, start, end));
} catch (NumberFormatException e) {
currentTag = new NLSTag(pos + sourceDelta, end + sourceDelta, currentLine, -1);
}
if (this.nlsTagsPtr == this.nlsTags.length) {
// resize
System.arraycopy(this.nlsTags, 0, (this.nlsTags = new NLSTag[this.nlsTagsPtr + 10]), 0, this.nlsTagsPtr);
}
this.nlsTags[this.nlsTagsPtr++] = currentTag;
} else {
end = start;
}
pos = CharOperation.indexOf(TAG_PREFIX, s, true, end, sourceEnd);
}
}
}
private int extractInt(char[] array, int start, int end) {
int value = 0;
for (int i = start; i < end; i++) {
final char currentChar = array[i];
int digit = 0;
switch(currentChar) {
case '0' :
digit = 0;
break;
case '1' :
digit = 1;
break;
case '2' :
digit = 2;
break;
case '3' :
digit = 3;
break;
case '4' :
digit = 4;
break;
case '5' :
digit = 5;
break;
case '6' :
digit = 6;
break;
case '7' :
digit = 7;
break;
case '8' :
digit = 8;
break;
case '9' :
digit = 9;
break;
default :
throw new NumberFormatException();
}
value *= 10;
if (digit < 0) throw new NumberFormatException();
value += digit;
}
return value;
}
public final void pushLineSeparator() {
//see comment on isLineDelimiter(char) for the use of '\n' and '\r'
final int INCREMENT = 250;
//currentCharacter is at position currentPosition-1
// cr 000D
if (this.currentCharacter == '\r') {
int separatorPos = this.currentPosition - 1;
if ((this.linePtr >= 0) && (this.lineEnds[this.linePtr] >= separatorPos)) return;
int length = this.lineEnds.length;
if (++this.linePtr >= length)
System.arraycopy(this.lineEnds, 0, this.lineEnds = new int[length + INCREMENT], 0, length);
this.lineEnds[this.linePtr] = separatorPos;
// look-ahead for merged cr+lf
try {
if (this.source[this.currentPosition] == '\n') {
//System.out.println("look-ahead LF-" + this.currentPosition);
this.lineEnds[this.linePtr] = this.currentPosition;
this.currentPosition++;
this.wasAcr = false;
} else {
this.wasAcr = true;
}
} catch(IndexOutOfBoundsException e) {
this.wasAcr = true;
}
} else {
// lf 000A
if (this.currentCharacter == '\n') { //must merge eventual cr followed by lf
if (this.wasAcr && (this.lineEnds[this.linePtr] == (this.currentPosition - 2))) {
//System.out.println("merge LF-" + (this.currentPosition - 1));
this.lineEnds[this.linePtr] = this.currentPosition - 1;
} else {
int separatorPos = this.currentPosition - 1;
if ((this.linePtr >= 0) && (this.lineEnds[this.linePtr] >= separatorPos)) return;
int length = this.lineEnds.length;
if (++this.linePtr >= length)
System.arraycopy(this.lineEnds, 0, this.lineEnds = new int[length + INCREMENT], 0, length);
this.lineEnds[this.linePtr] = separatorPos;
}
this.wasAcr = false;
}
}
}
public final void pushUnicodeLineSeparator() {
// cr 000D
if (this.currentCharacter == '\r') {
if (this.source[this.currentPosition] == '\n') {
this.wasAcr = false;
} else {
this.wasAcr = true;
}
} else {
// lf 000A
if (this.currentCharacter == '\n') { //must merge eventual cr followed by lf
this.wasAcr = false;
}
}
}
public void recordComment(int token) {
// compute position
int commentStart = this.startPosition;
int stopPosition = this.currentPosition;
switch (token) {
case TokenNameCOMMENT_LINE:
// both positions are negative
commentStart = -this.startPosition;
stopPosition = -this.lastCommentLinePosition;
break;
case TokenNameCOMMENT_BLOCK:
// only end position is negative
stopPosition = -this.currentPosition;
break;
}
// a new comment is recorded
int length = this.commentStops.length;
if (++this.commentPtr >= length) {
int newLength = length + COMMENT_ARRAYS_SIZE*10;
System.arraycopy(this.commentStops, 0, this.commentStops = new int[newLength], 0, length);
System.arraycopy(this.commentStarts, 0, this.commentStarts = new int[newLength], 0, length);
System.arraycopy(this.commentTagStarts, 0, this.commentTagStarts = new int[newLength], 0, length);
}
this.commentStops[this.commentPtr] = stopPosition;
this.commentStarts[this.commentPtr] = commentStart;
}
/**
* Reposition the scanner on some portion of the original source. The given endPosition is the last valid position.
* Beyond this position, the scanner will answer EOF tokens (<code>ITerminalSymbols.TokenNameEOF</code>).
*
* @param begin the given start position
* @param end the given end position
*/
public void resetTo(int begin, int end) {
//reset the scanner to a given position where it may rescan again
this.diet = false;
this.initialPosition = this.startPosition = this.currentPosition = begin;
if (this.source != null && this.source.length < end) {
this.eofPosition = this.source.length;
} else {
this.eofPosition = end < Integer.MAX_VALUE ? end + 1 : end;
}
this.commentPtr = -1; // reset comment stack
this.foundTaskCount = 0;
}
public final void scanEscapeCharacter() throws InvalidInputException {
// the string with "\\u" is a legal string of two chars \ and u
//thus we use a direct access to the source (for regular cases).
switch (this.currentCharacter) {
case 'b' :
this.currentCharacter = '\b';
break;
case 't' :
this.currentCharacter = '\t';
break;
case 'n' :
this.currentCharacter = '\n';
break;
case 'f' :
this.currentCharacter = '\f';
break;
case 'r' :
this.currentCharacter = '\r';
break;
case '\"' :
this.currentCharacter = '\"';
break;
case '\'' :
this.currentCharacter = '\'';
break;
case '\\' :
this.currentCharacter = '\\';
break;
default :
// -----------octal escape--------------
// OctalDigit
// OctalDigit OctalDigit
// ZeroToThree OctalDigit OctalDigit
int number = ScannerHelper.getNumericValue(this.currentCharacter);
if (number >= 0 && number <= 7) {
boolean zeroToThreeNot = number > 3;
if (ScannerHelper.isDigit(this.currentCharacter = this.source[this.currentPosition++])) {
int digit = ScannerHelper.getNumericValue(this.currentCharacter);
if (digit >= 0 && digit <= 7) {
number = (number * 8) + digit;
if (ScannerHelper.isDigit(this.currentCharacter = this.source[this.currentPosition++])) {
if (zeroToThreeNot) {// has read \NotZeroToThree OctalDigit Digit --> ignore last character
this.currentPosition--;
} else {
digit = ScannerHelper.getNumericValue(this.currentCharacter);
if (digit >= 0 && digit <= 7){ // has read \ZeroToThree OctalDigit OctalDigit
number = (number * 8) + digit;
} else {// has read \ZeroToThree OctalDigit NonOctalDigit --> ignore last character
this.currentPosition--;
}
}
} else { // has read \OctalDigit NonDigit--> ignore last character
this.currentPosition--;
}
} else { // has read \OctalDigit NonOctalDigit--> ignore last character
this.currentPosition--;
}
} else { // has read \OctalDigit --> ignore last character
this.currentPosition--;
}
if (number > 255)
throw new InvalidInputException(INVALID_ESCAPE);
this.currentCharacter = (char) number;
} else
throw new InvalidInputException(INVALID_ESCAPE);
}
}
//{ObjectTeams: added to retrieve OT-specific special identifiers (after, before, replace)
/*
* If the Identifier is an SpecialIdentifier it will return the appropriate symbol from TerminalTokens.
* @param data[] Identifier String
* @return The int-type of an Special Identifier or TokenNameERROR
*/
public int getCallinModifierToken(char[] data) {
// replace after before
int length=data.length;
int index=0;
char firstLetter = data[index];
switch (firstLetter) {
case 'a' :
switch(length) {
case 5: //after
if ((data[++index] == 'f')
&& (data[++index] == 't')
&& (data[++index] == 'e')
&& (data[++index] == 'r'))
return TokenNameafter;
}
break;
case 'b' :
switch (length) {
case 6:// before
if ((data[++index] == 'e')
&& (data[++index] == 'f')
&& (data[++index] == 'o')
&& (data[++index] == 'r')
&& (data[++index] == 'e'))
return TokenNamebefore;
}
break;
case 'r' :
switch (length) {
case 7: //replace
if ((data[++index] == 'e')
&& (data[++index] == 'p')
&& (data[++index] == 'l')
&& (data[++index] == 'a')
&& (data[++index] == 'c')
&& (data[++index] == 'e'))
return TokenNamereplace;
}
}
return TokenNameERROR;
}
// Markus Witte}
public int scanIdentifierOrKeywordWithBoundCheck() {
//test keywords
//first dispatch on the first char.
//then the length. If there are several
//keywors with the same length AND the same first char, then do another
//dispatch on the second char
this.useAssertAsAnIndentifier = false;
this.useEnumAsAnIndentifier = false;
char[] src = this.source;
identLoop: {
int pos;
int srcLength = this.eofPosition;
while (true) {
if ((pos = this.currentPosition) >= srcLength) // handle the obvious case upfront
break identLoop;
char c = src[pos];
if (c < ScannerHelper.MAX_OBVIOUS) {
if ((ScannerHelper.OBVIOUS_IDENT_CHAR_NATURES[c] &
(ScannerHelper.C_UPPER_LETTER | ScannerHelper.C_LOWER_LETTER | ScannerHelper.C_IDENT_PART | ScannerHelper.C_DIGIT)) != 0) {
if (this.withoutUnicodePtr != 0) {
this.currentCharacter = c;
unicodeStore();
}
this.currentPosition++;
} else if ((ScannerHelper.OBVIOUS_IDENT_CHAR_NATURES[c] & (ScannerHelper.C_SEPARATOR | ScannerHelper.C_JLS_SPACE)) != 0) {
this.currentCharacter = c;
break identLoop;
} else {
//System.out.println("slow<=128: "+ c);
while (getNextCharAsJavaIdentifierPartWithBoundCheck()){/*empty*/}
break identLoop;
}
} else {
//System.out.println("slow>>128: "+ c);
while (getNextCharAsJavaIdentifierPartWithBoundCheck()){/*empty*/}
break identLoop;
}
}
}
int index, length;
char[] data;
if (this.withoutUnicodePtr == 0) {
//quick test on length == 1 but not on length > 12 while most identifier
//have a length which is <= 12...but there are lots of identifier with
//only one char....
if ((length = this.currentPosition - this.startPosition) == 1) {
return TokenNameIdentifier;
}
data = this.source;
index = this.startPosition;
} else {
if ((length = this.withoutUnicodePtr) == 1)
return TokenNameIdentifier;
data = this.withoutUnicodeBuffer;
index = 1;
}
return internalScanIdentifierOrKeyword(index, length, data);
}
public int scanIdentifierOrKeyword() {
//test keywords
//first dispatch on the first char.
//then the length. If there are several
//keywors with the same length AND the same first char, then do another
//dispatch on the second char
this.useAssertAsAnIndentifier = false;
this.useEnumAsAnIndentifier = false;
char[] src = this.source;
identLoop: {
int pos;
int srcLength = this.eofPosition;
while (true) {
if ((pos = this.currentPosition) >= srcLength) // handle the obvious case upfront
break identLoop;
char c = src[pos];
if (c < ScannerHelper.MAX_OBVIOUS) {
if ((ScannerHelper.OBVIOUS_IDENT_CHAR_NATURES[c] &
(ScannerHelper.C_UPPER_LETTER | ScannerHelper.C_LOWER_LETTER | ScannerHelper.C_IDENT_PART | ScannerHelper.C_DIGIT)) != 0) {
if (this.withoutUnicodePtr != 0) {
this.currentCharacter = c;
unicodeStore();
}
this.currentPosition++;
} else if ((ScannerHelper.OBVIOUS_IDENT_CHAR_NATURES[c] & (ScannerHelper.C_SEPARATOR | ScannerHelper.C_JLS_SPACE)) != 0) {
this.currentCharacter = c;
break identLoop;
} else {
//System.out.println("slow<=128: "+ c);
while (getNextCharAsJavaIdentifierPart()){/*empty*/}
break identLoop;
}
} else {
//System.out.println("slow>>128: "+ c);
while (getNextCharAsJavaIdentifierPart()){/*empty*/}
break identLoop;
}
}
}
int index, length;
char[] data;
if (this.withoutUnicodePtr == 0) {
//quick test on length == 1 but not on length > 12 while most identifier
//have a length which is <= 12...but there are lots of identifier with
//only one char....
if ((length = this.currentPosition - this.startPosition) == 1) {
return TokenNameIdentifier;
}
data = this.source;
index = this.startPosition;
} else {
if ((length = this.withoutUnicodePtr) == 1)
return TokenNameIdentifier;
data = this.withoutUnicodeBuffer;
index = 1;
}
return internalScanIdentifierOrKeyword(index, length, data);
}
private int internalScanIdentifierOrKeyword(int index, int length, char[] data) {
//{ObjectTeams: callin/calloutSeen/atStartOfImport/precedenceSeen has effect only once:
boolean calloutSeen = this._calloutSeen;
this._calloutSeen = false;
boolean callinSeen = this._callinSeen;
this._callinSeen = false;
boolean precedenceSeen = this._precedenceSeen;
this._precedenceSeen = false;
boolean atStartOfImport = this._atStartOfImport;
this._atStartOfImport = false;
// SH}
switch (data[index]) {
case 'a' :
switch(length) {
//{ObjectTeams: keyword 'as':
case 2: //as
if ( this._isOTSource
&& (data[++index] == 's')) {
return TokenNameas;
} else {
return TokenNameIdentifier;
}
// MW}
case 8: //abstract
if ((data[++index] == 'b')
&& (data[++index] == 's')
&& (data[++index] == 't')
&& (data[++index] == 'r')
&& (data[++index] == 'a')
&& (data[++index] == 'c')
&& (data[++index] == 't')) {
return TokenNameabstract;
} else {
return TokenNameIdentifier;
}
//{ObjectTeams: 'after' (only if after "<-" or "precedence"):
case 5:
if (callinSeen || precedenceSeen) {
if ( (data[++index] == 'f')
&& (data[++index] == 't')
&& (data[++index] == 'e')
&& (data[++index] == 'r'))
return TokenNameafter;
}
return TokenNameIdentifier;
// SH}
case 6: // assert
if ((data[++index] == 's')
&& (data[++index] == 's')
&& (data[++index] == 'e')
&& (data[++index] == 'r')
&& (data[++index] == 't')) {
if (this.sourceLevel >= ClassFileConstants.JDK1_4) {
this.containsAssertKeyword = true;
return TokenNameassert;
} else {
this.useAssertAsAnIndentifier = true;
return TokenNameIdentifier;
}
} else {
return TokenNameIdentifier;
}
default:
return TokenNameIdentifier;
}
case 'b' : //boolean break byte (before)
switch (length) {
case 4 :
if ((data[++index] == 'y') && (data[++index] == 't') && (data[++index] == 'e'))
return TokenNamebyte;
else
//{ObjectTeams: check for base keyword
/*@original
return TokenNameIdentifier;
*/
{
if ( baseIsKeyword(atStartOfImport)
&& (data[index] == 'a')
&& (data[++index] == 's')
&& (data[++index] == 'e'))
return TokenNamebase;
else
return TokenNameIdentifier;
}
//Markus Witte}
case 5 :
if ((data[++index] == 'r')
&& (data[++index] == 'e')
&& (data[++index] == 'a')
&& (data[++index] == 'k'))
return TokenNamebreak;
else
return TokenNameIdentifier;
//{ObjectTeams: 'before' (only if after "<-"):
case 6:
if (callinSeen) {
if ( (data[++index] == 'e')
&& (data[++index] == 'f')
&& (data[++index] == 'o')
&& (data[++index] == 'r')
&& (data[++index] == 'e'))
return TokenNamebefore;
}
return TokenNameIdentifier;
// SH}
case 7 :
if ((data[++index] == 'o')
&& (data[++index] == 'o')
&& (data[++index] == 'l')
&& (data[++index] == 'e')
&& (data[++index] == 'a')
&& (data[++index] == 'n'))
return TokenNameboolean;
else
return TokenNameIdentifier;
default :
return TokenNameIdentifier;
}
case 'c' : //case char catch const class continue
switch (length) {
case 4 :
if (data[++index] == 'a')
if ((data[++index] == 's') && (data[++index] == 'e'))
return TokenNamecase;
else
return TokenNameIdentifier;
else
if ((data[index] == 'h') && (data[++index] == 'a') && (data[++index] == 'r'))
return TokenNamechar;
else
return TokenNameIdentifier;
case 5 :
if (data[++index] == 'a')
if ((data[++index] == 't') && (data[++index] == 'c') && (data[++index] == 'h'))
return TokenNamecatch;
else
return TokenNameIdentifier;
else
if (data[index] == 'l')
if ((data[++index] == 'a')
&& (data[++index] == 's')
&& (data[++index] == 's'))
//{ObjectTeams: advance scanner state:
{
if (this._teamKeywordSeen)
enterOTSource(); // either in team class or in ROFI class
// orig:
return TokenNameclass;
// :giro
}
// SH}
else
return TokenNameIdentifier;
else if ((data[index] == 'o')
&& (data[++index] == 'n')
&& (data[++index] == 's')
&& (data[++index] == 't'))
return TokenNameconst; //const is not used in java ???????
else
return TokenNameIdentifier;
//{ObjectTeams: check for callin keyword
case 6: //callin
if ( this._isOTSource
&& (data[++index] == 'a')
&& (data[++index] == 'l')
&& (data[++index] == 'l')
&& (data[++index] == 'i')
&& (data[++index] == 'n'))
return TokenNamecallin;
else
return TokenNameIdentifier;
//Markus Witte}
case 8 :
if ((data[++index] == 'o')
&& (data[++index] == 'n')
&& (data[++index] == 't')
&& (data[++index] == 'i')
&& (data[++index] == 'n')
&& (data[++index] == 'u')
&& (data[++index] == 'e'))
return TokenNamecontinue;
else
return TokenNameIdentifier;
default :
return TokenNameIdentifier;
}
case 'd' : //default do double
switch (length) {
case 2 :
if ((data[++index] == 'o'))
return TokenNamedo;
else
return TokenNameIdentifier;
case 6 :
if ((data[++index] == 'o')
&& (data[++index] == 'u')
&& (data[++index] == 'b')
&& (data[++index] == 'l')
&& (data[++index] == 'e'))
return TokenNamedouble;
else
return TokenNameIdentifier;
case 7 :
if ((data[++index] == 'e')
&& (data[++index] == 'f')
&& (data[++index] == 'a')
&& (data[++index] == 'u')
&& (data[++index] == 'l')
&& (data[++index] == 't'))
return TokenNamedefault;
else
return TokenNameIdentifier;
default :
return TokenNameIdentifier;
}
case 'e' : //else extends
switch (length) {
case 4 :
if (data[++index] == 'l') {
if ((data[++index] == 's') && (data[++index] == 'e')) {
return TokenNameelse;
} else {
return TokenNameIdentifier;
}
} else if ((data[index] == 'n')
&& (data[++index] == 'u')
&& (data[++index] == 'm')) {
if (this.sourceLevel >= ClassFileConstants.JDK1_5) {
return TokenNameenum;
} else {
this.useEnumAsAnIndentifier = true;
return TokenNameIdentifier;
}
}
return TokenNameIdentifier;
case 7 :
if ((data[++index] == 'x')
&& (data[++index] == 't')
&& (data[++index] == 'e')
&& (data[++index] == 'n')
&& (data[++index] == 'd')
&& (data[++index] == 's'))
return TokenNameextends;
else
return TokenNameIdentifier;
default :
return TokenNameIdentifier;
}
case 'f' : //final finally float for false
switch (length) {
case 3 :
if ((data[++index] == 'o') && (data[++index] == 'r'))
return TokenNamefor;
else
return TokenNameIdentifier;
case 5 :
if (data[++index] == 'i')
if ((data[++index] == 'n')
&& (data[++index] == 'a')
&& (data[++index] == 'l')) {
return TokenNamefinal;
} else
return TokenNameIdentifier;
else
if (data[index] == 'l')
if ((data[++index] == 'o')
&& (data[++index] == 'a')
&& (data[++index] == 't'))
return TokenNamefloat;
else
return TokenNameIdentifier;
else
if ((data[index] == 'a')
&& (data[++index] == 'l')
&& (data[++index] == 's')
&& (data[++index] == 'e'))
return TokenNamefalse;
else
return TokenNameIdentifier;
case 7 :
if ((data[++index] == 'i')
&& (data[++index] == 'n')
&& (data[++index] == 'a')
&& (data[++index] == 'l')
&& (data[++index] == 'l')
&& (data[++index] == 'y'))
return TokenNamefinally;
else
return TokenNameIdentifier;
default :
return TokenNameIdentifier;
}
case 'g' :
//{ObjectTeams: 'get':
if (length == 3 && calloutSeen) {
if ( (data[++index] == 'e')
&& (data[++index] == 't'))
return TokenNameget;
}
// SH}
//goto
if (length == 4) {
if ((data[++index] == 'o')
&& (data[++index] == 't')
&& (data[++index] == 'o')) {
return TokenNamegoto;
}
} //no goto in java are allowed, so why java removes this keyword ???
return TokenNameIdentifier;
case 'i' : //if implements import instanceof int interface
switch (length) {
case 2 :
if (data[++index] == 'f')
return TokenNameif;
else
return TokenNameIdentifier;
case 3 :
if ((data[++index] == 'n') && (data[++index] == 't'))
return TokenNameint;
else
return TokenNameIdentifier;
case 6 :
if ((data[++index] == 'm')
&& (data[++index] == 'p')
&& (data[++index] == 'o')
&& (data[++index] == 'r')
&& (data[++index] == 't'))
//{ObjectTeams: support 'base' as the very next word:
{
this._atStartOfImport = true;
// orig:
return TokenNameimport;
// :giro
}
// SH}
else
return TokenNameIdentifier;
case 9 :
if ((data[++index] == 'n')
&& (data[++index] == 't')
&& (data[++index] == 'e')
&& (data[++index] == 'r')
&& (data[++index] == 'f')
&& (data[++index] == 'a')
&& (data[++index] == 'c')
&& (data[++index] == 'e'))
//{ObjectTeams: advance scanner state:
{
if (this._teamKeywordSeen)
enterOTSource(); // in ROFI interface
// orig:
return TokenNameinterface;
// :giro
}
// SH}
else
return TokenNameIdentifier;
case 10 :
if (data[++index] == 'm')
if ((data[++index] == 'p')
&& (data[++index] == 'l')
&& (data[++index] == 'e')
&& (data[++index] == 'm')
&& (data[++index] == 'e')
&& (data[++index] == 'n')
&& (data[++index] == 't')
&& (data[++index] == 's'))
return TokenNameimplements;
else
return TokenNameIdentifier;
else
if ((data[index] == 'n')
&& (data[++index] == 's')
&& (data[++index] == 't')
&& (data[++index] == 'a')
&& (data[++index] == 'n')
&& (data[++index] == 'c')
&& (data[++index] == 'e')
&& (data[++index] == 'o')
&& (data[++index] == 'f'))
return TokenNameinstanceof;
else
return TokenNameIdentifier;
default :
return TokenNameIdentifier;
}
case 'l' : //long
if (length == 4) {
if ((data[++index] == 'o')
&& (data[++index] == 'n')
&& (data[++index] == 'g')) {
return TokenNamelong;
}
}
return TokenNameIdentifier;
case 'n' : //native new null
switch (length) {
case 3 :
if ((data[++index] == 'e') && (data[++index] == 'w'))
return TokenNamenew;
else
return TokenNameIdentifier;
case 4 :
if ((data[++index] == 'u') && (data[++index] == 'l') && (data[++index] == 'l'))
return TokenNamenull;
else
return TokenNameIdentifier;
case 6 :
if ((data[++index] == 'a')
&& (data[++index] == 't')
&& (data[++index] == 'i')
&& (data[++index] == 'v')
&& (data[++index] == 'e')) {
return TokenNamenative;
} else
return TokenNameIdentifier;
default :
return TokenNameIdentifier;
}
case 'p' : //package private protected public
switch (length) {
case 6 :
if ((data[++index] == 'u')
&& (data[++index] == 'b')
&& (data[++index] == 'l')
&& (data[++index] == 'i')
&& (data[++index] == 'c')) {
return TokenNamepublic;
} else
return TokenNameIdentifier;
case 7 :
if (data[++index] == 'a')
if ((data[++index] == 'c')
&& (data[++index] == 'k')
&& (data[++index] == 'a')
&& (data[++index] == 'g')
&& (data[++index] == 'e'))
return TokenNamepackage;
else
return TokenNameIdentifier;
else
if ((data[index] == 'r')
&& (data[++index] == 'i')
&& (data[++index] == 'v')
&& (data[++index] == 'a')
&& (data[++index] == 't')
&& (data[++index] == 'e')) {
return TokenNameprivate;
} else
return TokenNameIdentifier;
//{ObjectTeams: check for playedBy/precedence keywords
case 8 :
if ( this._isOTSource
&& (data[++index] == 'l')
&& (data[++index] == 'a')
&& (data[++index] == 'y')
&& (data[++index] == 'e')
&& (data[++index] == 'd')
&& (data[++index] == 'B')
&& (data[++index] == 'y')) {
return TokenNameplayedBy;
} else
return TokenNameIdentifier;
case 10 :
if ( this._isOTSource
&& (data[++index] == 'r')
&& (data[++index] == 'e')
&& (data[++index] == 'c')
&& (data[++index] == 'e')
&& (data[++index] == 'd')
&& (data[++index] == 'e')
&& (data[++index] == 'n')
&& (data[++index] == 'c')
&& (data[++index] == 'e')) {
this._precedenceSeen = true;
return TokenNameprecedence;
} else
return TokenNameIdentifier;
//Markus Witte/SH}
case 9 :
if ((data[++index] == 'r')
&& (data[++index] == 'o')
&& (data[++index] == 't')
&& (data[++index] == 'e')
&& (data[++index] == 'c')
&& (data[++index] == 't')
&& (data[++index] == 'e')
&& (data[++index] == 'd')) {
return TokenNameprotected;
} else
return TokenNameIdentifier;
default :
return TokenNameIdentifier;
}
case 'r' : //return
if (length == 6) {
if ((data[++index] == 'e')
&& (data[++index] == 't')
&& (data[++index] == 'u')
&& (data[++index] == 'r')
&& (data[++index] == 'n')) {
return TokenNamereturn;
}
}
//{ObjectTeams: 'replace' (only if after "<-"):
else if (length == 7 && callinSeen) {
if ( (data[++index] == 'e')
&& (data[++index] == 'p')
&& (data[++index] == 'l')
&& (data[++index] == 'a')
&& (data[++index] == 'c')
&& (data[++index] == 'e'))
return TokenNamereplace;
}
// SH}
//{ObjectTeams: 'readonly' (may appear in interfaces outside a team(?)
else if (length == 8) {
if ( this._isOTSource
&& (data[++index] == 'e')
&& (data[++index] == 'a')
&& (data[++index] == 'd')
&& (data[++index] == 'o')
&& (data[++index] == 'n')
&& (data[++index] == 'l')
&& (data[++index] == 'y')) {
return TokenNamereadonly;
}
}
// SH}
return TokenNameIdentifier;
case 's' : //short static super switch synchronized strictfp
switch (length) {
//{ObjectTeams: 'set' (after '->')
case 3:
if (calloutSeen) {
if ( (data[++index] == 'e')
&& (data[++index] == 't'))
return TokenNameset;
}
return TokenNameIdentifier;
// SH}
case 5 :
if (data[++index] == 'h')
if ((data[++index] == 'o') && (data[++index] == 'r') && (data[++index] == 't'))
return TokenNameshort;
else
return TokenNameIdentifier;
else
if ((data[index] == 'u')
&& (data[++index] == 'p')
&& (data[++index] == 'e')
&& (data[++index] == 'r'))
return TokenNamesuper;
else
return TokenNameIdentifier;
case 6 :
if (data[++index] == 't')
if ((data[++index] == 'a')
&& (data[++index] == 't')
&& (data[++index] == 'i')
&& (data[++index] == 'c')) {
return TokenNamestatic;
} else
return TokenNameIdentifier;
else
if ((data[index] == 'w')
&& (data[++index] == 'i')
&& (data[++index] == 't')
&& (data[++index] == 'c')
&& (data[++index] == 'h'))
return TokenNameswitch;
else
return TokenNameIdentifier;
case 8 :
if ((data[++index] == 't')
&& (data[++index] == 'r')
&& (data[++index] == 'i')
&& (data[++index] == 'c')
&& (data[++index] == 't')
&& (data[++index] == 'f')
&& (data[++index] == 'p'))
return TokenNamestrictfp;
else
return TokenNameIdentifier;
case 12 :
if ((data[++index] == 'y')
&& (data[++index] == 'n')
&& (data[++index] == 'c')
&& (data[++index] == 'h')
&& (data[++index] == 'r')
&& (data[++index] == 'o')
&& (data[++index] == 'n')
&& (data[++index] == 'i')
&& (data[++index] == 'z')
&& (data[++index] == 'e')
&& (data[++index] == 'd')) {
return TokenNamesynchronized;
} else
return TokenNameIdentifier;
default :
return TokenNameIdentifier;
}
case 't' : //try throw throws transient this true
switch (length) {
case 3 :
if ((data[++index] == 'r') && (data[++index] == 'y'))
return TokenNametry;
else
return TokenNameIdentifier;
case 4 :
if (data[++index] == 'h')
if ((data[++index] == 'i') && (data[++index] == 's'))
return TokenNamethis;
else
return TokenNameIdentifier;
else
if ((data[index] == 'r') && (data[++index] == 'u') && (data[++index] == 'e'))
return TokenNametrue;
else
//{ObjectTeams: check for team keyword (always checked except after '.' -- if seen set isOTsource)
if ((data[index] == 'e')
&& (data[++index] == 'a')
&& (data[++index] == 'm')
&& (this._isOTSource || this._dotSeen == 0)
&& !this.parsePureJavaOnly)
{
this._teamKeywordSeen = true;
return TokenNameteam;
} else
//Markus Witte}
return TokenNameIdentifier;
case 5 :
if ((data[++index] == 'h')
&& (data[++index] == 'r')
&& (data[++index] == 'o')
&& (data[++index] == 'w'))
return TokenNamethrow;
else
return TokenNameIdentifier;
case 6 :
//{ObjectTeams: check for tsuper keyword
/* orig:
if ((data[++index] == 'h')
&& (data[++index] == 'r')
:giro */
if ((data[++index] == 'h')) {
if ((data[++index] == 'r')
// orig:
&& (data[++index] == 'o')
&& (data[++index] == 'w')
&& (data[++index] == 's'))
return TokenNamethrows;
else
return TokenNameIdentifier;
// :giro
} else {
if ( this._isOTSource
&& (data[index] == 's')
&& (data[++index] == 'u')
&& (data[++index] == 'p')
&& (data[++index] == 'e')
&& (data[++index] == 'r'))
return TokenNametsuper;
else
return TokenNameIdentifier;
}
//Markus Witte}
case 9 :
if ((data[++index] == 'r')
&& (data[++index] == 'a')
&& (data[++index] == 'n')
&& (data[++index] == 's')
&& (data[++index] == 'i')
&& (data[++index] == 'e')
&& (data[++index] == 'n')
&& (data[++index] == 't')) {
return TokenNametransient;
} else
return TokenNameIdentifier;
default :
return TokenNameIdentifier;
}
case 'v' : //void volatile
switch (length) {
case 4 :
if ((data[++index] == 'o') && (data[++index] == 'i') && (data[++index] == 'd'))
return TokenNamevoid;
else
return TokenNameIdentifier;
case 8 :
if ((data[++index] == 'o')
&& (data[++index] == 'l')
&& (data[++index] == 'a')
&& (data[++index] == 't')
&& (data[++index] == 'i')
&& (data[++index] == 'l')
&& (data[++index] == 'e')) {
return TokenNamevolatile;
} else
return TokenNameIdentifier;
default :
return TokenNameIdentifier;
}
case 'w' : //while widefp
switch (length) {
//{ObjectTeams: check for with, when keywords
case 4 : // with when
switch (data[++index]) {
case 'i':
if ( this._isOTSource
&& (data[++index] == 't')
&& (data[++index] == 'h'))
return TokenNamewith;
break;
case 'h':
if ( this._isOTSource
&& (data[++index] == 'e')
&& (data[++index] == 'n'))
return TokenNamewhen;
}
return TokenNameIdentifier;
//Markus Witte}
case 5 :
if ((data[++index] == 'h')
&& (data[++index] == 'i')
&& (data[++index] == 'l')
&& (data[++index] == 'e'))
return TokenNamewhile;
else
return TokenNameIdentifier;
//case 6:if ( (data[++index] =='i') && (data[++index]=='d') && (data[++index]=='e') && (data[++index]=='f')&& (data[++index]=='p'))
//return TokenNamewidefp ;
//else
//return TokenNameIdentifier;
//{ObjectTeams: check for within keyword (also in std-Java files).
case 6 :
if ((data[++index] == 'i')
&& (data[++index] == 't')
&& (data[++index] == 'h')
&& (data[++index] == 'i')
&& (data[++index] == 'n')
&& !this.parsePureJavaOnly)
return TokenNamewithin;
else
return TokenNameIdentifier;
//Markus Witte}
default :
return TokenNameIdentifier;
}
default :
return TokenNameIdentifier;
}
}
public int scanNumber(boolean dotPrefix) throws InvalidInputException {
//when entering this method the currentCharacter is the first
//digit of the number. It may be preceeded by a '.' when
//dotPrefix is true
boolean floating = dotPrefix;
if ((!dotPrefix) && (this.currentCharacter == '0')) {
if (getNextChar('x', 'X') >= 0) { //----------hexa-----------------
int start = this.currentPosition;
while (getNextCharAsDigit(16)){/*empty*/}
int end = this.currentPosition;
if (getNextChar('l', 'L') >= 0) {
if (end == start) {
throw new InvalidInputException(INVALID_HEXA);
}
return TokenNameLongLiteral;
} else if (getNextChar('.')) {
if (this.sourceLevel < ClassFileConstants.JDK1_5) {
if (end == start) {
throw new InvalidInputException(INVALID_HEXA);
}
this.currentPosition = end;
return TokenNameIntegerLiteral;
}
// hexadecimal floating point literal
// read decimal part
boolean hasNoDigitsBeforeDot = end == start;
start = this.currentPosition;
while (getNextCharAsDigit(16)){/*empty*/}
end = this.currentPosition;
if (hasNoDigitsBeforeDot && end == start) {
throw new InvalidInputException(INVALID_HEXA);
}
if (getNextChar('p', 'P') >= 0) { // consume next character
this.unicodeAsBackSlash = false;
if (((this.currentCharacter = this.source[this.currentPosition++]) == '\\')
&& (this.source[this.currentPosition] == 'u')) {
getNextUnicodeChar();
} else {
if (this.withoutUnicodePtr != 0) {
unicodeStore();
}
}
if ((this.currentCharacter == '-')
|| (this.currentCharacter == '+')) { // consume next character
this.unicodeAsBackSlash = false;
if (((this.currentCharacter = this.source[this.currentPosition++]) == '\\')
&& (this.source[this.currentPosition] == 'u')) {
getNextUnicodeChar();
} else {
if (this.withoutUnicodePtr != 0) {
unicodeStore();
}
}
}
if (!ScannerHelper.isDigit(this.currentCharacter)) {
throw new InvalidInputException(INVALID_HEXA);
}
while (getNextCharAsDigit()){/*empty*/}
if (getNextChar('f', 'F') >= 0) {
return TokenNameFloatingPointLiteral;
}
if (getNextChar('d', 'D') >= 0) {
return TokenNameDoubleLiteral;
}
if (getNextChar('l', 'L') >= 0) {
throw new InvalidInputException(INVALID_HEXA);
}
return TokenNameDoubleLiteral;
} else {
throw new InvalidInputException(INVALID_HEXA);
}
} else if (getNextChar('p', 'P') >= 0) { // consume next character
if (this.sourceLevel < ClassFileConstants.JDK1_5) {
// if we are in source level < 1.5 we report an integer literal
this.currentPosition = end;
return TokenNameIntegerLiteral;
}
this.unicodeAsBackSlash = false;
if (((this.currentCharacter = this.source[this.currentPosition++]) == '\\')
&& (this.source[this.currentPosition] == 'u')) {
getNextUnicodeChar();
} else {
if (this.withoutUnicodePtr != 0) {
unicodeStore();
}
}
if ((this.currentCharacter == '-')
|| (this.currentCharacter == '+')) { // consume next character
this.unicodeAsBackSlash = false;
if (((this.currentCharacter = this.source[this.currentPosition++]) == '\\')
&& (this.source[this.currentPosition] == 'u')) {
getNextUnicodeChar();
} else {
if (this.withoutUnicodePtr != 0) {
unicodeStore();
}
}
}
if (!ScannerHelper.isDigit(this.currentCharacter))
throw new InvalidInputException(INVALID_FLOAT);
while (getNextCharAsDigit()){/*empty*/}
if (getNextChar('f', 'F') >= 0)
return TokenNameFloatingPointLiteral;
if (getNextChar('d', 'D') >= 0)
return TokenNameDoubleLiteral;
if (getNextChar('l', 'L') >= 0) {
throw new InvalidInputException(INVALID_HEXA);
}
return TokenNameDoubleLiteral;
} else {
if (end == start)
throw new InvalidInputException(INVALID_HEXA);
return TokenNameIntegerLiteral;
}
}
//there is x or X in the number
//potential octal ! ... some one may write 000099.0 ! thus 00100 < 00078.0 is true !!!!! crazy language
if (getNextCharAsDigit()) { //-------------potential octal-----------------
while (getNextCharAsDigit()){/*empty*/}
if (getNextChar('l', 'L') >= 0) {
return TokenNameLongLiteral;
}
if (getNextChar('f', 'F') >= 0) {
return TokenNameFloatingPointLiteral;
}
if (getNextChar('d', 'D') >= 0) {
return TokenNameDoubleLiteral;
} else { //make the distinction between octal and float ....
boolean isInteger = true;
if (getNextChar('.')) {
isInteger = false;
while (getNextCharAsDigit()){/*empty*/}
}
if (getNextChar('e', 'E') >= 0) { // consume next character
isInteger = false;
this.unicodeAsBackSlash = false;
if (((this.currentCharacter = this.source[this.currentPosition++]) == '\\')
&& (this.source[this.currentPosition] == 'u')) {
getNextUnicodeChar();
} else {
if (this.withoutUnicodePtr != 0) {
unicodeStore();
}
}
if ((this.currentCharacter == '-')
|| (this.currentCharacter == '+')) { // consume next character
this.unicodeAsBackSlash = false;
if (((this.currentCharacter = this.source[this.currentPosition++]) == '\\')
&& (this.source[this.currentPosition] == 'u')) {
getNextUnicodeChar();
} else {
if (this.withoutUnicodePtr != 0) {
unicodeStore();
}
}
}
if (!ScannerHelper.isDigit(this.currentCharacter))
throw new InvalidInputException(INVALID_FLOAT);
while (getNextCharAsDigit()){/*empty*/}
}
if (getNextChar('f', 'F') >= 0)
return TokenNameFloatingPointLiteral;
if (getNextChar('d', 'D') >= 0 || !isInteger)
return TokenNameDoubleLiteral;
return TokenNameIntegerLiteral;
}
} else {
/* carry on */
}
}
while (getNextCharAsDigit()){/*empty*/}
if ((!dotPrefix) && (getNextChar('l', 'L') >= 0))
return TokenNameLongLiteral;
if ((!dotPrefix) && (getNextChar('.'))) { //decimal part that can be empty
while (getNextCharAsDigit()){/*empty*/}
floating = true;
}
//if floating is true both exponant and suffix may be optional
if (getNextChar('e', 'E') >= 0) {
floating = true;
// consume next character
this.unicodeAsBackSlash = false;
if (((this.currentCharacter = this.source[this.currentPosition++]) == '\\')
&& (this.source[this.currentPosition] == 'u')) {
getNextUnicodeChar();
} else {
if (this.withoutUnicodePtr != 0) {
unicodeStore();
}
}
if ((this.currentCharacter == '-')
|| (this.currentCharacter == '+')) { // consume next character
this.unicodeAsBackSlash = false;
if (((this.currentCharacter = this.source[this.currentPosition++]) == '\\')
&& (this.source[this.currentPosition] == 'u')) {
getNextUnicodeChar();
} else {
if (this.withoutUnicodePtr != 0) {
unicodeStore();
}
}
}
if (!ScannerHelper.isDigit(this.currentCharacter))
throw new InvalidInputException(INVALID_FLOAT);
while (getNextCharAsDigit()){/*empty*/}
}
if (getNextChar('d', 'D') >= 0)
return TokenNameDoubleLiteral;
if (getNextChar('f', 'F') >= 0)
return TokenNameFloatingPointLiteral;
//the long flag has been tested before
return floating ? TokenNameDoubleLiteral : TokenNameIntegerLiteral;
}
/**
* Search the line number corresponding to a specific position
* @param position int
* @return int
*/
public final int getLineNumber(int position) {
return Util.getLineNumber(position, this.lineEnds, 0, this.linePtr);
}
public final void setSource(char[] sourceString){
//the source-buffer is set to sourceString
int sourceLength;
if (sourceString == null) {
this.source = CharOperation.NO_CHAR;
sourceLength = 0;
} else {
this.source = sourceString;
sourceLength = sourceString.length;
}
this.startPosition = -1;
this.eofPosition = sourceLength;
this.initialPosition = this.currentPosition = 0;
this.containsAssertKeyword = false;
this.linePtr = -1;
//{ObjectTeams: reset to default mode (std-Java).
resetOTFlags();
// SH}
}
/*
* Should be used if a parse (usually a diet parse) has already been performed on the unit,
* so as to get the already computed line end positions.
*/
public final void setSource(char[] contents, CompilationResult compilationResult) {
if (contents == null) {
char[] cuContents = compilationResult.compilationUnit.getContents();
setSource(cuContents);
} else {
setSource(contents);
}
int[] lineSeparatorPositions = compilationResult.lineSeparatorPositions;
if (lineSeparatorPositions != null) {
this.lineEnds = lineSeparatorPositions;
this.linePtr = lineSeparatorPositions.length - 1;
}
}
/*
* Should be used if a parse (usually a diet parse) has already been performed on the unit,
* so as to get the already computed line end positions.
*/
public final void setSource(CompilationResult compilationResult) {
setSource(null, compilationResult);
}
public String toString() {
if (this.startPosition == this.eofPosition)
return "EOF\n\n" + new String(this.source); //$NON-NLS-1$
if (this.currentPosition > this.eofPosition)
return "behind the EOF\n\n" + new String(this.source); //$NON-NLS-1$
if (this.currentPosition <= 0)
return "NOT started!\n\n"+ new String(this.source); //$NON-NLS-1$
StringBuffer buffer = new StringBuffer();
if (this.startPosition < 1000) {
buffer.append(this.source, 0, this.startPosition);
} else {
buffer.append("<source beginning>\n...\n"); //$NON-NLS-1$
int line = Util.getLineNumber(this.startPosition-1000, this.lineEnds, 0, this.linePtr);
int lineStart = getLineStart(line);
buffer.append(this.source, lineStart, this.startPosition-lineStart);
}
buffer.append("\n===============================\nStarts here -->"); //$NON-NLS-1$
int middleLength = (this.currentPosition - 1) - this.startPosition + 1;
if (middleLength > -1) {
buffer.append(this.source, this.startPosition, middleLength);
}
buffer.append("<-- Ends here\n===============================\n"); //$NON-NLS-1$
buffer.append(this.source, (this.currentPosition - 1) + 1, this.eofPosition - (this.currentPosition - 1) - 1);
return buffer.toString();
}
public String toStringAction(int act) {
switch (act) {
case TokenNameIdentifier :
return "Identifier(" + new String(getCurrentTokenSource()) + ")"; //$NON-NLS-1$ //$NON-NLS-2$
case TokenNameabstract :
return "abstract"; //$NON-NLS-1$
//{ObjectTeams: deal with OT-specific identifiers
case TokenNameas :
return "as"; //$NON-NLS-1$
case TokenNamecallin :
return "callin"; //$NON-NLS-1$
case TokenNameplayedBy :
return "playedBy"; //$NON-NLS-1$
case TokenNameprecedence :
return "precedence"; //$NON-NLS-1$
case TokenNameteam :
return "team"; //$NON-NLS-1$
case TokenNamewith :
return "with"; //$NON-NLS-1$
case TokenNamewithin :
return "within"; //$NON-NLS-1$
case TokenNamereplace:
return "replace"; //$NON-NLS-1$
case TokenNamebefore:
return "before"; //$NON-NLS-1$
case TokenNameafter:
return "after"; //$NON-NLS-1$
case TokenNameget:
return "get"; //$NON-NLS-1$
case TokenNameset:
return "set"; //$NON-NLS-1$
// Markus Witte}
case TokenNameboolean :
return "boolean"; //$NON-NLS-1$
case TokenNamebreak :
return "break"; //$NON-NLS-1$
case TokenNamebyte :
return "byte"; //$NON-NLS-1$
case TokenNamecase :
return "case"; //$NON-NLS-1$
case TokenNamecatch :
return "catch"; //$NON-NLS-1$
case TokenNamechar :
return "char"; //$NON-NLS-1$
case TokenNameclass :
return "class"; //$NON-NLS-1$
case TokenNamecontinue :
return "continue"; //$NON-NLS-1$
case TokenNamedefault :
return "default"; //$NON-NLS-1$
case TokenNamedo :
return "do"; //$NON-NLS-1$
case TokenNamedouble :
return "double"; //$NON-NLS-1$
case TokenNameelse :
return "else"; //$NON-NLS-1$
case TokenNameextends :
return "extends"; //$NON-NLS-1$
case TokenNamefalse :
return "false"; //$NON-NLS-1$
case TokenNamefinal :
return "final"; //$NON-NLS-1$
case TokenNamefinally :
return "finally"; //$NON-NLS-1$
case TokenNamefloat :
return "float"; //$NON-NLS-1$
case TokenNamefor :
return "for"; //$NON-NLS-1$
case TokenNameif :
return "if"; //$NON-NLS-1$
case TokenNameimplements :
return "implements"; //$NON-NLS-1$
case TokenNameimport :
return "import"; //$NON-NLS-1$
case TokenNameinstanceof :
return "instanceof"; //$NON-NLS-1$
case TokenNameint :
return "int"; //$NON-NLS-1$
case TokenNameinterface :
return "interface"; //$NON-NLS-1$
case TokenNamelong :
return "long"; //$NON-NLS-1$
case TokenNamenative :
return "native"; //$NON-NLS-1$
case TokenNamenew :
return "new"; //$NON-NLS-1$
case TokenNamenull :
return "null"; //$NON-NLS-1$
case TokenNamepackage :
return "package"; //$NON-NLS-1$
case TokenNameprivate :
return "private"; //$NON-NLS-1$
case TokenNameprotected :
return "protected"; //$NON-NLS-1$
case TokenNamepublic :
return "public"; //$NON-NLS-1$
case TokenNamereturn :
return "return"; //$NON-NLS-1$
case TokenNameshort :
return "short"; //$NON-NLS-1$
case TokenNamestatic :
return "static"; //$NON-NLS-1$
case TokenNamesuper :
return "super"; //$NON-NLS-1$
case TokenNameswitch :
return "switch"; //$NON-NLS-1$
case TokenNamesynchronized :
return "synchronized"; //$NON-NLS-1$
case TokenNamethis :
return "this"; //$NON-NLS-1$
case TokenNamethrow :
return "throw"; //$NON-NLS-1$
case TokenNamethrows :
return "throws"; //$NON-NLS-1$
case TokenNametransient :
return "transient"; //$NON-NLS-1$
case TokenNametrue :
return "true"; //$NON-NLS-1$
case TokenNametry :
return "try"; //$NON-NLS-1$
case TokenNamevoid :
return "void"; //$NON-NLS-1$
case TokenNamevolatile :
return "volatile"; //$NON-NLS-1$
case TokenNamewhile :
return "while"; //$NON-NLS-1$
case TokenNameIntegerLiteral :
return "Integer(" + new String(getCurrentTokenSource()) + ")"; //$NON-NLS-1$ //$NON-NLS-2$
case TokenNameLongLiteral :
return "Long(" + new String(getCurrentTokenSource()) + ")"; //$NON-NLS-1$ //$NON-NLS-2$
case TokenNameFloatingPointLiteral :
return "Float(" + new String(getCurrentTokenSource()) + ")"; //$NON-NLS-1$ //$NON-NLS-2$
case TokenNameDoubleLiteral :
return "Double(" + new String(getCurrentTokenSource()) + ")"; //$NON-NLS-1$ //$NON-NLS-2$
case TokenNameCharacterLiteral :
return "Char(" + new String(getCurrentTokenSource()) + ")"; //$NON-NLS-1$ //$NON-NLS-2$
case TokenNameStringLiteral :
return "String(" + new String(getCurrentTokenSource()) + ")"; //$NON-NLS-1$ //$NON-NLS-2$
case TokenNamePLUS_PLUS :
return "++"; //$NON-NLS-1$
case TokenNameMINUS_MINUS :
return "--"; //$NON-NLS-1$
case TokenNameEQUAL_EQUAL :
return "=="; //$NON-NLS-1$
//{ObjectTeams: deal with callins/callouts
case TokenNameBINDIN :
return "<-"; //$NON-NLS-1$
case TokenNameBINDOUT :
return "->"; //$NON-NLS-1$
case TokenNameCALLOUT_OVERRIDE :
return "=>"; //$NON-NLS-1$
// Markus Witte}
case TokenNameLESS_EQUAL :
return "<="; //$NON-NLS-1$
case TokenNameGREATER_EQUAL :
return ">="; //$NON-NLS-1$
case TokenNameNOT_EQUAL :
return "!="; //$NON-NLS-1$
case TokenNameLEFT_SHIFT :
return "<<"; //$NON-NLS-1$
case TokenNameRIGHT_SHIFT :
return ">>"; //$NON-NLS-1$
case TokenNameUNSIGNED_RIGHT_SHIFT :
return ">>>"; //$NON-NLS-1$
case TokenNamePLUS_EQUAL :
return "+="; //$NON-NLS-1$
case TokenNameMINUS_EQUAL :
return "-="; //$NON-NLS-1$
case TokenNameMULTIPLY_EQUAL :
return "*="; //$NON-NLS-1$
case TokenNameDIVIDE_EQUAL :
return "/="; //$NON-NLS-1$
case TokenNameAND_EQUAL :
return "&="; //$NON-NLS-1$
case TokenNameOR_EQUAL :
return "|="; //$NON-NLS-1$
case TokenNameXOR_EQUAL :
return "^="; //$NON-NLS-1$
case TokenNameREMAINDER_EQUAL :
return "%="; //$NON-NLS-1$
case TokenNameLEFT_SHIFT_EQUAL :
return "<<="; //$NON-NLS-1$
case TokenNameRIGHT_SHIFT_EQUAL :
return ">>="; //$NON-NLS-1$
case TokenNameUNSIGNED_RIGHT_SHIFT_EQUAL :
return ">>>="; //$NON-NLS-1$
case TokenNameOR_OR :
return "||"; //$NON-NLS-1$
case TokenNameAND_AND :
return "&&"; //$NON-NLS-1$
case TokenNamePLUS :
return "+"; //$NON-NLS-1$
case TokenNameMINUS :
return "-"; //$NON-NLS-1$
case TokenNameNOT :
return "!"; //$NON-NLS-1$
case TokenNameREMAINDER :
return "%"; //$NON-NLS-1$
case TokenNameXOR :
return "^"; //$NON-NLS-1$
case TokenNameAND :
return "&"; //$NON-NLS-1$
case TokenNameMULTIPLY :
return "*"; //$NON-NLS-1$
case TokenNameOR :
return "|"; //$NON-NLS-1$
case TokenNameTWIDDLE :
return "~"; //$NON-NLS-1$
case TokenNameDIVIDE :
return "/"; //$NON-NLS-1$
case TokenNameGREATER :
return ">"; //$NON-NLS-1$
case TokenNameLESS :
return "<"; //$NON-NLS-1$
case TokenNameLPAREN :
return "("; //$NON-NLS-1$
case TokenNameRPAREN :
return ")"; //$NON-NLS-1$
case TokenNameLBRACE :
return "{"; //$NON-NLS-1$
case TokenNameRBRACE :
return "}"; //$NON-NLS-1$
case TokenNameLBRACKET :
return "["; //$NON-NLS-1$
case TokenNameRBRACKET :
return "]"; //$NON-NLS-1$
case TokenNameSEMICOLON :
return ";"; //$NON-NLS-1$
case TokenNameQUESTION :
return "?"; //$NON-NLS-1$
case TokenNameCOLON :
return ":"; //$NON-NLS-1$
case TokenNameCOMMA :
return ","; //$NON-NLS-1$
case TokenNameDOT :
return "."; //$NON-NLS-1$
case TokenNameEQUAL :
return "="; //$NON-NLS-1$
case TokenNameEOF :
return "EOF"; //$NON-NLS-1$
case TokenNameWHITESPACE :
return "white_space(" + new String(getCurrentTokenSource()) + ")"; //$NON-NLS-1$ //$NON-NLS-2$
default :
return "not-a-token"; //$NON-NLS-1$
}
}
public void unicodeInitializeBuffer(int length) {
this.withoutUnicodePtr = length;
if (this.withoutUnicodeBuffer == null) this.withoutUnicodeBuffer = new char[length+(1+10)];
int bLength = this.withoutUnicodeBuffer.length;
if (1+length >= bLength) {
System.arraycopy(this.withoutUnicodeBuffer, 0, this.withoutUnicodeBuffer = new char[length + (1+10)], 0, bLength);
}
System.arraycopy(this.source, this.startPosition, this.withoutUnicodeBuffer, 1, length);
}
public void unicodeStore() {
int pos = ++this.withoutUnicodePtr;
if (this.withoutUnicodeBuffer == null) this.withoutUnicodeBuffer = new char[10];
int length = this.withoutUnicodeBuffer.length;
if (pos == length) {
System.arraycopy(this.withoutUnicodeBuffer, 0, this.withoutUnicodeBuffer = new char[length * 2], 0, length);
}
this.withoutUnicodeBuffer[pos] = this.currentCharacter;
}
}