use of org.mvel2.ast.InterceptorWrapper in project mvel by mikebrock.
the class AbstractParser method nextToken.
/**
* Retrieve the next token in the expression.
*
* @return -
*/
protected ASTNode nextToken() {
try {
/**
* If the cursor is at the end of the expression, we have nothing more to do:
* return null.
*/
if (!splitAccumulator.isEmpty()) {
lastNode = (ASTNode) splitAccumulator.pop();
if (cursor >= end && lastNode instanceof EndOfStatement) {
return nextToken();
} else {
return lastNode;
}
} else if (cursor >= end) {
return null;
}
int brace, idx;
int tmpStart;
String name;
/**
* Because of parser recursion for sub-expression parsing, we sometimes need to remain
* certain field states. We do not reset for assignments, boolean mode, list creation or
* a capture only mode.
*/
boolean capture = false, union = false;
if ((fields & ASTNode.COMPILE_IMMEDIATE) != 0 && pCtx == null) {
debugSymbols = (pCtx = getParserContext()).isDebugSymbols();
}
if (debugSymbols) {
if (!lastWasLineLabel) {
if (pCtx.getSourceFile() == null) {
throw new CompileException("unable to produce debugging symbols: source name must be provided.", expr, st);
}
if (!pCtx.isLineMapped(pCtx.getSourceFile())) {
pCtx.initLineMapping(pCtx.getSourceFile(), expr);
}
skipWhitespace();
if (cursor >= end) {
return null;
}
int line = pCtx.getLineFor(pCtx.getSourceFile(), cursor);
if (!pCtx.isVisitedLine(pCtx.getSourceFile(), pCtx.setLineCount(line)) && !pCtx.isBlockSymbols()) {
lastWasLineLabel = true;
pCtx.visitLine(pCtx.getSourceFile(), line);
return lastNode = pCtx.setLastLineLabel(new LineLabel(pCtx.getSourceFile(), line));
}
} else {
lastWasComment = lastWasLineLabel = false;
}
}
/**
* Skip any whitespace currently under the starting point.
*/
skipWhitespace();
/**
* From here to the end of the method is the core MVEL parsing code. Fiddling around here is asking for
* trouble unless you really know what you're doing.
*/
st = cursor;
Mainloop: while (cursor != end) {
if (isIdentifierPart(expr[cursor])) {
capture = true;
cursor++;
while (cursor != end && isIdentifierPart(expr[cursor])) cursor++;
}
if (capture) {
String t;
if (OPERATORS.containsKey(t = new String(expr, st, cursor - st))) {
switch(OPERATORS.get(t)) {
case NEW:
if (!isIdentifierPart(expr[st = cursor = trimRight(cursor)])) {
throw new CompileException("unexpected character (expected identifier): " + expr[cursor], expr, st);
}
/**
* Capture the beginning part of the token.
*/
do {
captureToNextTokenJunction();
skipWhitespace();
} while (cursor < end && expr[cursor] == '[');
/**
* If it's not a dimentioned array, continue capturing if necessary.
*/
if (cursor < end && !lastNonWhite(']'))
captureToEOT();
TypeDescriptor descr = new TypeDescriptor(expr, st, trimLeft(cursor) - st, fields);
if (pCtx == null)
pCtx = getParserContext();
if (pCtx.hasProtoImport(descr.getClassName())) {
return lastNode = new NewPrototypeNode(descr);
}
lastNode = new NewObjectNode(descr, fields, pCtx);
skipWhitespace();
if (cursor != end && expr[cursor] == '{') {
if (!((NewObjectNode) lastNode).getTypeDescr().isUndimensionedArray()) {
throw new CompileException("conflicting syntax: dimensioned array with initializer block", expr, st);
}
st = cursor;
Class egressType = lastNode.getEgressType();
if (egressType == null) {
try {
egressType = getClassReference(pCtx, descr);
} catch (ClassNotFoundException e) {
throw new CompileException("could not instantiate class", expr, st, e);
}
}
cursor = balancedCaptureWithLineAccounting(expr, st, end, expr[cursor], pCtx) + 1;
if (tokenContinues()) {
lastNode = new InlineCollectionNode(expr, st, cursor - st, fields, egressType, pCtx);
st = cursor;
captureToEOT();
return lastNode = new Union(expr, st + 1, cursor, fields, lastNode);
} else {
return lastNode = new InlineCollectionNode(expr, st, cursor - st, fields, egressType, pCtx);
}
} else if (((NewObjectNode) lastNode).getTypeDescr().isUndimensionedArray()) {
throw new CompileException("array initializer expected", expr, st);
}
st = cursor;
return lastNode;
case ASSERT:
st = cursor = trimRight(cursor);
captureToEOS();
return lastNode = new AssertNode(expr, st, cursor-- - st, fields, pCtx);
case RETURN:
st = cursor = trimRight(cursor);
captureToEOS();
return lastNode = new ReturnNode(expr, st, cursor - st, fields, pCtx);
case IF:
return captureCodeBlock(ASTNode.BLOCK_IF);
case ELSE:
throw new CompileException("else without if", expr, st);
case FOREACH:
return captureCodeBlock(ASTNode.BLOCK_FOREACH);
case WHILE:
return captureCodeBlock(ASTNode.BLOCK_WHILE);
case UNTIL:
return captureCodeBlock(ASTNode.BLOCK_UNTIL);
case FOR:
return captureCodeBlock(ASTNode.BLOCK_FOR);
case WITH:
return captureCodeBlock(ASTNode.BLOCK_WITH);
case DO:
return captureCodeBlock(ASTNode.BLOCK_DO);
case PROTO:
return captureCodeBlock(PROTO);
case ISDEF:
st = cursor = trimRight(cursor);
captureToNextTokenJunction();
return lastNode = new IsDef(expr, st, cursor - st);
case IMPORT:
st = cursor = trimRight(cursor);
captureToEOS();
ImportNode importNode = new ImportNode(expr, st, cursor - st);
if (pCtx == null)
pCtx = getParserContext();
if (importNode.isPackageImport()) {
pCtx.addPackageImport(importNode.getPackageImport());
} else {
pCtx.addImport(importNode.getImportClass().getSimpleName(), importNode.getImportClass());
}
return lastNode = importNode;
case IMPORT_STATIC:
st = cursor = trimRight(cursor);
captureToEOS();
return lastNode = new StaticImportNode(expr, st, trimLeft(cursor) - st);
case FUNCTION:
lastNode = captureCodeBlock(FUNCTION);
st = cursor + 1;
return lastNode;
case UNTYPED_VAR:
int end;
st = cursor + 1;
while (true) {
captureToEOT();
end = cursor;
skipWhitespace();
if (cursor != end && expr[cursor] == '=') {
if (end == (cursor = st))
throw new CompileException("illegal use of reserved word: var", expr, st);
continue Mainloop;
} else {
name = new String(expr, st, end - st);
if (pCtx != null && (idx = pCtx.variableIndexOf(name)) != -1) {
splitAccumulator.add(lastNode = new IndexedDeclTypedVarNode(idx, st, end - st, Object.class));
} else {
splitAccumulator.add(lastNode = new DeclTypedVarNode(name, expr, st, end - st, Object.class, fields, pCtx));
}
}
if (cursor == this.end || expr[cursor] != ',')
break;
else {
cursor++;
skipWhitespace();
st = cursor;
}
}
return (ASTNode) splitAccumulator.pop();
}
}
skipWhitespace();
/**
* If we *were* capturing a token, and we just hit a non-identifier
* character, we stop and figure out what to do.
*/
if (cursor != end && expr[cursor] == '(') {
cursor = balancedCaptureWithLineAccounting(expr, cursor, end, '(', pCtx) + 1;
}
/**
* If we encounter any of the following cases, we are still dealing with
* a contiguous token.
*/
CaptureLoop: while (cursor != end) {
switch(expr[cursor]) {
case '.':
union = true;
cursor++;
skipWhitespace();
continue;
case '?':
if (lookToLast() == '.') {
union = true;
cursor++;
continue;
} else {
break CaptureLoop;
}
case '+':
switch(lookAhead()) {
case '+':
name = new String(subArray(st, trimLeft(cursor)));
if (pCtx != null && (idx = pCtx.variableIndexOf(name)) != -1) {
lastNode = new IndexedPostFixIncNode(idx, pCtx);
} else {
lastNode = new PostFixIncNode(name, pCtx);
}
cursor += 2;
expectEOS();
return lastNode;
case '=':
name = createStringTrimmed(expr, st, cursor - st);
st = cursor += 2;
captureToEOS();
if (union) {
return lastNode = new DeepAssignmentNode(expr, st = trimRight(st), trimLeft(cursor) - st, fields, ADD, name, pCtx);
} else if (pCtx != null && (idx = pCtx.variableIndexOf(name)) != -1) {
return lastNode = new IndexedAssignmentNode(expr, st, cursor - st, fields, ADD, name, idx, pCtx);
} else {
return lastNode = new OperativeAssign(name, expr, st = trimRight(st), trimLeft(cursor) - st, ADD, fields, pCtx);
}
}
if (isDigit(lookAhead()) && cursor > 1 && (expr[cursor - 1] == 'E' || expr[cursor - 1] == 'e') && isDigit(expr[cursor - 2])) {
cursor++;
// capture = true;
continue Mainloop;
}
break CaptureLoop;
case '-':
switch(lookAhead()) {
case '-':
name = new String(subArray(st, trimLeft(cursor)));
if (pCtx != null && (idx = pCtx.variableIndexOf(name)) != -1) {
lastNode = new IndexedPostFixDecNode(idx, pCtx);
} else {
lastNode = new PostFixDecNode(name, pCtx);
}
cursor += 2;
expectEOS();
return lastNode;
case '=':
name = new String(expr, st, trimLeft(cursor) - st);
st = cursor += 2;
captureToEOS();
if (union) {
return lastNode = new DeepAssignmentNode(expr, st, cursor - st, fields, SUB, t, pCtx);
} else if (pCtx != null && (idx = pCtx.variableIndexOf(name)) != -1) {
return lastNode = new IndexedOperativeAssign(expr, st, cursor - st, SUB, idx, fields, pCtx);
} else {
return lastNode = new OperativeAssign(name, expr, st, cursor - st, SUB, fields, pCtx);
}
}
if (isDigit(lookAhead()) && cursor > 1 && (expr[cursor - 1] == 'E' || expr[cursor - 1] == 'e') && isDigit(expr[cursor - 2])) {
cursor++;
capture = true;
continue Mainloop;
}
break CaptureLoop;
/**
* Exit immediately for any of these cases.
*/
case '!':
case ',':
case '"':
case '\'':
case ';':
case ':':
break CaptureLoop;
// special compact code for recursive parses
case '\u00AB':
case '\u00BB':
case '\u00AC':
case '&':
case '^':
case '|':
case '*':
case '/':
case '%':
char op = expr[cursor];
if (lookAhead() == '=') {
name = new String(expr, st, trimLeft(cursor) - st);
st = cursor += 2;
captureToEOS();
if (union) {
return lastNode = new DeepAssignmentNode(expr, st, cursor - st, fields, opLookup(op), t, pCtx);
} else if (pCtx != null && (idx = pCtx.variableIndexOf(name)) != -1) {
return lastNode = new IndexedOperativeAssign(expr, st, cursor - st, opLookup(op), idx, fields, pCtx);
} else {
return lastNode = new OperativeAssign(name, expr, st, cursor - st, opLookup(op), fields, pCtx);
}
}
break CaptureLoop;
case '<':
if ((lookAhead() == '<' && lookAhead(2) == '=')) {
name = new String(expr, st, trimLeft(cursor) - st);
st = cursor += 3;
captureToEOS();
if (union) {
return lastNode = new DeepAssignmentNode(expr, st, cursor - st, fields, BW_SHIFT_LEFT, t, pCtx);
} else if (pCtx != null && (idx = pCtx.variableIndexOf(name)) != -1) {
return lastNode = new IndexedOperativeAssign(expr, st, cursor - st, BW_SHIFT_LEFT, idx, fields, pCtx);
} else {
return lastNode = new OperativeAssign(name, expr, st, cursor - st, BW_SHIFT_LEFT, fields, pCtx);
}
}
break CaptureLoop;
case '>':
if (lookAhead() == '>') {
if (lookAhead(2) == '=') {
name = new String(expr, st, trimLeft(cursor) - st);
st = cursor += 3;
captureToEOS();
if (union) {
return lastNode = new DeepAssignmentNode(expr, st, cursor - st, fields, BW_SHIFT_RIGHT, t, pCtx);
} else if (pCtx != null && (idx = pCtx.variableIndexOf(name)) != -1) {
return lastNode = new IndexedOperativeAssign(expr, st, cursor - st, BW_SHIFT_RIGHT, idx, fields, pCtx);
} else {
return lastNode = new OperativeAssign(name, expr, st, cursor - st, BW_SHIFT_RIGHT, fields, pCtx);
}
} else if ((lookAhead(2) == '>' && lookAhead(3) == '=')) {
name = new String(expr, st, trimLeft(cursor) - st);
st = cursor += 4;
captureToEOS();
if (union) {
return lastNode = new DeepAssignmentNode(expr, st, cursor - st, fields, BW_USHIFT_RIGHT, t, pCtx);
} else if (pCtx != null && (idx = pCtx.variableIndexOf(name)) != -1) {
return lastNode = new IndexedOperativeAssign(expr, st, cursor - st, BW_USHIFT_RIGHT, idx, fields, pCtx);
} else {
return lastNode = new OperativeAssign(name, expr, st, cursor - st, BW_USHIFT_RIGHT, fields, pCtx);
}
}
}
break CaptureLoop;
case '(':
cursor = balancedCaptureWithLineAccounting(expr, cursor, end, '(', pCtx) + 1;
continue;
case '[':
cursor = balancedCaptureWithLineAccounting(expr, cursor, end, '[', pCtx) + 1;
continue;
case '{':
if (!union)
break CaptureLoop;
cursor = balancedCaptureWithLineAccounting(expr, cursor, end, '{', pCtx) + 1;
continue;
case '~':
if (lookAhead() == '=') {
// tmp = subArray(start, trimLeft(cursor));
tmpStart = st;
int tmpOffset = cursor - st;
st = cursor += 2;
captureToEOT();
return lastNode = new RegExMatch(expr, tmpStart, tmpOffset, fields, st, cursor - st, pCtx);
}
break CaptureLoop;
case '=':
if (lookAhead() == '+') {
name = new String(expr, st, trimLeft(cursor) - st);
st = cursor += 2;
if (!isNextIdentifierOrLiteral()) {
throw new CompileException("unexpected symbol '" + expr[cursor] + "'", expr, st);
}
captureToEOS();
if (pCtx != null && (idx = pCtx.variableIndexOf(name)) != -1) {
return lastNode = new IndexedOperativeAssign(expr, st, cursor - st, ADD, idx, fields, pCtx);
} else {
return lastNode = new OperativeAssign(name, expr, st, cursor - st, ADD, fields, pCtx);
}
} else if (lookAhead() == '-') {
name = new String(expr, st, trimLeft(cursor) - st);
st = cursor += 2;
if (!isNextIdentifierOrLiteral()) {
throw new CompileException("unexpected symbol '" + expr[cursor] + "'", expr, st);
}
captureToEOS();
if (pCtx != null && (idx = pCtx.variableIndexOf(name)) != -1) {
return lastNode = new IndexedOperativeAssign(expr, st, cursor - st, SUB, idx, fields, pCtx);
} else {
return lastNode = new OperativeAssign(name, expr, st, cursor - st, SUB, fields, pCtx);
}
}
if (greedy && lookAhead() != '=') {
cursor++;
if (union) {
captureToEOS();
return lastNode = new DeepAssignmentNode(expr, st, cursor - st, fields | ASTNode.ASSIGN, pCtx);
} else if (lastWasIdentifier) {
return procTypedNode(false);
} else if (pCtx != null && ((idx = pCtx.variableIndexOf(t)) != -1 && (pCtx.isIndexAllocation()))) {
captureToEOS();
IndexedAssignmentNode ian = new IndexedAssignmentNode(expr, st = trimRight(st), trimLeft(cursor) - st, ASTNode.ASSIGN, idx, pCtx);
if (idx == -1) {
pCtx.addIndexedInput(t = ian.getAssignmentVar());
ian.setRegister(pCtx.variableIndexOf(t));
}
return lastNode = ian;
} else {
captureToEOS();
return lastNode = new AssignmentNode(expr, st, cursor - st, fields | ASTNode.ASSIGN, pCtx);
}
}
break CaptureLoop;
default:
if (cursor != end) {
if (isIdentifierPart(expr[cursor])) {
if (!union) {
break CaptureLoop;
}
cursor++;
while (cursor != end && isIdentifierPart(expr[cursor])) cursor++;
} else if ((cursor + 1) != end && isIdentifierPart(expr[cursor + 1])) {
break CaptureLoop;
} else {
cursor++;
}
} else {
break CaptureLoop;
}
}
}
/**
* Produce the token.
*/
trimWhitespace();
return createPropertyToken(st, cursor);
} else {
switch(expr[cursor]) {
case '.':
{
cursor++;
if (isDigit(expr[cursor])) {
capture = true;
continue;
}
expectNextChar_IW('{');
return lastNode = new ThisWithNode(expr, st, cursor - st - 1, cursor + 1, (cursor = balancedCaptureWithLineAccounting(expr, cursor, end, '{', pCtx) + 1) - 3, fields, pCtx);
}
case '@':
{
st++;
captureToEOT();
if (pCtx == null || (pCtx.getInterceptors() == null || !pCtx.getInterceptors().containsKey(name = new String(expr, st, cursor - st)))) {
throw new CompileException("reference to undefined interceptor: " + new String(expr, st, cursor - st), expr, st);
}
return lastNode = new InterceptorWrapper(pCtx.getInterceptors().get(name), nextToken());
}
case '=':
return createOperator(expr, st, (cursor += 2));
case '-':
if (lookAhead() == '-') {
cursor += 2;
skipWhitespace();
st = cursor;
captureIdentifier();
name = new String(subArray(st, cursor));
if (pCtx != null && (idx = pCtx.variableIndexOf(name)) != -1) {
return lastNode = new IndexedPreFixDecNode(idx, pCtx);
} else {
return lastNode = new PreFixDecNode(name, pCtx);
}
} else if ((cursor == start || (lastNode != null && (lastNode instanceof BooleanNode || lastNode.isOperator()))) && !isDigit(lookAhead())) {
captureToEOT();
return new Sign(expr, st, cursor - st, fields, pCtx);
} else if ((cursor != start && !isWhitespace(expr[cursor - 1]) && (!(lastNode != null && (lastNode instanceof BooleanNode || lastNode.isOperator())))) || !isDigit(lookAhead())) {
return createOperator(expr, st, cursor++ + 1);
} else if ((cursor - 1) != start || (!isDigit(expr[cursor - 1])) && isDigit(lookAhead())) {
cursor++;
break;
} else {
throw new CompileException("not a statement", expr, st);
}
case '+':
if (lookAhead() == '+') {
cursor += 2;
skipWhitespace();
st = cursor;
captureIdentifier();
name = new String(subArray(st, cursor));
if (pCtx != null && (idx = pCtx.variableIndexOf(name)) != -1) {
return lastNode = new IndexedPreFixIncNode(idx, pCtx);
} else {
return lastNode = new PreFixIncNode(name, pCtx);
}
}
return createOperator(expr, st, cursor++ + 1);
case '*':
if (lookAhead() == '*') {
cursor++;
}
return createOperator(expr, st, cursor++ + 1);
case ';':
cursor++;
lastWasIdentifier = false;
return lastNode = new EndOfStatement();
case '#':
case '/':
case '?':
case ':':
case '^':
case '%':
{
return createOperator(expr, st, cursor++ + 1);
}
case '(':
{
cursor++;
boolean singleToken = true;
skipWhitespace();
for (brace = 1; cursor != end && brace != 0; cursor++) {
switch(expr[cursor]) {
case '(':
brace++;
break;
case ')':
brace--;
break;
case '\'':
cursor = captureStringLiteral('\'', expr, cursor, end);
break;
case '"':
cursor = captureStringLiteral('"', expr, cursor, end);
break;
case 'i':
if (brace == 1 && isWhitespace(lookBehind()) && lookAhead() == 'n' && isWhitespace(lookAhead(2))) {
for (int level = brace; cursor != end; cursor++) {
switch(expr[cursor]) {
case '(':
brace++;
break;
case ')':
if (--brace < level) {
cursor++;
if (tokenContinues()) {
lastNode = new Fold(expr, trimRight(st + 1), cursor - st - 2, fields, pCtx);
if (expr[st = cursor] == '.')
st++;
captureToEOT();
return lastNode = new Union(expr, st = trimRight(st), cursor - st, fields, lastNode);
} else {
return lastNode = new Fold(expr, trimRight(st + 1), cursor - st - 2, fields, pCtx);
}
}
break;
case '\'':
cursor = captureStringLiteral('\'', expr, cursor, end);
break;
case '"':
cursor = captureStringLiteral('\"', expr, cursor, end);
break;
}
}
throw new CompileException("unterminated projection; closing parathesis required", expr, st);
}
break;
default:
if (expr[cursor] != '.') {
switch(expr[cursor]) {
case '[':
case ']':
break;
default:
if (!(isIdentifierPart(expr[cursor]) || expr[cursor] == '.')) {
singleToken = false;
}
}
}
}
}
if (brace != 0) {
throw new CompileException("unbalanced braces in expression: (" + brace + "):", expr, st);
}
tmpStart = -1;
if (singleToken) {
int _st;
TypeDescriptor tDescr = new TypeDescriptor(expr, _st = trimRight(st + 1), trimLeft(cursor - 1) - _st, fields);
Class cls;
try {
if (tDescr.isClass() && (cls = getClassReference(pCtx, tDescr)) != null) {
st = cursor;
captureToEOS();
return lastNode = new TypeCast(expr, st, cursor - st, cls, fields, pCtx);
}
} catch (ClassNotFoundException e) {
// fallthrough
}
}
if (tmpStart != -1) {
return handleUnion(handleSubstatement(new Substatement(expr, tmpStart, cursor - tmpStart, fields, pCtx)));
} else {
return handleUnion(handleSubstatement(new Substatement(expr, st = trimRight(st + 1), trimLeft(cursor - 1) - st, fields, pCtx)));
}
}
case '}':
case ']':
case ')':
{
throw new CompileException("unbalanced braces", expr, st);
}
case '>':
{
switch(expr[cursor + 1]) {
case '>':
if (expr[cursor += 2] == '>')
cursor++;
return createOperator(expr, st, cursor);
case '=':
return createOperator(expr, st, cursor += 2);
default:
return createOperator(expr, st, ++cursor);
}
}
case '<':
{
if (expr[++cursor] == '<') {
if (expr[++cursor] == '<')
cursor++;
return createOperator(expr, st, cursor);
} else if (expr[cursor] == '=') {
return createOperator(expr, st, ++cursor);
} else {
return createOperator(expr, st, cursor);
}
}
case '\'':
case '"':
lastNode = new LiteralNode(handleStringEscapes(subset(expr, st + 1, (cursor = captureStringLiteral(expr[cursor], expr, cursor, end)) - st - 1)), String.class);
cursor++;
if (tokenContinues()) {
return lastNode = handleUnion(lastNode);
}
return lastNode;
case '&':
{
if (expr[cursor++ + 1] == '&') {
return createOperator(expr, st, ++cursor);
} else {
return createOperator(expr, st, cursor);
}
}
case '|':
{
if (expr[cursor++ + 1] == '|') {
return createOperator(expr, st, ++cursor);
} else {
return createOperator(expr, st, cursor);
}
}
case '~':
if ((cursor++ - 1 != 0 || !isIdentifierPart(lookBehind())) && isDigit(expr[cursor])) {
st = cursor;
captureToEOT();
return lastNode = new Invert(expr, st, cursor - st, fields, pCtx);
} else if (expr[cursor] == '(') {
st = cursor--;
captureToEOT();
return lastNode = new Invert(expr, st, cursor - st, fields, pCtx);
} else {
if (expr[cursor] == '=')
cursor++;
return createOperator(expr, st, cursor);
}
case '!':
{
++cursor;
if (isNextIdentifier()) {
if (lastNode != null && !lastNode.isOperator()) {
throw new CompileException("unexpected operator '!'", expr, st);
}
st = cursor;
captureToEOT();
if ("new".equals(name = new String(expr, st, cursor - st)) || "isdef".equals(name)) {
captureToEOT();
return lastNode = new Negation(expr, st, cursor - st, fields, pCtx);
} else {
return lastNode = new Negation(expr, st, cursor - st, fields, pCtx);
}
} else if (expr[cursor] == '(') {
st = cursor--;
captureToEOT();
return lastNode = new Negation(expr, st, cursor - st, fields, pCtx);
} else if (expr[cursor] != '=')
throw new CompileException("unexpected operator '!'", expr, st, null);
else {
return createOperator(expr, st, ++cursor);
}
}
case '[':
case '{':
cursor = balancedCaptureWithLineAccounting(expr, cursor, end, expr[cursor], pCtx) + 1;
if (tokenContinues()) {
lastNode = new InlineCollectionNode(expr, st, cursor - st, fields, pCtx);
st = cursor;
captureToEOT();
if (expr[st] == '.')
st++;
return lastNode = new Union(expr, st, cursor - st, fields, lastNode);
} else {
return lastNode = new InlineCollectionNode(expr, st, cursor - st, fields, pCtx);
}
default:
cursor++;
}
}
}
if (st == cursor)
return null;
else
return createPropertyToken(st, cursor);
} catch (RedundantCodeException e) {
return nextToken();
} catch (NumberFormatException e) {
throw new CompileException("badly formatted number: " + e.getMessage(), expr, st, e);
} catch (StringIndexOutOfBoundsException e) {
throw new CompileException("unexpected end of statement", expr, cursor, e);
} catch (ArrayIndexOutOfBoundsException e) {
throw new CompileException("unexpected end of statement", expr, cursor, e);
} catch (CompileException e) {
throw ErrorUtil.rewriteIfNeeded(e, expr, cursor);
}
}
use of org.mvel2.ast.InterceptorWrapper in project mvel by mvel.
the class AbstractParser method nextToken.
/**
* Retrieve the next token in the expression.
*
* @return -
*/
protected ASTNode nextToken() {
try {
/**
* If the cursor is at the end of the expression, we have nothing more to do:
* return null.
*/
if (!splitAccumulator.isEmpty()) {
lastNode = (ASTNode) splitAccumulator.pop();
if (cursor >= end && lastNode instanceof EndOfStatement) {
return nextToken();
} else {
return lastNode;
}
} else if (cursor >= end) {
return null;
}
int brace, idx;
int tmpStart;
String name;
/**
* Because of parser recursion for sub-expression parsing, we sometimes need to remain
* certain field states. We do not reset for assignments, boolean mode, list creation or
* a capture only mode.
*/
boolean capture = false, union = false;
if ((fields & ASTNode.COMPILE_IMMEDIATE) != 0) {
debugSymbols = pCtx.isDebugSymbols();
}
if (debugSymbols) {
if (!lastWasLineLabel) {
if (pCtx.getSourceFile() == null) {
throw new CompileException("unable to produce debugging symbols: source name must be provided.", expr, st);
}
if (!pCtx.isLineMapped(pCtx.getSourceFile())) {
pCtx.initLineMapping(pCtx.getSourceFile(), expr);
}
skipWhitespace();
if (cursor >= end) {
return null;
}
int line = pCtx.getLineFor(pCtx.getSourceFile(), cursor);
if (!pCtx.isVisitedLine(pCtx.getSourceFile(), pCtx.setLineCount(line)) && !pCtx.isBlockSymbols()) {
lastWasLineLabel = true;
pCtx.visitLine(pCtx.getSourceFile(), line);
return lastNode = pCtx.setLastLineLabel(new LineLabel(pCtx.getSourceFile(), line, pCtx));
}
} else {
lastWasComment = lastWasLineLabel = false;
}
}
/**
* Skip any whitespace currently under the starting point.
*/
skipWhitespace();
/**
* From here to the end of the method is the core MVEL parsing code. Fiddling around here is asking for
* trouble unless you really know what you're doing.
*/
st = cursor;
Mainloop: while (cursor != end) {
if (isIdentifierPart(expr[cursor])) {
capture = true;
cursor++;
while (cursor != end && isIdentifierPart(expr[cursor])) cursor++;
}
if (capture) {
String t;
if (OPERATORS.containsKey(t = new String(expr, st, cursor - st)) && !Character.isDigit(expr[st])) {
switch(OPERATORS.get(t)) {
case NEW:
if (!isIdentifierPart(expr[st = cursor = trimRight(cursor)])) {
throw new CompileException("unexpected character (expected identifier): " + expr[cursor], expr, st);
}
/**
* Capture the beginning part of the token.
*/
do {
captureToNextTokenJunction();
skipWhitespace();
} while (cursor < end && expr[cursor] == '[');
/**
* If it's not a dimentioned array, continue capturing if necessary.
*/
if (cursor < end && !lastNonWhite(']'))
captureToEOT();
TypeDescriptor descr = new TypeDescriptor(expr, st, trimLeft(cursor) - st, fields);
if (pCtx.getFunctions().containsKey(descr.getClassName())) {
return lastNode = new NewObjectPrototype(pCtx, pCtx.getFunction(descr.getClassName()));
}
if (pCtx.hasProtoImport(descr.getClassName())) {
return lastNode = new NewPrototypeNode(descr, pCtx);
}
lastNode = new NewObjectNode(descr, fields, pCtx);
skipWhitespace();
if (cursor != end && expr[cursor] == '{') {
if (!((NewObjectNode) lastNode).getTypeDescr().isUndimensionedArray()) {
throw new CompileException("conflicting syntax: dimensioned array with initializer block", expr, st);
}
st = cursor;
Class egressType = lastNode.getEgressType();
if (egressType == null) {
try {
egressType = getClassReference(pCtx, descr);
} catch (ClassNotFoundException e) {
throw new CompileException("could not instantiate class", expr, st, e);
}
}
cursor = balancedCaptureWithLineAccounting(expr, st, end, expr[cursor], pCtx) + 1;
if (tokenContinues()) {
lastNode = new InlineCollectionNode(expr, st, cursor - st, fields, egressType, pCtx);
st = cursor;
captureToEOT();
return lastNode = new Union(expr, st + 1, cursor, fields, lastNode, pCtx);
} else {
return lastNode = new InlineCollectionNode(expr, st, cursor - st, fields, egressType, pCtx);
}
} else if (((NewObjectNode) lastNode).getTypeDescr().isUndimensionedArray()) {
throw new CompileException("array initializer expected", expr, st);
}
st = cursor;
return lastNode;
case ASSERT:
st = cursor = trimRight(cursor);
captureToEOS();
return lastNode = new AssertNode(expr, st, cursor-- - st, fields, pCtx);
case RETURN:
st = cursor = trimRight(cursor);
captureToEOS();
return lastNode = new ReturnNode(expr, st, cursor - st, fields, pCtx);
case IF:
return captureCodeBlock(ASTNode.BLOCK_IF);
case ELSE:
throw new CompileException("else without if", expr, st);
case FOREACH:
return captureCodeBlock(ASTNode.BLOCK_FOREACH);
case WHILE:
return captureCodeBlock(ASTNode.BLOCK_WHILE);
case UNTIL:
return captureCodeBlock(ASTNode.BLOCK_UNTIL);
case FOR:
return captureCodeBlock(ASTNode.BLOCK_FOR);
case WITH:
return captureCodeBlock(ASTNode.BLOCK_WITH);
case DO:
return captureCodeBlock(ASTNode.BLOCK_DO);
case STACKLANG:
return captureCodeBlock(STACKLANG);
case PROTO:
return captureCodeBlock(PROTO);
case ISDEF:
st = cursor = trimRight(cursor);
captureToNextTokenJunction();
return lastNode = new IsDef(expr, st, cursor - st, pCtx);
case IMPORT:
st = cursor = trimRight(cursor);
captureToEOS();
ImportNode importNode = new ImportNode(expr, st, cursor - st, pCtx);
if (importNode.isPackageImport()) {
pCtx.addPackageImport(importNode.getPackageImport());
} else {
pCtx.addImport(importNode.getImportClass().getSimpleName(), importNode.getImportClass());
}
return lastNode = importNode;
case IMPORT_STATIC:
st = cursor = trimRight(cursor);
captureToEOS();
StaticImportNode staticImportNode = new StaticImportNode(expr, st, trimLeft(cursor) - st, pCtx);
pCtx.addImport(staticImportNode.getMethod().getName(), staticImportNode.getMethod());
return lastNode = staticImportNode;
case FUNCTION:
lastNode = captureCodeBlock(FUNCTION);
st = cursor + 1;
return lastNode;
case UNTYPED_VAR:
int end;
st = cursor + 1;
while (true) {
captureToEOT();
end = cursor;
skipWhitespace();
if (cursor != end && expr[cursor] == '=') {
if (end == (cursor = st))
throw new CompileException("illegal use of reserved word: var", expr, st);
continue Mainloop;
} else {
name = new String(expr, st, end - st);
if (pCtx != null && (idx = pCtx.variableIndexOf(name)) != -1) {
splitAccumulator.add(lastNode = new IndexedDeclTypedVarNode(idx, st, end - st, Object.class, pCtx));
} else {
splitAccumulator.add(lastNode = new DeclTypedVarNode(name, expr, st, end - st, Object.class, fields, pCtx));
}
}
if (cursor == this.end || expr[cursor] != ',')
break;
else {
cursor++;
skipWhitespace();
st = cursor;
}
}
return (ASTNode) splitAccumulator.pop();
case CONTAINS:
lastWasIdentifier = false;
return lastNode = new OperatorNode(Operator.CONTAINS, expr, st, pCtx);
}
}
skipWhitespace();
/**
* If we *were* capturing a token, and we just hit a non-identifier
* character, we stop and figure out what to do.
*/
if (cursor != end && expr[cursor] == '(') {
cursor = balancedCaptureWithLineAccounting(expr, cursor, end, '(', pCtx) + 1;
}
/**
* If we encounter any of the following cases, we are still dealing with
* a contiguous token.
*/
CaptureLoop: while (cursor != end) {
switch(expr[cursor]) {
case '.':
union = true;
cursor++;
skipWhitespace();
continue;
case '?':
if (lookToLast() == '.' || cursor == start) {
union = true;
cursor++;
continue;
} else {
break CaptureLoop;
}
case '+':
switch(lookAhead()) {
case '+':
name = new String(subArray(st, trimLeft(cursor)));
if (pCtx != null && (idx = pCtx.variableIndexOf(name)) != -1) {
lastNode = new IndexedPostFixIncNode(idx, pCtx);
} else {
lastNode = new PostFixIncNode(name, pCtx);
}
cursor += 2;
expectEOS();
return lastNode;
case '=':
name = createStringTrimmed(expr, st, cursor - st);
st = cursor += 2;
captureToEOS();
if (union) {
return lastNode = new DeepAssignmentNode(expr, st = trimRight(st), trimLeft(cursor) - st, fields, ADD, name, pCtx);
} else if (pCtx != null && (idx = pCtx.variableIndexOf(name)) != -1) {
return lastNode = new IndexedAssignmentNode(expr, st, cursor - st, fields, ADD, name, idx, pCtx);
} else {
return lastNode = new OperativeAssign(name, expr, st = trimRight(st), trimLeft(cursor) - st, ADD, fields, pCtx);
}
}
if (isDigit(lookAhead()) && cursor > 1 && (expr[cursor - 1] == 'E' || expr[cursor - 1] == 'e') && isDigit(expr[cursor - 2])) {
cursor++;
// capture = true;
continue Mainloop;
}
break CaptureLoop;
case '-':
switch(lookAhead()) {
case '-':
name = new String(subArray(st, trimLeft(cursor)));
if (pCtx != null && (idx = pCtx.variableIndexOf(name)) != -1) {
lastNode = new IndexedPostFixDecNode(idx, pCtx);
} else {
lastNode = new PostFixDecNode(name, pCtx);
}
cursor += 2;
expectEOS();
return lastNode;
case '=':
name = new String(expr, st, trimLeft(cursor) - st);
st = cursor += 2;
captureToEOS();
if (union) {
return lastNode = new DeepAssignmentNode(expr, st, cursor - st, fields, SUB, t, pCtx);
} else if (pCtx != null && (idx = pCtx.variableIndexOf(name)) != -1) {
return lastNode = new IndexedOperativeAssign(expr, st, cursor - st, SUB, idx, fields, pCtx);
} else {
return lastNode = new OperativeAssign(name, expr, st, cursor - st, SUB, fields, pCtx);
}
}
if (isDigit(lookAhead()) && cursor > 1 && (expr[cursor - 1] == 'E' || expr[cursor - 1] == 'e') && isDigit(expr[cursor - 2])) {
cursor++;
capture = true;
continue Mainloop;
}
break CaptureLoop;
/**
* Exit immediately for any of these cases.
*/
case '!':
case ',':
case '"':
case '\'':
case ';':
case ':':
break CaptureLoop;
// special compact code for recursive parses
case '\u00AB':
case '\u00BB':
case '\u00AC':
case '&':
case '^':
case '|':
case '*':
case '/':
case '%':
char op = expr[cursor];
if (lookAhead() == '=') {
name = new String(expr, st, trimLeft(cursor) - st);
st = cursor += 2;
captureToEOS();
if (union) {
return lastNode = new DeepAssignmentNode(expr, st, cursor - st, fields, opLookup(op), t, pCtx);
} else if (pCtx != null && (idx = pCtx.variableIndexOf(name)) != -1) {
return lastNode = new IndexedOperativeAssign(expr, st, cursor - st, opLookup(op), idx, fields, pCtx);
} else {
return lastNode = new OperativeAssign(name, expr, st, cursor - st, opLookup(op), fields, pCtx);
}
}
break CaptureLoop;
case '<':
if ((lookAhead() == '<' && lookAhead(2) == '=')) {
name = new String(expr, st, trimLeft(cursor) - st);
st = cursor += 3;
captureToEOS();
if (union) {
return lastNode = new DeepAssignmentNode(expr, st, cursor - st, fields, BW_SHIFT_LEFT, t, pCtx);
} else if (pCtx != null && (idx = pCtx.variableIndexOf(name)) != -1) {
return lastNode = new IndexedOperativeAssign(expr, st, cursor - st, BW_SHIFT_LEFT, idx, fields, pCtx);
} else {
return lastNode = new OperativeAssign(name, expr, st, cursor - st, BW_SHIFT_LEFT, fields, pCtx);
}
}
break CaptureLoop;
case '>':
if (lookAhead() == '>') {
if (lookAhead(2) == '=') {
name = new String(expr, st, trimLeft(cursor) - st);
st = cursor += 3;
captureToEOS();
if (union) {
return lastNode = new DeepAssignmentNode(expr, st, cursor - st, fields, BW_SHIFT_RIGHT, t, pCtx);
} else if (pCtx != null && (idx = pCtx.variableIndexOf(name)) != -1) {
return lastNode = new IndexedOperativeAssign(expr, st, cursor - st, BW_SHIFT_RIGHT, idx, fields, pCtx);
} else {
return lastNode = new OperativeAssign(name, expr, st, cursor - st, BW_SHIFT_RIGHT, fields, pCtx);
}
} else if ((lookAhead(2) == '>' && lookAhead(3) == '=')) {
name = new String(expr, st, trimLeft(cursor) - st);
st = cursor += 4;
captureToEOS();
if (union) {
return lastNode = new DeepAssignmentNode(expr, st, cursor - st, fields, BW_USHIFT_RIGHT, t, pCtx);
} else if (pCtx != null && (idx = pCtx.variableIndexOf(name)) != -1) {
return lastNode = new IndexedOperativeAssign(expr, st, cursor - st, BW_USHIFT_RIGHT, idx, fields, pCtx);
} else {
return lastNode = new OperativeAssign(name, expr, st, cursor - st, BW_USHIFT_RIGHT, fields, pCtx);
}
}
}
break CaptureLoop;
case '(':
cursor = balancedCaptureWithLineAccounting(expr, cursor, end, '(', pCtx) + 1;
continue;
case '[':
cursor = balancedCaptureWithLineAccounting(expr, cursor, end, '[', pCtx) + 1;
continue;
case '{':
if (!union)
break CaptureLoop;
cursor = balancedCaptureWithLineAccounting(expr, cursor, end, '{', pCtx) + 1;
continue;
case '~':
if (lookAhead() == '=') {
// tmp = subArray(start, trimLeft(cursor));
tmpStart = st;
int tmpOffset = cursor - st;
st = cursor += 2;
captureToEOT();
return lastNode = new RegExMatch(expr, tmpStart, tmpOffset, fields, st, cursor - st, pCtx);
}
break CaptureLoop;
case '=':
if (lookAhead() == '+') {
name = new String(expr, st, trimLeft(cursor) - st);
st = cursor += 2;
if (!isNextIdentifierOrLiteral()) {
throw new CompileException("unexpected symbol '" + expr[cursor] + "'", expr, st);
}
captureToEOS();
if (pCtx != null && (idx = pCtx.variableIndexOf(name)) != -1) {
return lastNode = new IndexedOperativeAssign(expr, st, cursor - st, ADD, idx, fields, pCtx);
} else {
return lastNode = new OperativeAssign(name, expr, st, cursor - st, ADD, fields, pCtx);
}
} else if (lookAhead() == '-') {
name = new String(expr, st, trimLeft(cursor) - st);
st = cursor += 2;
if (!isNextIdentifierOrLiteral()) {
throw new CompileException("unexpected symbol '" + expr[cursor] + "'", expr, st);
}
captureToEOS();
if (pCtx != null && (idx = pCtx.variableIndexOf(name)) != -1) {
return lastNode = new IndexedOperativeAssign(expr, st, cursor - st, SUB, idx, fields, pCtx);
} else {
return lastNode = new OperativeAssign(name, expr, st, cursor - st, SUB, fields, pCtx);
}
}
if (greedy && lookAhead() != '=') {
cursor++;
if (union) {
captureToEOS();
return lastNode = new DeepAssignmentNode(expr, st, cursor - st, fields | ASTNode.ASSIGN, pCtx);
} else if (lastWasIdentifier) {
return procTypedNode(false);
} else if (pCtx != null && ((idx = pCtx.variableIndexOf(t)) != -1 && (pCtx.isIndexAllocation()))) {
captureToEOS();
IndexedAssignmentNode ian = new IndexedAssignmentNode(expr, st = trimRight(st), trimLeft(cursor) - st, ASTNode.ASSIGN, idx, pCtx);
if (idx == -1) {
pCtx.addIndexedInput(t = ian.getVarName());
ian.setRegister(pCtx.variableIndexOf(t));
}
return lastNode = ian;
} else {
captureToEOS();
return lastNode = new AssignmentNode(expr, st, cursor - st, fields | ASTNode.ASSIGN, pCtx);
}
}
break CaptureLoop;
default:
if (cursor != end) {
if (isIdentifierPart(expr[cursor])) {
if (!union) {
break CaptureLoop;
}
cursor++;
while (cursor != end && isIdentifierPart(expr[cursor])) cursor++;
} else if ((cursor + 1) != end && isIdentifierPart(expr[cursor + 1])) {
break CaptureLoop;
} else {
cursor++;
}
} else {
break CaptureLoop;
}
}
}
/**
* Produce the token.
*/
trimWhitespace();
return createPropertyToken(st, cursor);
} else {
switch(expr[cursor]) {
case '.':
{
cursor++;
if (isDigit(expr[cursor])) {
capture = true;
continue;
}
expectNextChar_IW('{');
return lastNode = new ThisWithNode(expr, st, cursor - st - 1, cursor + 1, (cursor = balancedCaptureWithLineAccounting(expr, cursor, end, '{', pCtx) + 1) - 3, fields, pCtx);
}
case '@':
{
st++;
captureToEOT();
if (pCtx == null || (pCtx.getInterceptors() == null || !pCtx.getInterceptors().containsKey(name = new String(expr, st, cursor - st)))) {
throw new CompileException("reference to undefined interceptor: " + new String(expr, st, cursor - st), expr, st);
}
return lastNode = new InterceptorWrapper(pCtx.getInterceptors().get(name), nextToken(), pCtx);
}
case '=':
return createOperator(expr, st, (cursor += 2));
case '-':
if (lookAhead() == '-') {
cursor += 2;
skipWhitespace();
st = cursor;
captureIdentifier();
name = new String(subArray(st, cursor));
if (pCtx != null && (idx = pCtx.variableIndexOf(name)) != -1) {
return lastNode = new IndexedPreFixDecNode(idx, pCtx);
} else {
return lastNode = new PreFixDecNode(name, pCtx);
}
} else if ((cursor == start || (lastNode != null && (lastNode instanceof BooleanNode || lastNode.isOperator()))) && !isDigit(lookAhead())) {
cursor += 1;
captureToEOT();
return new Sign(expr, st, cursor - st, fields, pCtx);
} else if ((cursor != start && (lastNode != null && !(lastNode instanceof BooleanNode || lastNode.isOperator()))) || !isDigit(lookAhead())) {
return createOperator(expr, st, cursor++ + 1);
} else if ((cursor - 1) != start || (!isDigit(expr[cursor - 1])) && isDigit(lookAhead())) {
cursor++;
break;
} else {
throw new CompileException("not a statement", expr, st);
}
case '+':
if (lookAhead() == '+') {
cursor += 2;
skipWhitespace();
st = cursor;
captureIdentifier();
name = new String(subArray(st, cursor));
if (pCtx != null && (idx = pCtx.variableIndexOf(name)) != -1) {
return lastNode = new IndexedPreFixIncNode(idx, pCtx);
} else {
return lastNode = new PreFixIncNode(name, pCtx);
}
}
return createOperator(expr, st, cursor++ + 1);
case '*':
if (lookAhead() == '*') {
cursor++;
}
return createOperator(expr, st, cursor++ + 1);
case ';':
cursor++;
lastWasIdentifier = false;
return lastNode = new EndOfStatement(pCtx);
case '?':
if (cursor == start) {
cursor++;
continue;
}
case '#':
case '/':
case ':':
case '^':
case '%':
{
return createOperator(expr, st, cursor++ + 1);
}
case '(':
{
cursor++;
boolean singleToken = true;
skipWhitespace();
for (brace = 1; cursor != end && brace != 0; cursor++) {
switch(expr[cursor]) {
case '(':
brace++;
break;
case ')':
brace--;
break;
case '\'':
cursor = captureStringLiteral('\'', expr, cursor, end);
break;
case '"':
cursor = captureStringLiteral('"', expr, cursor, end);
break;
case 'i':
if (brace == 1 && isWhitespace(lookBehind()) && lookAhead() == 'n' && isWhitespace(lookAhead(2))) {
for (int level = brace; cursor != end; cursor++) {
switch(expr[cursor]) {
case '(':
brace++;
break;
case ')':
if (--brace < level) {
cursor++;
if (tokenContinues()) {
lastNode = new Fold(expr, trimRight(st + 1), cursor - st - 2, fields, pCtx);
if (expr[st = cursor] == '.')
st++;
captureToEOT();
return lastNode = new Union(expr, st = trimRight(st), cursor - st, fields, lastNode, pCtx);
} else {
return lastNode = new Fold(expr, trimRight(st + 1), cursor - st - 2, fields, pCtx);
}
}
break;
case '\'':
cursor = captureStringLiteral('\'', expr, cursor, end);
break;
case '"':
cursor = captureStringLiteral('\"', expr, cursor, end);
break;
}
}
throw new CompileException("unterminated projection; closing parathesis required", expr, st);
}
break;
default:
if (expr[cursor] != '.') {
switch(expr[cursor]) {
case '[':
case ']':
break;
default:
if (!(isIdentifierPart(expr[cursor]) || expr[cursor] == '.')) {
singleToken = false;
}
}
}
}
}
if (brace != 0) {
throw new CompileException("unbalanced braces in expression: (" + brace + "):", expr, st);
}
tmpStart = -1;
if (singleToken) {
int _st;
TypeDescriptor tDescr = new TypeDescriptor(expr, _st = trimRight(st + 1), trimLeft(cursor - 1) - _st, fields);
Class cls;
try {
if (tDescr.isClass() && (cls = getClassReference(pCtx, tDescr)) != null) {
// lookahead to check if it could be a real cast
boolean isCast = false;
for (int i = cursor; i < expr.length; i++) {
if (expr[i] == ' ' || expr[i] == '\t')
continue;
isCast = isIdentifierPart(expr[i]) || expr[i] == '\'' || expr[i] == '"' || expr[i] == '(';
break;
}
if (isCast) {
st = cursor;
captureToEOT();
return lastNode = new TypeCast(expr, st, cursor - st, cls, fields, pCtx);
}
}
} catch (ClassNotFoundException e) {
// fallthrough
}
}
if (tmpStart != -1) {
return handleUnion(handleSubstatement(new Substatement(expr, tmpStart, cursor - tmpStart, fields, pCtx)));
} else {
return handleUnion(handleSubstatement(new Substatement(expr, st = trimRight(st + 1), trimLeft(cursor - 1) - st, fields, pCtx)));
}
}
case '}':
case ']':
case ')':
{
throw new CompileException("unbalanced braces", expr, st);
}
case '>':
{
switch(expr[cursor + 1]) {
case '>':
if (expr[cursor += 2] == '>')
cursor++;
return createOperator(expr, st, cursor);
case '=':
return createOperator(expr, st, cursor += 2);
default:
return createOperator(expr, st, ++cursor);
}
}
case '<':
{
if (expr[++cursor] == '<') {
if (expr[++cursor] == '<')
cursor++;
return createOperator(expr, st, cursor);
} else if (expr[cursor] == '=') {
return createOperator(expr, st, ++cursor);
} else {
return createOperator(expr, st, cursor);
}
}
case '\'':
case '"':
lastNode = new LiteralNode(handleStringEscapes(subset(expr, st + 1, (cursor = captureStringLiteral(expr[cursor], expr, cursor, end)) - st - 1)), String.class, pCtx);
cursor++;
if (tokenContinues()) {
return lastNode = handleUnion(lastNode);
}
return lastNode;
case '&':
{
if (expr[cursor++ + 1] == '&') {
return createOperator(expr, st, ++cursor);
} else {
return createOperator(expr, st, cursor);
}
}
case '|':
{
if (expr[cursor++ + 1] == '|') {
return createOperator(expr, st, ++cursor);
} else {
return createOperator(expr, st, cursor);
}
}
case '~':
if ((cursor++ - 1 != 0 || !isIdentifierPart(lookBehind())) && isDigit(expr[cursor])) {
st = cursor;
captureToEOT();
return lastNode = new Invert(expr, st, cursor - st, fields, pCtx);
} else if (expr[cursor] == '(') {
st = cursor--;
captureToEOT();
return lastNode = new Invert(expr, st, cursor - st, fields, pCtx);
} else {
if (expr[cursor] == '=')
cursor++;
return createOperator(expr, st, cursor);
}
case '!':
{
++cursor;
if (isNextIdentifier()) {
if (lastNode != null && !lastNode.isOperator()) {
throw new CompileException("unexpected operator '!'", expr, st);
}
st = cursor;
captureToEOT();
if ("new".equals(name = new String(expr, st, cursor - st)) || "isdef".equals(name)) {
captureToEOT();
return lastNode = new Negation(expr, st, cursor - st, fields, pCtx);
} else {
return lastNode = new Negation(expr, st, cursor - st, fields, pCtx);
}
} else if (expr[cursor] == '(') {
st = cursor--;
captureToEOT();
return lastNode = new Negation(expr, st, cursor - st, fields, pCtx);
} else if (expr[cursor] == '!') {
// just ignore a double negation
++cursor;
return nextToken();
} else if (expr[cursor] != '=')
throw new CompileException("unexpected operator '!'", expr, st, null);
else {
return createOperator(expr, st, ++cursor);
}
}
case '[':
case '{':
cursor = balancedCaptureWithLineAccounting(expr, cursor, end, expr[cursor], pCtx) + 1;
if (tokenContinues()) {
lastNode = new InlineCollectionNode(expr, st, cursor - st, fields, pCtx);
st = cursor;
captureToEOT();
if (expr[st] == '.')
st++;
return lastNode = new Union(expr, st, cursor - st, fields, lastNode, pCtx);
} else {
return lastNode = new InlineCollectionNode(expr, st, cursor - st, fields, pCtx);
}
default:
cursor++;
}
}
}
if (st == cursor)
return null;
else
return createPropertyToken(st, cursor);
} catch (RedundantCodeException e) {
return nextToken();
} catch (NumberFormatException e) {
throw new CompileException("badly formatted number: " + e.getMessage(), expr, st, e);
} catch (StringIndexOutOfBoundsException e) {
throw new CompileException("unexpected end of statement", expr, cursor, e);
} catch (ArrayIndexOutOfBoundsException e) {
throw new CompileException("unexpected end of statement", expr, cursor, e);
} catch (CompileException e) {
throw ErrorUtil.rewriteIfNeeded(e, expr, cursor);
}
}
Aggregations