Search in sources :

Example 1 with CompileException

use of org.mvel2.CompileException 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 '«':
                        case '»':
                        case '¬':
                        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);
    }
}
Also used : CompileException(org.mvel2.CompileException)

Example 2 with CompileException

use of org.mvel2.CompileException in project mvel by mikebrock.

the class AbstractParser method reduce.

/**
   * This method is called when we reach the point where we must subEval a trinary operation in the expression.
   * (ie. val1 op val2).  This is not the same as a binary operation, although binary operations would appear
   * to have 3 structures as well.  A binary structure (or also a junction in the expression) compares the
   * current state against 2 downrange structures (usually an op and a val).
   */
protected void reduce() {
    Object v1, v2;
    int operator;
    try {
        switch(operator = (Integer) stk.pop()) {
            case ADD:
            case SUB:
            case DIV:
            case MULT:
            case MOD:
            case EQUAL:
            case NEQUAL:
            case GTHAN:
            case LTHAN:
            case GETHAN:
            case LETHAN:
            case POWER:
                stk.op(operator);
                break;
            case AND:
                v1 = stk.pop();
                stk.push(((Boolean) stk.pop()) && ((Boolean) v1));
                break;
            case OR:
                v1 = stk.pop();
                stk.push(((Boolean) stk.pop()) || ((Boolean) v1));
                break;
            case CHOR:
                v1 = stk.pop();
                if (!isEmpty(v2 = stk.pop()) || !isEmpty(v1)) {
                    stk.clear();
                    stk.push(!isEmpty(v2) ? v2 : v1);
                    return;
                } else
                    stk.push(null);
                break;
            case REGEX:
                stk.push(java.util.regex.Pattern.compile(java.lang.String.valueOf(stk.pop())).matcher(java.lang.String.valueOf(stk.pop())).matches());
                break;
            case INSTANCEOF:
                stk.push(((Class) stk.pop()).isInstance(stk.pop()));
                break;
            case CONVERTABLE_TO:
                stk.push(org.mvel2.DataConversion.canConvert(stk.peek2().getClass(), (Class) stk.pop2()));
                break;
            case CONTAINS:
                stk.push(containsCheck(stk.peek2(), stk.pop2()));
                break;
            case BW_AND:
                stk.push(asInt(stk.peek2()) & asInt(stk.pop2()));
                break;
            case BW_OR:
                stk.push(asInt(stk.peek2()) | asInt(stk.pop2()));
                break;
            case BW_XOR:
                stk.push(asInt(stk.peek2()) ^ asInt(stk.pop2()));
                break;
            case BW_SHIFT_LEFT:
                stk.push(asInt(stk.peek2()) << asInt(stk.pop2()));
                break;
            case BW_USHIFT_LEFT:
                int iv2 = asInt(stk.peek2());
                if (iv2 < 0)
                    iv2 *= -1;
                stk.push(iv2 << asInt(stk.pop2()));
                break;
            case BW_SHIFT_RIGHT:
                stk.push(asInt(stk.peek2()) >> asInt(stk.pop2()));
                break;
            case BW_USHIFT_RIGHT:
                stk.push(asInt(stk.peek2()) >>> asInt(stk.pop2()));
                break;
            case SOUNDEX:
                stk.push(soundex(java.lang.String.valueOf(stk.pop())).equals(soundex(java.lang.String.valueOf(stk.pop()))));
                break;
            case SIMILARITY:
                stk.push(similarity(java.lang.String.valueOf(stk.pop()), java.lang.String.valueOf(stk.pop())));
                break;
        }
    } catch (ClassCastException e) {
        throw new CompileException("syntax error or incompatable types", expr, st, e);
    } catch (ArithmeticException e) {
        throw new CompileException("arithmetic error: " + e.getMessage(), expr, st, e);
    } catch (Exception e) {
        throw new CompileException("failed to subEval expression", expr, st, e);
    }
}
Also used : CompileException(org.mvel2.CompileException) CompileException(org.mvel2.CompileException)

Example 3 with CompileException

use of org.mvel2.CompileException in project mvel by mikebrock.

the class AbstractParser method arithmeticFunctionReduction.

/**
   * Reduce the current operations on the stack.
   *
   * @param operator the operator
   * @return a stack control code
   */
protected int arithmeticFunctionReduction(int operator) {
    ASTNode tk;
    int operator2;
    /**
     * If the next token is an operator, we check to see if it has a higher
     * precdence.
     */
    if ((tk = nextToken()) != null) {
        if (isArithmeticOperator(operator2 = tk.getOperator()) && PTABLE[operator2] > PTABLE[operator]) {
            stk.xswap();
            /**
         * The current arith. operator is of higher precedence the last.
         */
            tk = nextToken();
            /**
         * Check to see if we're compiling or executing interpretively.  If we're compiling, we really
         * need to stop if this is not a literal.
         */
            if (compileMode && !tk.isLiteral()) {
                splitAccumulator.push(tk, new OperatorNode(operator2, expr, st));
                return OP_OVERFLOW;
            }
            dStack.push(operator = operator2, tk.getReducedValue(ctx, ctx, variableFactory));
            while (true) {
                // look ahead again
                if ((tk = nextToken()) != null && (operator2 = tk.getOperator()) != -1 && operator2 != 37 && PTABLE[operator2] > PTABLE[operator]) {
                    if (dStack.isReduceable()) {
                        stk.copyx2(dStack);
                    }
                    /**
             * This operator is of higher precedence, or the same level precedence.  push to the RHS.
             */
                    dStack.push(operator = operator2, nextToken().getReducedValue(ctx, ctx, variableFactory));
                    continue;
                } else if (tk != null && operator2 != -1 && operator2 != 37) {
                    if (PTABLE[operator2] == PTABLE[operator]) {
                        if (!dStack.isEmpty())
                            dreduce();
                        else {
                            while (stk.isReduceable()) {
                                stk.xswap_op();
                            }
                        }
                        /**
               * This operator is of the same level precedence.  push to the RHS.
               */
                        dStack.push(operator = operator2, nextToken().getReducedValue(ctx, ctx, variableFactory));
                        continue;
                    } else {
                        /**
               * The operator doesn't have higher precedence. Therfore reduce the LHS.
               */
                        while (dStack.size() > 1) {
                            dreduce();
                        }
                        operator = tk.getOperator();
                        // Reduce the lesser or equal precedence operations.
                        while (stk.size() != 1 && stk.peek2() instanceof Integer && ((operator2 = (Integer) stk.peek2()) < PTABLE.length) && PTABLE[operator2] >= PTABLE[operator]) {
                            stk.xswap_op();
                        }
                    }
                } else {
                    if (dStack.size() > 1) {
                        dreduce();
                    }
                    if (stk.isReduceable())
                        stk.xswap();
                    break;
                }
                if ((tk = nextToken()) != null) {
                    switch(operator) {
                        case AND:
                            {
                                if (!(stk.peekBoolean()))
                                    return OP_TERMINATE;
                                else {
                                    splitAccumulator.add(tk);
                                    return AND;
                                }
                            }
                        case OR:
                            {
                                if ((stk.peekBoolean()))
                                    return OP_TERMINATE;
                                else {
                                    splitAccumulator.add(tk);
                                    return OR;
                                }
                            }
                        default:
                            stk.push(operator, tk.getReducedValue(ctx, ctx, variableFactory));
                    }
                }
            }
        } else if (!tk.isOperator()) {
            throw new CompileException("unexpected token: " + tk.getName(), expr, st);
        } else {
            reduce();
            splitAccumulator.push(tk);
        }
    }
    // keep XSWAPing and reducing, until there is nothing left.
    if (stk.isReduceable()) {
        while (true) {
            reduce();
            if (stk.isReduceable()) {
                stk.xswap();
            } else {
                break;
            }
        }
    }
    return OP_RESET_FRAME;
}
Also used : CompileException(org.mvel2.CompileException)

Example 4 with CompileException

use of org.mvel2.CompileException in project mvel by mikebrock.

the class AbstractParser method procTypedNode.

/**
   * Process the current typed node
   *
   * @param decl node is a declaration or not
   * @return and ast node
   */
private ASTNode procTypedNode(boolean decl) {
    while (true) {
        if (lastNode.getLiteralValue() instanceof String) {
            char[] tmp = ((String) lastNode.getLiteralValue()).toCharArray();
            TypeDescriptor tDescr = new TypeDescriptor(tmp, 0, tmp.length, 0);
            try {
                lastNode.setLiteralValue(getClassReference(pCtx, tDescr));
                lastNode.discard();
            } catch (Exception e) {
            // fall through;
            }
        }
        if (lastNode.isLiteral() && lastNode.getLiteralValue() instanceof Class) {
            lastNode.discard();
            captureToEOS();
            if (decl) {
                splitAccumulator.add(new DeclTypedVarNode(new String(expr, st, cursor - st), expr, st, cursor - st, (Class) lastNode.getLiteralValue(), fields | ASTNode.ASSIGN, pCtx));
            } else {
                captureToEOS();
                splitAccumulator.add(new TypedVarNode(expr, st, cursor - st - 1, fields | ASTNode.ASSIGN, (Class) lastNode.getLiteralValue(), pCtx));
            }
        } else if (lastNode instanceof Proto) {
            captureToEOS();
            if (decl) {
                splitAccumulator.add(new DeclProtoVarNode(new String(expr, st, cursor - st), (Proto) lastNode, fields | ASTNode.ASSIGN, pCtx));
            } else {
                splitAccumulator.add(new ProtoVarNode(expr, st, cursor - st, fields | ASTNode.ASSIGN, (Proto) lastNode, pCtx));
            }
        } else // this redundant looking code is needed to work with the interpreter and MVELSH properly.
        if ((fields & ASTNode.COMPILE_IMMEDIATE) == 0) {
            if (stk.peek() instanceof Class) {
                captureToEOS();
                if (decl) {
                    splitAccumulator.add(new DeclTypedVarNode(new String(expr, st, cursor - st), expr, st, cursor - st, (Class) stk.pop(), fields | ASTNode.ASSIGN, pCtx));
                } else {
                    splitAccumulator.add(new TypedVarNode(expr, st, cursor - st, fields | ASTNode.ASSIGN, (Class) stk.pop(), pCtx));
                }
            } else if (stk.peek() instanceof Proto) {
                captureToEOS();
                if (decl) {
                    splitAccumulator.add(new DeclProtoVarNode(new String(expr, st, cursor - st), (Proto) stk.pop(), fields | ASTNode.ASSIGN, pCtx));
                } else {
                    splitAccumulator.add(new ProtoVarNode(expr, st, cursor - st, fields | ASTNode.ASSIGN, (Proto) stk.pop(), pCtx));
                }
            } else {
                throw new CompileException("unknown class or illegal statement: " + lastNode.getLiteralValue(), expr, cursor);
            }
        } else {
            throw new CompileException("unknown class or illegal statement: " + lastNode.getLiteralValue(), expr, cursor);
        }
        skipWhitespace();
        if (cursor < end && expr[cursor] == ',') {
            st = ++cursor;
            splitAccumulator.add(new EndOfStatement());
        } else {
            return (ASTNode) splitAccumulator.pop();
        }
    }
}
Also used : CompileException(org.mvel2.CompileException) CompileException(org.mvel2.CompileException)

Example 5 with CompileException

use of org.mvel2.CompileException in project mvel by mikebrock.

the class ASMAccessorOptimizer method getCollectionPropertyAO.

private Object getCollectionPropertyAO(Object ctx, String prop) throws IllegalAccessException, InvocationTargetException {
    if (prop.length() > 0) {
        ctx = getBeanProperty(ctx, prop);
        first = false;
    }
    if (ctx == null)
        return null;
    assert debug("\n  **  ENTER -> {collection:<<" + prop + ">>; ctx=" + ctx + "}");
    int _start = ++cursor;
    skipWhitespace();
    if (cursor == end)
        throw new CompileException("unterminated '['", expr, st);
    if (scanTo(']'))
        throw new CompileException("unterminated '['", expr, st);
    String tk = new String(expr, _start, cursor - _start);
    assert debug("{collection token:<<" + tk + ">>}");
    ExecutableStatement compiled = (ExecutableStatement) subCompileExpression(tk.toCharArray());
    Object item = compiled.getValue(ctx, variableFactory);
    ++cursor;
    if (ctx instanceof Map) {
        if (hasPropertyHandler(Map.class)) {
            return propHandlerByteCode(tk, ctx, Map.class);
        } else {
            if (first) {
                assert debug("ALOAD 1");
                mv.visitVarInsn(ALOAD, 1);
            }
            assert debug("CHECKCAST java/util/Map");
            mv.visitTypeInsn(CHECKCAST, "java/util/Map");
            Class c = writeLiteralOrSubexpression(compiled);
            if (c != null && c.isPrimitive()) {
                wrapPrimitive(c);
            }
            assert debug("INVOKEINTERFACE: Map.get");
            mv.visitMethodInsn(INVOKEINTERFACE, "java/util/Map", "get", "(Ljava/lang/Object;)Ljava/lang/Object;");
        }
        return ((Map) ctx).get(item);
    } else if (ctx instanceof List) {
        if (hasPropertyHandler(List.class)) {
            return propHandlerByteCode(tk, ctx, List.class);
        } else {
            if (first) {
                assert debug("ALOAD 1");
                mv.visitVarInsn(ALOAD, 1);
            }
            assert debug("CHECKCAST java/util/List");
            mv.visitTypeInsn(CHECKCAST, "java/util/List");
            writeLiteralOrSubexpression(compiled, int.class);
            assert debug("INVOKEINTERFACE: java/util/List.get");
            mv.visitMethodInsn(INVOKEINTERFACE, "java/util/List", "get", "(I)Ljava/lang/Object;");
            return ((List) ctx).get(convert(item, Integer.class));
        }
    } else if (ctx.getClass().isArray()) {
        if (hasPropertyHandler(Array.class)) {
            return propHandlerByteCode(tk, ctx, Array.class);
        } else {
            if (first) {
                assert debug("ALOAD 1");
                mv.visitVarInsn(ALOAD, 1);
            }
            assert debug("CHECKCAST " + getDescriptor(ctx.getClass()));
            mv.visitTypeInsn(CHECKCAST, getDescriptor(ctx.getClass()));
            writeLiteralOrSubexpression(compiled, int.class, item.getClass());
            Class cls = getBaseComponentType(ctx.getClass());
            if (cls.isPrimitive()) {
                if (cls == int.class) {
                    assert debug("IALOAD");
                    mv.visitInsn(IALOAD);
                } else if (cls == char.class) {
                    assert debug("CALOAD");
                    mv.visitInsn(CALOAD);
                } else if (cls == boolean.class) {
                    assert debug("BALOAD");
                    mv.visitInsn(BALOAD);
                } else if (cls == double.class) {
                    assert debug("DALOAD");
                    mv.visitInsn(DALOAD);
                } else if (cls == float.class) {
                    assert debug("FALOAD");
                    mv.visitInsn(FALOAD);
                } else if (cls == short.class) {
                    assert debug("SALOAD");
                    mv.visitInsn(SALOAD);
                } else if (cls == long.class) {
                    assert debug("LALOAD");
                    mv.visitInsn(LALOAD);
                } else if (cls == byte.class) {
                    assert debug("BALOAD");
                    mv.visitInsn(BALOAD);
                }
                wrapPrimitive(cls);
            } else {
                assert debug("AALOAD");
                mv.visitInsn(AALOAD);
            }
            return Array.get(ctx, convert(item, Integer.class));
        }
    } else if (ctx instanceof CharSequence) {
        if (hasPropertyHandler(CharSequence.class)) {
            return propHandlerByteCode(tk, ctx, CharSequence.class);
        } else {
            if (first) {
                assert debug("ALOAD 1");
                mv.visitVarInsn(ALOAD, 1);
            }
            assert debug("CHECKCAST java/lang/CharSequence");
            mv.visitTypeInsn(CHECKCAST, "java/lang/CharSequence");
            if (item instanceof Integer) {
                intPush((Integer) item);
                assert debug("INVOKEINTERFACE java/lang/CharSequence.charAt");
                mv.visitMethodInsn(INVOKEINTERFACE, "java/lang/CharSequence", "charAt", "(I)C");
                wrapPrimitive(char.class);
                return ((CharSequence) ctx).charAt((Integer) item);
            } else {
                writeLiteralOrSubexpression(compiled, Integer.class);
                unwrapPrimitive(int.class);
                assert debug("INVOKEINTERFACE java/lang/CharSequence.charAt");
                mv.visitMethodInsn(INVOKEINTERFACE, "java/lang/CharSequence", "charAt", "(I)C");
                wrapPrimitive(char.class);
                return ((CharSequence) ctx).charAt(convert(item, Integer.class));
            }
        }
    } else {
        TypeDescriptor tDescr = new TypeDescriptor(expr, start, end - start, 0);
        if (tDescr.isArray()) {
            try {
                Class cls = getClassReference((Class) ctx, tDescr, variableFactory, pCtx);
                //   rootNode = new StaticReferenceAccessor(cls);
                ldcClassConstant(cls);
                return cls;
            } catch (Exception e) {
            //fall through
            }
        }
        throw new CompileException("illegal use of []: unknown type: " + (ctx == null ? null : ctx.getClass().getName()), expr, st);
    }
}
Also used : TypeDescriptor(org.mvel2.ast.TypeDescriptor) ArrayList(java.util.ArrayList) List(java.util.List) Map(java.util.Map) IOException(java.io.IOException)

Aggregations

CompileException (org.mvel2.CompileException)23 List (java.util.List)8 Map (java.util.Map)8 IOException (java.io.IOException)7 ExecutableStatement (org.mvel2.compiler.ExecutableStatement)7 ArrayList (java.util.ArrayList)6 Function (org.mvel2.ast.Function)4 TypeDescriptor (org.mvel2.ast.TypeDescriptor)4 WeakHashMap (java.util.WeakHashMap)3 ParserContext (org.mvel2.ParserContext)3 Proto (org.mvel2.ast.Proto)3 ExpressionCompiler (org.mvel2.compiler.ExpressionCompiler)3 StringAppender (org.mvel2.util.StringAppender)3 Label (org.mvel2.asm.Label)2 ASTNode (org.mvel2.ast.ASTNode)2 EndOfStatement (org.mvel2.ast.EndOfStatement)2 CompiledExpression (org.mvel2.compiler.CompiledExpression)2 DefaultLocalVariableResolverFactory (org.mvel2.integration.impl.DefaultLocalVariableResolverFactory)2 ItemResolverFactory (org.mvel2.integration.impl.ItemResolverFactory)2 ExecutionStack (org.mvel2.util.ExecutionStack)2