org.infinispan.protostream.impl.parser.AnnotationLexer Maven / Gradle / Ivy
package org.infinispan.protostream.impl.parser;
import org.infinispan.protostream.AnnotationParserException;
import org.infinispan.protostream.descriptors.AnnotationElement;
/**
* Splits an input array of characters into tokens. See {@link AnnotationTokens}.
*
* @author [email protected]
* @since 2.0
*/
final class AnnotationLexer {
AnnotationTokens token;
long pos;
long lastPos;
String name;
// a temporary buffer used for accumulating the current token
private char[] sbuf = new char[128];
private int sp;
private final char[] buf;
private final int buflen;
private int bp = -1;
private char ch = 0;
private int line = 1;
private int col = 0;
private boolean leadingWhitespace = true;
/**
* Do we expect to encounter non-syntactically correct text which is probably human readable documentation
* surrounding the annotations?
*/
private boolean expectDocNoise;
public AnnotationLexer(char[] input, boolean expectDocNoise) {
this.expectDocNoise = expectDocNoise;
buf = input;
buflen = input.length;
scanNextChar();
skipDocNoise();
}
public void skipDocNoise() {
if (token == AnnotationTokens.AT || token == AnnotationTokens.EOF) {
return;
}
sp = 0;
do {
switch (ch) {
case ' ':
case '\t':
scanNextChar();
continue;
case '\f':
col = 0;
leadingWhitespace = true;
scanNextChar();
continue;
case '\r':
line++;
col = 0;
leadingWhitespace = true;
scanNextChar();
if (ch == '\n') {
col = 0;
leadingWhitespace = true;
scanNextChar();
}
continue;
case '\n':
line++;
col = 0;
leadingWhitespace = true;
scanNextChar();
continue;
case '@':
if (!leadingWhitespace) {
throw new AnnotationParserException(String.format("Error: %d,%d: Annotations must start on an empty line", line, col));
}
// intentional fall-through
case 0:
nextToken();
return;
default:
if (expectDocNoise) {
scanNextChar();
} else {
throw new AnnotationParserException(String.format("Error: %d,%d: Unexpected character: %c", line, col, ch));
}
}
} while (bp != buflen);
token = AnnotationTokens.EOF;
}
private void scanNextChar() {
if (ch != 0 && !Character.isWhitespace(ch)) {
leadingWhitespace = false;
}
bp++;
if (bp == buflen) {
ch = 0;
} else {
ch = buf[bp];
col++;
}
}
private void putChar(char c) {
if (sp == sbuf.length) {
char newSbuf[] = new char[sbuf.length * 2];
System.arraycopy(sbuf, 0, newSbuf, 0, sbuf.length);
sbuf = newSbuf;
}
sbuf[sp++] = c;
}
private void scanLiteralChar() {
if (ch == '\\') {
scanNextChar();
switch (ch) {
case 'b':
putChar('\b');
scanNextChar();
break;
case 't':
putChar('\t');
scanNextChar();
break;
case 'n':
putChar('\n');
scanNextChar();
break;
case 'f':
putChar('\f');
scanNextChar();
break;
case 'r':
putChar('\r');
scanNextChar();
break;
case '\'':
putChar('\'');
scanNextChar();
break;
case '"':
putChar('"');
scanNextChar();
break;
case '\\':
putChar('\\');
scanNextChar();
break;
default:
throw new AnnotationParserException(String.format("Error: %d,%d: illegal escape character: %c", line, col, ch));
}
} else if (bp != buflen) {
putChar(ch);
scanNextChar();
}
}
private void scanDecimal() {
while (Character.digit(ch, 10) >= 0) {
putChar(ch);
scanNextChar();
}
if (ch == 'e' || ch == 'E') {
putChar(ch);
scanNextChar();
if (ch == '+' || ch == '-') {
putChar(ch);
scanNextChar();
}
if ('0' <= ch && ch <= '9') {
do {
putChar(ch);
scanNextChar();
} while ('0' <= ch && ch <= '9');
} else {
throw new AnnotationParserException(String.format("Error: %s: malformed floating point literal", AnnotationElement.positionToString(pos)));
}
}
if (ch == 'f' || ch == 'F') {
scanNextChar();
token = AnnotationTokens.FLOAT_LITERAL;
} else {
if (ch == 'd' || ch == 'D') {
scanNextChar();
}
token = AnnotationTokens.DOUBLE_LITERAL;
}
}
private void scanNumber() {
while (Character.digit(ch, 10) >= 0) {
putChar(ch);
scanNextChar();
}
if (ch == '.') {
putChar(ch);
scanNextChar();
scanDecimal();
} else if (ch == 'e' || ch == 'E' || ch == 'f' || ch == 'F' || ch == 'd' || ch == 'D') {
scanDecimal();
} else if (ch == 'l' || ch == 'L') {
scanNextChar();
token = AnnotationTokens.LONG_LITERAL;
} else {
token = AnnotationTokens.INT_LITERAL;
}
}
private void scanIdentifier() {
do {
putChar(ch);
if (++bp == buflen) {
ch = 0;
break;
}
ch = buf[bp];
col++;
}
while (ch == '_' || ch == '$' || ch >= '0' && ch <= '9' || ch >= 'A' && ch <= 'Z' || ch >= 'a' && ch <= 'z'
|| ch > 128 && Character.isJavaIdentifierPart(ch));
name = new String(sbuf, 0, sp);
AnnotationTokens tok = AnnotationTokens.byName(name);
token = tok == null ? AnnotationTokens.IDENTIFIER : tok;
}
public int mark() {
return bp;
}
public String getText(int startIndex, int endIndex) {
return new String(buf, startIndex, endIndex - startIndex);
}
public void nextToken() {
lastPos = AnnotationElement.makePosition(line, col);
sp = 0;
while (true) {
pos = AnnotationElement.makePosition(line, col);
switch (ch) {
case ',':
scanNextChar();
token = AnnotationTokens.COMMA;
return;
case '(':
scanNextChar();
token = AnnotationTokens.LPAREN;
return;
case ')':
scanNextChar();
token = AnnotationTokens.RPAREN;
return;
case '{':
scanNextChar();
token = AnnotationTokens.LBRACE;
return;
case '}':
scanNextChar();
token = AnnotationTokens.RBRACE;
return;
case '@':
scanNextChar();
token = AnnotationTokens.AT;
return;
case '=':
scanNextChar();
token = AnnotationTokens.EQ;
return;
case '.':
scanNextChar();
if ('0' <= ch && ch <= '9') {
putChar('.');
scanDecimal();
} else {
token = AnnotationTokens.DOT;
}
return;
case '_':
case '$':
case 'A':
case 'B':
case 'C':
case 'D':
case 'E':
case 'F':
case 'G':
case 'H':
case 'I':
case 'J':
case 'K':
case 'L':
case 'M':
case 'N':
case 'O':
case 'P':
case 'Q':
case 'R':
case 'S':
case 'T':
case 'U':
case 'V':
case 'W':
case 'X':
case 'Y':
case 'Z':
case 'a':
case 'b':
case 'c':
case 'd':
case 'e':
case 'f':
case 'g':
case 'h':
case 'i':
case 'j':
case 'k':
case 'l':
case 'm':
case 'n':
case 'o':
case 'p':
case 'q':
case 'r':
case 's':
case 't':
case 'u':
case 'v':
case 'w':
case 'x':
case 'y':
case 'z':
scanIdentifier();
return;
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
scanNumber();
return;
case '\'':
scanNextChar();
if (ch == '\'') {
throw new AnnotationParserException(String.format("Error: %s: empty character literal", AnnotationElement.positionToString(pos)));
} else {
if (ch == '\r' || ch == '\n') {
throw new AnnotationParserException(String.format("Error: %s: illegal line end in character literal", AnnotationElement.positionToString(pos)));
}
scanLiteralChar();
if (ch == '\'') {
scanNextChar();
token = AnnotationTokens.CHARACTER_LITERAL;
} else {
throw new AnnotationParserException(String.format("Error: %s: unclosed character literal", AnnotationElement.positionToString(pos)));
}
}
return;
case '"':
scanNextChar();
while (ch != '"' && ch != '\r' && ch != '\n' && bp < buflen) {
scanLiteralChar();
}
if (ch == '"') {
token = AnnotationTokens.STRING_LITERAL;
scanNextChar();
} else {
throw new AnnotationParserException(String.format("Error: %s: unclosed string literal", AnnotationElement.positionToString(pos)));
}
return;
case ' ':
case '\t':
scanNextChar();
continue;
case '\f':
col = 0;
leadingWhitespace = true;
scanNextChar();
continue;
case '\r':
line++;
col = 0;
leadingWhitespace = true;
scanNextChar();
if (ch == '\n') {
col = 0;
leadingWhitespace = true;
scanNextChar();
}
continue;
case '\n':
line++;
col = 0;
leadingWhitespace = true;
scanNextChar();
continue;
default:
if (ch == 0 && bp == buflen) {
token = AnnotationTokens.EOF;
} else if (Character.isJavaIdentifierStart(ch)) {
scanIdentifier();
} else {
throw new AnnotationParserException(String.format("Error: %s: illegal character: %c", AnnotationElement.positionToString(pos), ch));
}
return;
}
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy