Search in sources :

Example 11 with Or

use of org.mvel2.ast.Or in project mvel by mikebrock.

the class PropertyAccessor method getMethod.

/**
 * Find an appropriate method, execute it, and return it's response.
 *
 * @param ctx  -
 * @param name -
 * @return -
 * @throws Exception -
 */
@SuppressWarnings({ "unchecked" })
private Object getMethod(Object ctx, String name) {
    int _start = cursor;
    String tk = cursor != end && property[cursor] == '(' && ((cursor = balancedCapture(property, cursor, '(')) - _start) > 1 ? new String(property, _start + 1, cursor - _start - 1) : "";
    cursor++;
    Object[] args;
    if (tk.length() == 0) {
        args = ParseTools.EMPTY_OBJ_ARR;
    } else {
        List<char[]> subtokens = parseParameterList(tk.toCharArray(), 0, -1);
        args = new Object[subtokens.size()];
        for (int i = 0; i < subtokens.size(); i++) {
            args[i] = eval(subtokens.get(i), thisReference, variableFactory);
        }
    }
    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 Function) {
            ((Function) ptr).checkArgumentCount(args.length);
            return ((Function) ptr).call(null, thisReference, 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)
        throw new CompileException("no such method or function: " + name, property, cursor);
    /**
     * If the target object is an instance of java.lang.Class itself then do not
     * adjust the Class scope target.
     */
    Class cls = (ctx instanceof Class ? (Class) ctx : ctx.getClass());
    if (cls == Proto.ProtoInstance.class) {
        return ((Proto.ProtoInstance) ctx).get(name).call(null, thisReference, variableFactory, args);
    }
    /**
     * Check to see if we have already cached this method;
     */
    Object[] cache = checkMethodCache(cls, createSignature(name, tk));
    Method m;
    Class[] parameterTypes;
    if (cache != null) {
        m = (Method) cache[0];
        parameterTypes = (Class[]) cache[1];
    } else {
        m = null;
        parameterTypes = null;
    }
    /**
     * If we have not cached the method then we need to go ahead and try to resolve it.
     */
    if (m == null) {
        /**
         * Try to find an instance method from the class target.
         */
        if ((m = getBestCandidate(args, name, cls, cls.getMethods(), false)) != null) {
            addMethodCache(cls, createSignature(name, tk), m);
            parameterTypes = m.getParameterTypes();
        }
        if (m == null) {
            /**
             * If we didn't find anything, maybe we're looking for the actual java.lang.Class methods.
             */
            if ((m = getBestCandidate(args, name, cls, cls.getClass().getDeclaredMethods(), false)) != null) {
                addMethodCache(cls, createSignature(name, tk), m);
                parameterTypes = m.getParameterTypes();
            }
        }
    }
    if (m == null) {
        StringAppender errorBuild = new StringAppender();
        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(", ");
        }
        if ("size".equals(name) && args.length == 0 && cls.isArray()) {
            return getLength(ctx);
        }
        System.out.println("{ " + new String(property) + " }");
        throw new PropertyAccessException("unable to resolve method: " + cls.getName() + "." + name + "(" + errorBuild.toString() + ") [arglength=" + args.length + "]", property, st);
    } else {
        for (int i = 0; i < args.length; i++) {
            args[i] = convert(args[i], parameterTypes[i]);
        }
        /**
         * Invoke the target method and return the response.
         */
        try {
            return m.invoke(ctx, args);
        } catch (IllegalAccessException e) {
            try {
                addMethodCache(cls, createSignature(name, tk), (m = getWidenedTarget(m)));
                return m.invoke(ctx, args);
            } catch (Exception e2) {
                throw new PropertyAccessException("unable to invoke method: " + name, property, cursor, e2);
            }
        } catch (RuntimeException e) {
            throw e;
        } catch (Exception e) {
            throw new PropertyAccessException("unable to invoke method: " + name, property, cursor, e);
        }
    }
}
Also used : Function(org.mvel2.ast.Function) Proto(org.mvel2.ast.Proto) MethodStub(org.mvel2.util.MethodStub) StringAppender(org.mvel2.util.StringAppender)

Example 12 with Or

use of org.mvel2.ast.Or in project mvel by mikebrock.

the class PropertyAccessor method getCollectionProperty.

/**
 * Handle accessing a property embedded in a collections, map, or array
 *
 * @param ctx  -
 * @param prop -
 * @return -
 * @throws Exception -
 */
private Object getCollectionProperty(Object ctx, String prop) throws Exception {
    if (prop.length() != 0) {
        ctx = getBeanProperty(ctx, prop);
    }
    if (ctx == null)
        return null;
    int _start = ++cursor;
    whiteSpaceSkip();
    if (cursor == end || scanTo(']'))
        throw new PropertyAccessException("unterminated '['", property, cursor);
    prop = new String(property, _start, cursor++ - _start);
    if (ctx instanceof Map) {
        return ((Map) ctx).get(eval(prop, ctx, variableFactory));
    } else if (ctx instanceof List) {
        return ((List) ctx).get((Integer) eval(prop, ctx, variableFactory));
    } else if (ctx instanceof Collection) {
        int count = (Integer) eval(prop, ctx, variableFactory);
        if (count > ((Collection) ctx).size())
            throw new PropertyAccessException("index [" + count + "] out of bounds on collections", property, cursor);
        Iterator iter = ((Collection) ctx).iterator();
        for (int i = 0; i < count; i++) iter.next();
        return iter.next();
    } else if (ctx.getClass().isArray()) {
        return Array.get(ctx, (Integer) eval(prop, ctx, variableFactory));
    } else if (ctx instanceof CharSequence) {
        return ((CharSequence) ctx).charAt((Integer) eval(prop, ctx, variableFactory));
    } else {
        // TypeDescriptor td = new TypeDescriptor(property, 0);
        try {
            return getClassReference(getCurrentThreadParserContext(), (Class) ctx, new TypeDescriptor(property, start, length, 0));
        } catch (Exception e) {
            throw new PropertyAccessException("illegal use of []: unknown type: " + (ctx == null ? null : ctx.getClass().getName()), property, st, e);
        }
    }
}
Also used : TypeDescriptor(org.mvel2.ast.TypeDescriptor)

Example 13 with Or

use of org.mvel2.ast.Or in project mvel by mikebrock.

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);
                if (pCtx == null)
                    pCtx = getParserContext();
                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()) {
                if (pCtx == null)
                    pCtx = getParserContext();
                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);
            if (pCtx == null)
                pCtx = getParserContext();
            ProtoParser parser = new ProtoParser(expr, st, cursor, name, pCtx, fields, splitAccumulator);
            Proto proto = parser.parse();
            if (pCtx == null)
                pCtx = getParserContext();
            pCtx.addImport(proto);
            proto.setCursorPosition(st, cursor);
            cursor = parser.getCursor();
            ProtoParser.notifyForLateResolution(proto);
            return lastNode = proto;
        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) ProtoParser(org.mvel2.util.ProtoParser) CompileException(org.mvel2.CompileException)

Example 14 with Or

use of org.mvel2.ast.Or in project mvel by mikebrock.

the class PropertyVerifier method getMethod.

/**
 * Process method
 *
 * @param ctx  - the ingress type
 * @param name - the property component
 * @return known egress type.
 */
private Class getMethod(Class ctx, String name) {
    int st = cursor;
    /**
     * Check to see if this is the first element in the statement.
     */
    if (first) {
        first = false;
        methodCall = true;
        /**
         * It's the first element in the statement, therefore we check to see if there is a static import of a
         * native Java method or an MVEL function.
         */
        if (pCtx.hasImport(name)) {
            Method m = pCtx.getStaticImport(name).getMethod();
            /**
             * Replace the method parameters.
             */
            ctx = m.getDeclaringClass();
            name = m.getName();
        } else if (pCtx.hasFunction(name)) {
            resolvedExternally = false;
            Function f = pCtx.getFunction(name);
            f.checkArgumentCount(parseParameterList((((cursor = balancedCapture(expr, cursor, end, '(')) - st) > 1 ? ParseTools.subset(expr, st + 1, cursor - st - 1) : new char[0]), 0, -1).size());
            return f.getEgressType();
        } else if (pCtx.hasVarOrInput("this")) {
            if (pCtx.isStrictTypeEnforcement()) {
                recordTypeParmsForProperty("this");
            }
            ctx = pCtx.getVarOrInputType("this");
            resolvedExternally = false;
        }
    }
    /**
     * Get the arguments for the method.
     */
    String tk;
    if (cursor < end && expr[cursor] == '(' && ((cursor = balancedCapture(expr, cursor, end, '(')) - st) > 1) {
        tk = new String(expr, st + 1, cursor - st - 1);
    } else {
        tk = "";
    }
    cursor++;
    /**
     * Parse out the arguments list.
     */
    Class[] args;
    List<char[]> subtokens = parseParameterList(tk.toCharArray(), 0, -1);
    if (subtokens.size() == 0) {
        args = new Class[0];
        subtokens = Collections.emptyList();
    } else {
        // ParserContext subCtx = pCtx.createSubcontext();
        args = new Class[subtokens.size()];
        /**
         *  Subcompile all the arguments to determine their known types.
         */
        // ExpressionCompiler compiler;
        List<ErrorDetail> errors = pCtx.getErrorList().isEmpty() ? pCtx.getErrorList() : new ArrayList<ErrorDetail>(pCtx.getErrorList());
        CompileException rethrow = null;
        for (int i = 0; i < subtokens.size(); i++) {
            try {
                args[i] = MVEL.analyze(subtokens.get(i), pCtx);
                if ("null".equals(String.valueOf(subtokens.get(i)))) {
                    args[i] = NullType.class;
                }
            } catch (CompileException e) {
                rethrow = ErrorUtil.rewriteIfNeeded(e, expr, this.st);
            }
            if (errors.size() < pCtx.getErrorList().size()) {
                for (ErrorDetail detail : pCtx.getErrorList()) {
                    if (!errors.contains(detail)) {
                        detail.setExpr(expr);
                        detail.setCursor(new String(expr).substring(this.st).indexOf(new String(subtokens.get(i))) + this.st);
                        detail.setColumn(0);
                        detail.setLineNumber(0);
                        detail.calcRowAndColumn();
                    }
                }
            }
            if (rethrow != null) {
                throw rethrow;
            }
        }
    }
    /**
     * If the target object is an instance of java.lang.Class itself then do not
     * adjust the Class scope target.
     */
    Method m;
    if ((m = getBestCandidate(args, name, ctx, ctx.getMethods(), pCtx.isStrongTyping())) == null) {
        if ((m = getBestCandidate(args, name, ctx, ctx.getDeclaredMethods(), pCtx.isStrongTyping())) == null) {
            StringAppender errorBuild = new StringAppender();
            for (int i = 0; i < args.length; i++) {
                errorBuild.append(args[i] != null ? args[i].getName() : null);
                if (i < args.length - 1)
                    errorBuild.append(", ");
            }
            if (("size".equals(name) || "length".equals(name)) && args.length == 0 && ctx.isArray()) {
                return Integer.class;
            }
            if (pCtx.isStrictTypeEnforcement()) {
                throw new CompileException("unable to resolve method using strict-mode: " + ctx.getName() + "." + name + "(" + errorBuild.toString() + ")", expr, tkStart);
            }
            return Object.class;
        }
    }
    /**
     * If we're in strict mode, we look for generic type information.
     */
    if (pCtx.isStrictTypeEnforcement() && m.getGenericReturnType() != null) {
        Map<String, Class> typeArgs = new HashMap<String, Class>();
        Type[] gpt = m.getGenericParameterTypes();
        Class z;
        ParameterizedType pt;
        for (int i = 0; i < gpt.length; i++) {
            if (gpt[i] instanceof ParameterizedType) {
                pt = (ParameterizedType) gpt[i];
                if ((z = pCtx.getImport(new String(subtokens.get(i)))) != null) {
                    /**
                     * We record the value of the type parameter to our typeArgs Map.
                     */
                    if (pt.getRawType().equals(Class.class)) {
                        /**
                         * If this is an instance of Class, we deal with the special parameterization case.
                         */
                        typeArgs.put(pt.getActualTypeArguments()[0].toString(), z);
                    } else {
                        typeArgs.put(gpt[i].toString(), z);
                    }
                }
            }
        }
        if (pCtx.isStrictTypeEnforcement() && ctx.getTypeParameters().length != 0 && pCtx.getLastTypeParameters() != null && pCtx.getLastTypeParameters().length == ctx.getTypeParameters().length) {
            TypeVariable[] typeVariables = ctx.getTypeParameters();
            for (int i = 0; i < typeVariables.length; i++) {
                typeArgs.put(typeVariables[i].getName(), (Class) pCtx.getLastTypeParameters()[i]);
            }
        }
        /**
         * Get the return type argument
         */
        Type parametricReturnType = m.getGenericReturnType();
        String returnTypeArg = parametricReturnType.toString();
        // push return type parameters onto parser context, only if this is a parametric type
        if (parametricReturnType instanceof ParameterizedType) {
            pCtx.setLastTypeParameters(((ParameterizedType) parametricReturnType).getActualTypeArguments());
        }
        if (paramTypes != null && paramTypes.containsKey(returnTypeArg)) {
            /**
             * If the paramTypes Map contains the known type, return that type.
             */
            return (Class) paramTypes.get(returnTypeArg);
        } else if (typeArgs.containsKey(returnTypeArg)) {
            /**
             * If the generic type was declared as part of the method, it will be in this
             * Map.
             */
            return typeArgs.get(returnTypeArg);
        }
    }
    if (!Modifier.isPublic(m.getModifiers())) {
        StringAppender errorBuild = new StringAppender();
        for (int i = 0; i < args.length; i++) {
            errorBuild.append(args[i] != null ? args[i].getName() : null);
            if (i < args.length - 1)
                errorBuild.append(", ");
        }
        String scope = Modifier.toString(m.getModifiers());
        if (scope.trim().equals(""))
            scope = "<package local>";
        addFatalError("the referenced method is not accessible: " + ctx.getName() + "." + name + "(" + errorBuild.toString() + ")" + " (scope: " + scope + "; required: public", this.tkStart);
    }
    return m.getReturnType();
}
Also used : Function(org.mvel2.ast.Function) NullType(org.mvel2.util.NullType) StringAppender(org.mvel2.util.StringAppender)

Example 15 with Or

use of org.mvel2.ast.Or in project mvel by mikebrock.

the class AbstractOptimizer method tryStaticAccess.

/**
 * Try static access of the property, and return an instance of the Field, Method of Class if successful.
 *
 * @return - Field, Method or Class instance.
 */
protected Object tryStaticAccess() {
    int begin = cursor;
    try {
        /**
         * Try to resolve this *smartly* as a static class reference.
         *
         * This starts at the end of the token and starts to step backwards to figure out whether
         * or not this may be a static class reference.  We search for method calls simply by
         * inspecting for ()'s.  The first union area we come to where no brackets are present is our
         * test-point for a class reference.  If we find a class, we pass the reference to the
         * property accessor along  with trailing methods (if any).
         */
        boolean meth = false;
        // int end = start + length;
        int last = end;
        for (int i = end - 1; i > start; i--) {
            switch(expr[i]) {
                case '.':
                    if (!meth) {
                        try {
                            String test = new String(expr, start, (cursor = last) - start);
                            return Class.forName(test, true, pCtx != null ? pCtx.getParserConfiguration().getClassLoader() : currentThread().getContextClassLoader());
                        } catch (ClassNotFoundException e) {
                            Class cls = Class.forName(new String(expr, start, i - start), true, pCtx != null ? pCtx.getParserConfiguration().getClassLoader() : currentThread().getContextClassLoader());
                            String name = new String(expr, i + 1, end - i - 1);
                            try {
                                return cls.getField(name);
                            } catch (NoSuchFieldException nfe) {
                                for (Method m : cls.getMethods()) {
                                    if (name.equals(m.getName()))
                                        return m;
                                }
                                return null;
                            }
                        }
                    }
                    meth = false;
                    last = i;
                    break;
                case '}':
                    i--;
                    for (int d = 1; i > start && d != 0; i--) {
                        switch(expr[i]) {
                            case '}':
                                d++;
                                break;
                            case '{':
                                d--;
                                break;
                            case '"':
                            case '\'':
                                char s = expr[i];
                                while (i > start && (expr[i] != s && expr[i - 1] != '\\')) i--;
                        }
                    }
                    break;
                case ')':
                    i--;
                    for (int d = 1; i > start && d != 0; i--) {
                        switch(expr[i]) {
                            case ')':
                                d++;
                                break;
                            case '(':
                                d--;
                                break;
                            case '"':
                            case '\'':
                                char s = expr[i];
                                while (i > start && (expr[i] != s && expr[i - 1] != '\\')) i--;
                        }
                    }
                    meth = true;
                    last = i++;
                    break;
                case '\'':
                    while (--i > start) {
                        if (expr[i] == '\'' && expr[i - 1] != '\\') {
                            break;
                        }
                    }
                    break;
                case '"':
                    while (--i > start) {
                        if (expr[i] == '"' && expr[i - 1] != '\\') {
                            break;
                        }
                    }
                    break;
            }
        }
    } catch (Exception cnfe) {
        cursor = begin;
    }
    return null;
}
Also used : Method(java.lang.reflect.Method) CompileException(org.mvel2.CompileException)

Aggregations

CompileException (org.mvel2.CompileException)7 Map (java.util.Map)4 IOException (java.io.IOException)3 ASTNode (org.mvel2.ast.ASTNode)3 Function (org.mvel2.ast.Function)3 HashMap (java.util.HashMap)2 List (java.util.List)2 ParserConfiguration (org.mvel2.ParserConfiguration)2 ParserContext (org.mvel2.ParserContext)2 ExecutableStatement (org.mvel2.compiler.ExecutableStatement)2 StringAppender (org.mvel2.util.StringAppender)2 Collections (edu.emory.mathcs.backport.java.util.Collections)1 File (java.io.File)1 FileInputStream (java.io.FileInputStream)1 Method (java.lang.reflect.Method)1 Paths (java.nio.file.Paths)1 ArrayList (java.util.ArrayList)1 Arrays (java.util.Arrays)1 Comparator (java.util.Comparator)1 HashSet (java.util.HashSet)1