Search in sources :

Example 21 with ASTNode

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

the class MVELInterpretedRuntime method parseAndExecuteInterpreted.

/**
 * Main interpreter loop.
 *
 * @return value
 */
private Object parseAndExecuteInterpreted() {
    ASTNode tk = null;
    int operator;
    lastWasIdentifier = false;
    try {
        while ((tk = nextToken()) != null) {
            holdOverRegister = null;
            if (lastWasIdentifier && lastNode.isDiscard()) {
                stk.discard();
            }
            /**
             * If we are at the beginning of a statement, then we immediately push the first token
             * onto the stack.
             */
            if (stk.isEmpty()) {
                if ((tk.fields & ASTNode.STACKLANG) != 0) {
                    stk.push(tk.getReducedValue(stk, ctx, variableFactory));
                    Object o = stk.peek();
                    if (o instanceof Integer) {
                        arithmeticFunctionReduction((Integer) o);
                    }
                } else {
                    stk.push(tk.getReducedValue(ctx, ctx, variableFactory));
                }
                /**
                 * If this is a substatement, we need to move the result into the d-stack to preserve
                 * proper execution order.
                 */
                if (tk instanceof Substatement && (tk = nextToken()) != null) {
                    if (isArithmeticOperator(operator = tk.getOperator())) {
                        stk.push(nextToken().getReducedValue(ctx, ctx, variableFactory), operator);
                        if (procBooleanOperator(arithmeticFunctionReduction(operator)) == -1)
                            return stk.peek();
                        else
                            continue;
                    }
                } else {
                    continue;
                }
            }
            if (variableFactory.tiltFlag()) {
                return stk.pop();
            }
            switch(procBooleanOperator(operator = tk.getOperator())) {
                case RETURN:
                    variableFactory.setTiltFlag(true);
                    return stk.pop();
                case OP_TERMINATE:
                    return stk.peek();
                case OP_RESET_FRAME:
                    continue;
                case OP_OVERFLOW:
                    if (!tk.isOperator()) {
                        if (!(stk.peek() instanceof Class)) {
                            throw new CompileException("unexpected token or unknown identifier:" + tk.getName(), expr, st);
                        }
                        variableFactory.createVariable(tk.getName(), null, (Class) stk.peek());
                    }
                    continue;
            }
            stk.push(nextToken().getReducedValue(ctx, ctx, variableFactory), operator);
            switch((operator = arithmeticFunctionReduction(operator))) {
                case OP_TERMINATE:
                    return stk.peek();
                case OP_RESET_FRAME:
                    continue;
            }
            if (procBooleanOperator(operator) == OP_TERMINATE)
                return stk.peek();
        }
        if (holdOverRegister != null) {
            return holdOverRegister;
        }
    } catch (CompileException e) {
        throw ErrorUtil.rewriteIfNeeded(e, expr, start);
    } catch (NullPointerException e) {
        if (tk != null && tk.isOperator()) {
            CompileException ce = new CompileException("incomplete statement: " + tk.getName() + " (possible use of reserved keyword as identifier: " + tk.getName() + ")", expr, st, e);
            ce.setExpr(expr);
            ce.setLineNumber(line);
            ce.setCursor(cursor);
            throw ce;
        } else {
            throw e;
        }
    }
    return stk.peek();
}
Also used : ASTNode(org.mvel2.ast.ASTNode) Substatement(org.mvel2.ast.Substatement)

Example 22 with ASTNode

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

the class CoreConfidenceTests method testInterceptors.

public void testInterceptors() {
    Interceptor testInterceptor = new Interceptor() {

        public int doBefore(ASTNode node, VariableResolverFactory factory) {
            System.out.println("BEFORE Node: " + node.getName());
            return 0;
        }

        public int doAfter(Object val, ASTNode node, VariableResolverFactory factory) {
            System.out.println("AFTER Node: " + node.getName());
            return 0;
        }
    };
    Map<String, Interceptor> interceptors = new HashMap<String, Interceptor>();
    interceptors.put("test", testInterceptor);
    executeExpression(compileExpression("@test System.out.println('MIDDLE');", null, interceptors));
}
Also used : DefaultLocalVariableResolverFactory(org.mvel2.integration.impl.DefaultLocalVariableResolverFactory) MapVariableResolverFactory(org.mvel2.integration.impl.MapVariableResolverFactory) IndexedVariableResolverFactory(org.mvel2.integration.impl.IndexedVariableResolverFactory) VariableResolverFactory(org.mvel2.integration.VariableResolverFactory) HashMap(java.util.HashMap) LinkedHashMap(java.util.LinkedHashMap) ASTNode(org.mvel2.ast.ASTNode) MapObject(org.mvel2.tests.core.res.MapObject) Interceptor(org.mvel2.integration.Interceptor)

Example 23 with ASTNode

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

the class AbstractParser method createPropertyToken.

/**
 * Generate a property token
 *
 * @param st  the start offset
 * @param end the end offset
 * @return an ast node
 */
private ASTNode createPropertyToken(int st, int end) {
    String tmp;
    if (isPropertyOnly(expr, st, end)) {
        if (pCtx != null && pCtx.hasImports()) {
            int find;
            if ((find = findFirst('.', st, end - st, expr)) != -1) {
                String iStr = new String(expr, st, find - st);
                if (pCtx.hasImport(iStr)) {
                    lastWasIdentifier = true;
                    return lastNode = new LiteralDeepPropertyNode(expr, find + 1, end - find - 1, fields, pCtx.getImport(iStr), pCtx);
                }
            } else {
                if (pCtx.hasImport(tmp = new String(expr, st, cursor - st))) {
                    lastWasIdentifier = true;
                    return lastNode = new LiteralNode(pCtx.getStaticOrClassImport(tmp), pCtx);
                }
            }
        }
        if (LITERALS.containsKey(tmp = new String(expr, st, end - st))) {
            lastWasIdentifier = true;
            return lastNode = new LiteralNode(LITERALS.get(tmp), pCtx);
        } else if (OPERATORS.containsKey(tmp)) {
            lastWasIdentifier = false;
            return lastNode = new OperatorNode(OPERATORS.get(tmp), expr, st, pCtx);
        } else if (lastWasIdentifier) {
            return procTypedNode(true);
        }
    }
    if (pCtx != null && isArrayType(expr, st, end)) {
        if (pCtx.hasImport(new String(expr, st, cursor - st - 2))) {
            lastWasIdentifier = true;
            TypeDescriptor typeDescriptor = new TypeDescriptor(expr, st, cursor - st, fields);
            try {
                return lastNode = new LiteralNode(typeDescriptor.getClassReference(pCtx), pCtx);
            } catch (ClassNotFoundException e) {
                throw new CompileException("could not resolve class: " + typeDescriptor.getClassName(), expr, st);
            }
        }
    }
    lastWasIdentifier = true;
    return lastNode = new ASTNode(expr, trimRight(st), trimLeft(end) - st, fields, pCtx);
}
Also used : LiteralNode(org.mvel2.ast.LiteralNode) LiteralDeepPropertyNode(org.mvel2.ast.LiteralDeepPropertyNode) TypeDescriptor(org.mvel2.ast.TypeDescriptor) ASTNode(org.mvel2.ast.ASTNode) CompileException(org.mvel2.CompileException) OperatorNode(org.mvel2.ast.OperatorNode)

Example 24 with ASTNode

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

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, pCtx));
                return OP_OVERFLOW;
            }
            dStack.push(operator = operator2, tk.getReducedValue(ctx, ctx, variableFactory));
            while (true) {
                ASTNode previousToken = tk;
                // look ahead again
                if ((tk = nextToken()) != null && (operator2 = tk.getOperator()) != -1 && operator2 != END_OF_STMT && 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.
                     */
                    ASTNode nextToken = nextToken();
                    if (compileMode && !nextToken.isLiteral()) {
                        splitAccumulator.push(nextToken, new OperatorNode(operator2, expr, st, pCtx));
                        return OP_OVERFLOW;
                    }
                    dStack.push(operator = operator2, nextToken.getReducedValue(ctx, ctx, variableFactory));
                    continue;
                } else if (tk != null && operator2 != -1 && operator2 != END_OF_STMT) {
                    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:
                            if (compileMode && !tk.isLiteral()) {
                                stk.push(operator, tk);
                                return OP_NOT_LITERAL;
                            }
                            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 : ASTNode(org.mvel2.ast.ASTNode) CompileException(org.mvel2.CompileException) OperatorNode(org.mvel2.ast.OperatorNode)

Example 25 with ASTNode

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

the class ExpressionCompiler method verify.

protected ASTNode verify(ParserContext pCtx, ASTNode tk) {
    if (tk.isOperator() && (tk.getOperator().equals(Operator.AND) || tk.getOperator().equals(Operator.OR))) {
        secondPassOptimization = true;
    }
    if (tk.isDiscard() || tk.isOperator()) {
        return tk;
    } else if (tk.isLiteral()) {
        /**
         * Convert literal values from the default ASTNode to the more-efficient LiteralNode.
         */
        if ((fields & COMPILE_IMMEDIATE) != 0 && tk.getClass() == ASTNode.class) {
            return new LiteralNode(tk.getLiteralValue(), pCtx);
        } else {
            return tk;
        }
    }
    if (verifying) {
        if (tk.isIdentifier()) {
            PropertyVerifier propVerifier = new PropertyVerifier(expr, tk.getStart(), tk.getOffset(), pCtx);
            if (tk instanceof Union) {
                propVerifier.setCtx(((Union) tk).getLeftEgressType());
                tk.setEgressType(returnType = propVerifier.analyze());
            } else {
                tk.setEgressType(returnType = propVerifier.analyze());
                if (propVerifier.isFqcn()) {
                    tk.setAsFQCNReference();
                }
                if (propVerifier.isClassLiteral()) {
                    return new LiteralNode(returnType, pCtx);
                }
                if (propVerifier.isInput()) {
                    pCtx.addInput(tk.getAbsoluteName(), propVerifier.isDeepProperty() ? Object.class : returnType);
                }
                if (!propVerifier.isMethodCall() && !returnType.isEnum() && !pCtx.isOptimizerNotified() && pCtx.isStrongTyping() && !pCtx.isVariableVisible(tk.getAbsoluteName()) && !tk.isFQCN()) {
                    throw new CompileException("no such identifier: " + tk.getAbsoluteName(), expr, tk.getStart());
                }
            }
        } else if (tk.isAssignment()) {
            Assignment a = (Assignment) tk;
            if (a.getAssignmentVar() != null) {
                // pCtx.makeVisible(a.getAssignmentVar());
                PropertyVerifier propVerifier = new PropertyVerifier(a.getAssignmentVar(), pCtx);
                tk.setEgressType(returnType = propVerifier.analyze());
                if (!a.isNewDeclaration() && propVerifier.isResolvedExternally()) {
                    pCtx.addInput(tk.getAbsoluteName(), returnType);
                }
                ExecutableStatement c = (ExecutableStatement) subCompileExpression(expr, tk.getStart(), tk.getOffset(), pCtx);
                if (pCtx.isStrictTypeEnforcement()) {
                    /**
                     * If we're using strict type enforcement, we need to see if this coercion can be done now,
                     * or fail epicly.
                     */
                    if (!returnType.isAssignableFrom(c.getKnownEgressType()) && c.isLiteralOnly()) {
                        if (canConvert(c.getKnownEgressType(), returnType)) {
                            /**
                             * We convert the literal to the proper type.
                             */
                            try {
                                // Don't convert to a literal for DeepOperativeAssignmentNode. Coercion will be done by BinaryOperation
                                if (!(a instanceof DeepOperativeAssignmentNode)) {
                                    a.setValueStatement(new ExecutableLiteral(convert(c.getValue(null, null), returnType)));
                                }
                                return tk;
                            } catch (Exception e) {
                            // fall through.
                            }
                        } else if (returnType.isPrimitive() && unboxPrimitive(c.getKnownEgressType()).equals(returnType)) {
                            /**
                             * We ignore boxed primitive cases, since MVEL does not recognize primitives.
                             */
                            return tk;
                        }
                        throw new CompileException("cannot assign type " + c.getKnownEgressType().getName() + " to " + returnType.getName(), expr, st);
                    }
                }
            }
        } else if (tk instanceof NewObjectNode) {
            // this is a bit of a hack for now.
            NewObjectNode n = (NewObjectNode) tk;
            List<char[]> parms = ParseTools.parseMethodOrConstructor(tk.getNameAsArray());
            if (parms != null) {
                for (char[] p : parms) {
                    MVEL.analyze(p, pCtx);
                }
            }
        }
        returnType = tk.getEgressType();
    }
    if (!tk.isLiteral() && tk.getClass() == ASTNode.class && (tk.getFields() & ASTNode.ARRAY_TYPE_LITERAL) == 0) {
        if (pCtx.isStrongTyping())
            tk.strongTyping();
        tk.storePctx();
        tk.storeInLiteralRegister(pCtx);
    }
    return tk;
}
Also used : Union(org.mvel2.ast.Union) CompileException(org.mvel2.CompileException) Assignment(org.mvel2.ast.Assignment) LiteralNode(org.mvel2.ast.LiteralNode) NewObjectNode(org.mvel2.ast.NewObjectNode) DeepOperativeAssignmentNode(org.mvel2.ast.DeepOperativeAssignmentNode) CompileException(org.mvel2.CompileException)

Aggregations

ASTNode (org.mvel2.ast.ASTNode)37 CompileException (org.mvel2.CompileException)12 LiteralNode (org.mvel2.ast.LiteralNode)11 CompiledExpression (org.mvel2.compiler.CompiledExpression)8 Interceptor (org.mvel2.integration.Interceptor)8 VariableResolverFactory (org.mvel2.integration.VariableResolverFactory)8 MapVariableResolverFactory (org.mvel2.integration.impl.MapVariableResolverFactory)8 HashMap (java.util.HashMap)7 BinaryOperation (org.mvel2.ast.BinaryOperation)7 WithNode (org.mvel2.ast.WithNode)7 ExecutableStatement (org.mvel2.compiler.ExecutableStatement)7 ParserContext (org.mvel2.ParserContext)6 Substatement (org.mvel2.ast.Substatement)6 ExecutableLiteral (org.mvel2.compiler.ExecutableLiteral)6 ExpressionCompiler (org.mvel2.compiler.ExpressionCompiler)6 AstNode (com.linkedin.pinot.pql.parsers.pql2.ast.AstNode)5 OperatorNode (org.mvel2.ast.OperatorNode)5 Union (org.mvel2.ast.Union)5 ExecutableAccessor (org.mvel2.compiler.ExecutableAccessor)5 MethodAccessor (org.mvel2.optimizers.impl.refl.nodes.MethodAccessor)5