Search in sources :

Example 21 with Function

use of org.mvel2.ast.Function 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 DeepOperativeAssignmentNode(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 DeepOperativeAssignmentNode(expr, st = trimRight(st), trimLeft(cursor) - st, fields, SUB, name, 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 ':':
                        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 DeepOperativeAssignmentNode(expr, st = trimRight(st), trimLeft(cursor) - st, fields, opLookup(op), name, 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);
    }
}
Also used : Fold(org.mvel2.ast.Fold) IndexedPreFixDecNode(org.mvel2.ast.IndexedPreFixDecNode) LineLabel(org.mvel2.ast.LineLabel) InterceptorWrapper(org.mvel2.ast.InterceptorWrapper) ThisWithNode(org.mvel2.ast.ThisWithNode) StaticImportNode(org.mvel2.ast.StaticImportNode) ImportNode(org.mvel2.ast.ImportNode) StaticImportNode(org.mvel2.ast.StaticImportNode) Invert(org.mvel2.ast.Invert) AssignmentNode(org.mvel2.ast.AssignmentNode) IndexedAssignmentNode(org.mvel2.ast.IndexedAssignmentNode) DeepOperativeAssignmentNode(org.mvel2.ast.DeepOperativeAssignmentNode) DeepAssignmentNode(org.mvel2.ast.DeepAssignmentNode) IndexedDeclTypedVarNode(org.mvel2.ast.IndexedDeclTypedVarNode) IndexedPreFixDecNode(org.mvel2.ast.IndexedPreFixDecNode) PreFixDecNode(org.mvel2.ast.PreFixDecNode) RedundantCodeException(org.mvel2.ast.RedundantCodeException) OperatorNode(org.mvel2.ast.OperatorNode) BooleanNode(org.mvel2.ast.BooleanNode) NewObjectPrototype(org.mvel2.ast.NewObjectPrototype) LiteralNode(org.mvel2.ast.LiteralNode) TypeDescriptor(org.mvel2.ast.TypeDescriptor) NewObjectNode(org.mvel2.ast.NewObjectNode) IndexedOperativeAssign(org.mvel2.ast.IndexedOperativeAssign) TypeCast(org.mvel2.ast.TypeCast) IndexedPreFixIncNode(org.mvel2.ast.IndexedPreFixIncNode) Substatement(org.mvel2.ast.Substatement) IndexedPostFixIncNode(org.mvel2.ast.IndexedPostFixIncNode) PostFixIncNode(org.mvel2.ast.PostFixIncNode) IndexedPostFixDecNode(org.mvel2.ast.IndexedPostFixDecNode) Negation(org.mvel2.ast.Negation) InlineCollectionNode(org.mvel2.ast.InlineCollectionNode) IndexedPostFixIncNode(org.mvel2.ast.IndexedPostFixIncNode) OperativeAssign(org.mvel2.ast.OperativeAssign) IndexedOperativeAssign(org.mvel2.ast.IndexedOperativeAssign) Union(org.mvel2.ast.Union) NewPrototypeNode(org.mvel2.ast.NewPrototypeNode) DeepOperativeAssignmentNode(org.mvel2.ast.DeepOperativeAssignmentNode) CompileException(org.mvel2.CompileException) IsDef(org.mvel2.ast.IsDef) PreFixIncNode(org.mvel2.ast.PreFixIncNode) IndexedPreFixIncNode(org.mvel2.ast.IndexedPreFixIncNode) RegExMatch(org.mvel2.ast.RegExMatch) EndOfStatement(org.mvel2.ast.EndOfStatement) DeepAssignmentNode(org.mvel2.ast.DeepAssignmentNode) ReturnNode(org.mvel2.ast.ReturnNode) IndexedAssignmentNode(org.mvel2.ast.IndexedAssignmentNode) IndexedPostFixDecNode(org.mvel2.ast.IndexedPostFixDecNode) PostFixDecNode(org.mvel2.ast.PostFixDecNode) IndexedDeclTypedVarNode(org.mvel2.ast.IndexedDeclTypedVarNode) DeclTypedVarNode(org.mvel2.ast.DeclTypedVarNode) AssertNode(org.mvel2.ast.AssertNode) Sign(org.mvel2.ast.Sign)

Example 22 with Function

use of org.mvel2.ast.Function in project mvel by mvel.

the class AbstractParser method _captureBlock.

private ASTNode _captureBlock(ASTNode node, final char[] expr, boolean cond, int type) {
    skipWhitespace();
    int startCond = 0;
    int endCond = 0;
    int blockStart;
    int blockEnd;
    String name;
    /**
     * Functions are a special case we handle differently from the rest of block parsing
     */
    switch(type) {
        case FUNCTION:
            {
                int st = cursor;
                captureToNextTokenJunction();
                if (cursor == end) {
                    throw new CompileException("unexpected end of statement", expr, st);
                }
                /**
                 * Check to see if the name is legal.
                 */
                if (isReservedWord(name = createStringTrimmed(expr, st, cursor - st)) || isNotValidNameorLabel(name))
                    throw new CompileException("illegal function name or use of reserved word", expr, cursor);
                FunctionParser parser = new FunctionParser(name, cursor, end - cursor, expr, fields, pCtx, splitAccumulator);
                Function function = parser.parse();
                cursor = parser.getCursor();
                return lastNode = function;
            }
        case PROTO:
            {
                if (ProtoParser.isUnresolvedWaiting()) {
                    ProtoParser.checkForPossibleUnresolvedViolations(expr, cursor, pCtx);
                }
                int st = cursor;
                captureToNextTokenJunction();
                if (isReservedWord(name = createStringTrimmed(expr, st, cursor - st)) || isNotValidNameorLabel(name))
                    throw new CompileException("illegal prototype name or use of reserved word", expr, cursor);
                if (expr[cursor = nextNonBlank()] != '{') {
                    throw new CompileException("expected '{' but found: " + expr[cursor], expr, cursor);
                }
                cursor = balancedCaptureWithLineAccounting(expr, st = cursor + 1, end, '{', pCtx);
                ProtoParser parser = new ProtoParser(expr, st, cursor, name, pCtx, fields, splitAccumulator);
                Proto proto = parser.parse();
                pCtx.addImport(proto);
                proto.setCursorPosition(st, cursor);
                cursor = parser.getCursor();
                ProtoParser.notifyForLateResolution(proto);
                return lastNode = proto;
            }
        case STACKLANG:
            {
                if (expr[cursor = nextNonBlank()] != '{') {
                    throw new CompileException("expected '{' but found: " + expr[cursor], expr, cursor);
                }
                int st;
                cursor = balancedCaptureWithLineAccounting(expr, st = cursor + 1, end, '{', pCtx);
                Stacklang stacklang = new Stacklang(expr, st, cursor - st, fields, pCtx);
                cursor++;
                return lastNode = stacklang;
            }
        default:
            if (cond) {
                if (expr[cursor] != '(') {
                    throw new CompileException("expected '(' but encountered: " + expr[cursor], expr, cursor);
                }
                /**
                 * This block is an: IF, FOREACH or WHILE node.
                 */
                endCond = cursor = balancedCaptureWithLineAccounting(expr, startCond = cursor, end, '(', pCtx);
                startCond++;
                cursor++;
            }
    }
    skipWhitespace();
    if (cursor >= end) {
        throw new CompileException("unexpected end of statement", expr, end);
    } else if (expr[cursor] == '{') {
        blockEnd = cursor = balancedCaptureWithLineAccounting(expr, blockStart = cursor, end, '{', pCtx);
    } else {
        blockStart = cursor - 1;
        captureToEOSorEOL();
        blockEnd = cursor + 1;
    }
    if (type == ASTNode.BLOCK_IF) {
        IfNode ifNode = (IfNode) node;
        if (node != null) {
            if (!cond) {
                return ifNode.setElseBlock(expr, st = trimRight(blockStart + 1), trimLeft(blockEnd) - st, pCtx);
            } else {
                return ifNode.setElseIf((IfNode) createBlockToken(startCond, endCond, trimRight(blockStart + 1), trimLeft(blockEnd), type));
            }
        } else {
            return createBlockToken(startCond, endCond, blockStart + 1, blockEnd, type);
        }
    } else if (type == ASTNode.BLOCK_DO) {
        cursor++;
        skipWhitespace();
        st = cursor;
        captureToNextTokenJunction();
        if ("while".equals(name = new String(expr, st, cursor - st))) {
            skipWhitespace();
            startCond = cursor + 1;
            endCond = cursor = balancedCaptureWithLineAccounting(expr, cursor, end, '(', pCtx);
            return createBlockToken(startCond, endCond, trimRight(blockStart + 1), trimLeft(blockEnd), type);
        } else if ("until".equals(name)) {
            skipWhitespace();
            startCond = cursor + 1;
            endCond = cursor = balancedCaptureWithLineAccounting(expr, cursor, end, '(', pCtx);
            return createBlockToken(startCond, endCond, trimRight(blockStart + 1), trimLeft(blockEnd), ASTNode.BLOCK_DO_UNTIL);
        } else {
            throw new CompileException("expected 'while' or 'until' but encountered: " + name, expr, cursor);
        }
    } else // DON"T REMOVE THIS COMMENT!
    // else if (isFlag(ASTNode.BLOCK_FOREACH) || isFlag(ASTNode.BLOCK_WITH)) {
    {
        return createBlockToken(startCond, endCond, trimRight(blockStart + 1), trimLeft(blockEnd), type);
    }
}
Also used : FunctionParser(org.mvel2.util.FunctionParser) Function(org.mvel2.ast.Function) ProtoParser(org.mvel2.util.ProtoParser) Proto(org.mvel2.ast.Proto) CompileException(org.mvel2.CompileException) IfNode(org.mvel2.ast.IfNode) Stacklang(org.mvel2.ast.Stacklang)

Example 23 with Function

use of org.mvel2.ast.Function in project mvel by mvel.

the class NewObjectPrototype method getReducedValue.

@Override
public Object getReducedValue(Object ctx, Object thisValue, VariableResolverFactory factory) {
    final MapVariableResolverFactory resolverFactory = new MapVariableResolverFactory(new HashMap<String, Object>(), factory);
    function.getCompiledBlock().getValue(ctx, thisValue, resolverFactory);
    return new PrototypalFunctionInstance(function, resolverFactory);
}
Also used : MapVariableResolverFactory(org.mvel2.integration.impl.MapVariableResolverFactory)

Example 24 with Function

use of org.mvel2.ast.Function in project mvel by mvel.

the class DynamicFunctionAccessor method getValue.

public Object getValue(Object ctx, Object elCtx, VariableResolverFactory variableFactory) {
    Object[] parms = null;
    Function function;
    if (ctx instanceof FunctionInstance) {
        function = ((FunctionInstance) ctx).getFunction();
    } else {
        function = (Function) ctx;
    }
    if (parameters != null && parameters.length != 0) {
        parms = new Object[parameters.length];
        for (int i = 0; i < parms.length; i++) {
            parms[i] = parameters[i].getValue(ctx, elCtx, variableFactory);
        }
    }
    if (nextNode != null) {
        return nextNode.getValue(function.call(ctx, elCtx, variableFactory, parms), elCtx, variableFactory);
    } else {
        return function.call(ctx, elCtx, variableFactory, parms);
    }
}
Also used : Function(org.mvel2.ast.Function) FunctionInstance(org.mvel2.ast.FunctionInstance)

Example 25 with Function

use of org.mvel2.ast.Function in project mvel by mvel.

the class ReflectiveAccessorOptimizer method getMethod.

private Object getMethod(Object ctx, String name, Object[] args, Class[] argTypes, ExecutableStatement[] es) throws Exception {
    if (first && variableFactory != null && variableFactory.isResolveable(name)) {
        Object ptr = variableFactory.getVariableResolver(name).getValue();
        if (ptr instanceof Method) {
            ctx = ((Method) ptr).getDeclaringClass();
            name = ((Method) ptr).getName();
        } else if (ptr instanceof MethodStub) {
            ctx = ((MethodStub) ptr).getClassReference();
            name = ((MethodStub) ptr).getMethodName();
        } else if (ptr instanceof FunctionInstance) {
            FunctionInstance func = (FunctionInstance) ptr;
            if (!name.equals(func.getFunction().getName())) {
                getBeanProperty(ctx, name);
                addAccessorNode(new DynamicFunctionAccessor(es));
            } else {
                addAccessorNode(new FunctionAccessor(func, es));
            }
            return func.call(ctx, thisRef, variableFactory, args);
        } else {
            throw new OptimizationFailure("attempt to optimize a method call for a reference that does not point to a method: " + name + " (reference is type: " + (ctx != null ? ctx.getClass().getName() : null) + ")");
        }
        first = false;
    }
    if (ctx == null && currType == null) {
        throw new PropertyAccessException("null pointer or function not found: " + name, this.expr, this.start, pCtx);
    }
    boolean classTarget = false;
    Class<?> cls = currType != null ? currType : ((classTarget = ctx instanceof Class) ? (Class<?>) ctx : ctx.getClass());
    currType = null;
    Method m;
    Class[] parameterTypes = null;
    /**
     * Try to find an instance method from the class target.
     */
    if ((m = getBestCandidate(argTypes, name, cls, cls.getMethods(), false, classTarget)) != null) {
        parameterTypes = m.getParameterTypes();
    }
    if (m == null && classTarget) {
        /**
         * If we didn't find anything, maybe we're looking for the actual java.lang.Class methods.
         */
        if ((m = getBestCandidate(argTypes, name, cls, Class.class.getMethods(), false)) != null) {
            parameterTypes = m.getParameterTypes();
        }
    }
    // If we didn't find anything and the declared class is different from the actual one try also with the actual one
    if (m == null && ctx != null && cls != ctx.getClass() && !(ctx instanceof Class)) {
        cls = ctx.getClass();
        if ((m = getBestCandidate(argTypes, name, cls, cls.getMethods(), false, classTarget)) != null) {
            parameterTypes = m.getParameterTypes();
        }
    }
    if (m == null) {
        StringAppender errorBuild = new StringAppender();
        if ("size".equals(name) && args.length == 0 && cls.isArray()) {
            addAccessorNode(new ArrayLength());
            return getLength(ctx);
        }
        for (int i = 0; i < args.length; i++) {
            errorBuild.append(args[i] != null ? args[i].getClass().getName() : null);
            if (i < args.length - 1)
                errorBuild.append(", ");
        }
        throw new PropertyAccessException("unable to resolve method: " + cls.getName() + "." + name + "(" + errorBuild.toString() + ") [arglength=" + args.length + "]", this.expr, this.st, pCtx);
    }
    if (es != null) {
        ExecutableStatement cExpr;
        for (int i = 0; i < es.length; i++) {
            cExpr = es[i];
            if (cExpr.getKnownIngressType() == null) {
                cExpr.setKnownIngressType(paramTypeVarArgsSafe(parameterTypes, i, m.isVarArgs()));
                cExpr.computeTypeConversionRule();
            }
            if (!cExpr.isConvertableIngressEgress()) {
                args[i] = convert(args[i], paramTypeVarArgsSafe(parameterTypes, i, m.isVarArgs()));
            }
        }
    } else {
        /**
         * Coerce any types if required.
         */
        for (int i = 0; i < args.length; i++) args[i] = convert(args[i], paramTypeVarArgsSafe(parameterTypes, i, m.isVarArgs()));
    }
    Method method = getWidenedTarget(cls, m);
    Object o = ctx != null ? method.invoke(ctx, normalizeArgsForVarArgs(parameterTypes, args, m.isVarArgs())) : null;
    if (hasNullMethodHandler()) {
        addAccessorNode(new MethodAccessorNH(method, (ExecutableStatement[]) es, getNullMethodHandler()));
        if (o == null)
            o = getNullMethodHandler().getProperty(m.getName(), ctx, variableFactory);
    } else {
        addAccessorNode(new MethodAccessor(method, (ExecutableStatement[]) es));
    }
    /**
     * return the response.
     */
    currType = toNonPrimitiveType(method.getReturnType());
    return o;
}
Also used : ExecutableStatement(org.mvel2.compiler.ExecutableStatement) MethodAccessor(org.mvel2.optimizers.impl.refl.nodes.MethodAccessor) DynamicFunctionAccessor(org.mvel2.optimizers.impl.refl.nodes.DynamicFunctionAccessor) DynamicFunctionAccessor(org.mvel2.optimizers.impl.refl.nodes.DynamicFunctionAccessor) FunctionAccessor(org.mvel2.optimizers.impl.refl.nodes.FunctionAccessor) OptimizationFailure(org.mvel2.OptimizationFailure) PropertyAccessException(org.mvel2.PropertyAccessException) ArrayLength(org.mvel2.optimizers.impl.refl.nodes.ArrayLength) Method(java.lang.reflect.Method) MethodAccessorNH(org.mvel2.optimizers.impl.refl.nodes.MethodAccessorNH) FunctionInstance(org.mvel2.ast.FunctionInstance) MethodStub(org.mvel2.util.MethodStub) StringAppender(org.mvel2.util.StringAppender)

Aggregations

Function (org.mvel2.ast.Function)12 CompileException (org.mvel2.CompileException)10 EndOfStatement (org.mvel2.ast.EndOfStatement)5 StringAppender (org.mvel2.util.StringAppender)5 IOException (java.io.IOException)4 HashMap (java.util.HashMap)4 Proto (org.mvel2.ast.Proto)4 ExecutableStatement (org.mvel2.compiler.ExecutableStatement)4 Serializable (java.io.Serializable)3 Method (java.lang.reflect.Method)3 MapVariableResolverFactory (org.mvel2.integration.impl.MapVariableResolverFactory)3 MethodStub (org.mvel2.util.MethodStub)3 BufferedReader (java.io.BufferedReader)2 StringReader (java.io.StringReader)2 Map (java.util.Map)2 FunctionError (org.drools.compiler.compiler.FunctionError)2 LineMappings (org.drools.core.rule.LineMappings)2 OptimizationFailure (org.mvel2.OptimizationFailure)2 PropertyAccessException (org.mvel2.PropertyAccessException)2 FunctionInstance (org.mvel2.ast.FunctionInstance)2