Search in sources :

Example 1 with ASTArrayAccess

use of org.apache.commons.jexl3.parser.ASTArrayAccess in project commons-jexl by apache.

the class Interpreter method visit.

@Override
protected Object visit(final ASTReference node, final Object data) {
    cancelCheck(node);
    final int numChildren = node.jjtGetNumChildren();
    final JexlNode parent = node.jjtGetParent();
    // pass first piece of data in and loop through children
    Object object = null;
    JexlNode objectNode = null;
    JexlNode ptyNode = null;
    StringBuilder ant = null;
    boolean antish = !(parent instanceof ASTReference);
    int v = 1;
    main: for (int c = 0; c < numChildren; c++) {
        objectNode = node.jjtGetChild(c);
        if (objectNode instanceof ASTMethodNode) {
            antish = false;
            if (object == null) {
                // we may be performing a method call on an antish var
                if (ant != null) {
                    final JexlNode child = objectNode.jjtGetChild(0);
                    if (child instanceof ASTIdentifierAccess) {
                        final int alen = ant.length();
                        ant.append('.');
                        ant.append(((ASTIdentifierAccess) child).getName());
                        object = context.get(ant.toString());
                        if (object != null) {
                            object = visit((ASTMethodNode) objectNode, object, context);
                            continue;
                        }
                        // remove method name from antish
                        ant.delete(alen, ant.length());
                        ptyNode = objectNode;
                    }
                }
                break;
            }
        } else if (objectNode instanceof ASTArrayAccess) {
            antish = false;
            if (object == null) {
                ptyNode = objectNode;
                break;
            }
        }
        // attempt to evaluate the property within the object (visit(ASTIdentifierAccess node))
        object = objectNode.jjtAccept(this, object);
        cancelCheck(node);
        if (object != null) {
            // disallow mixing antish variable & bean with same root; avoid ambiguity
            antish = false;
        } else if (antish) {
            // create first from first node
            if (ant == null) {
                // if we still have a null object, check for an antish variable
                final JexlNode first = node.jjtGetChild(0);
                if (!(first instanceof ASTIdentifier)) {
                    // not an identifier, not antish
                    ptyNode = objectNode;
                    break main;
                }
                final ASTIdentifier afirst = (ASTIdentifier) first;
                ant = new StringBuilder(afirst.getName());
                // *... and continue
                if (!options.isAntish()) {
                    antish = false;
                    continue;
                }
                // skip the first node case since it was trialed in jjtAccept above and returned null
                if (c == 0) {
                    continue;
                }
            }
            // catch up to current node
            for (; v <= c; ++v) {
                final JexlNode child = node.jjtGetChild(v);
                if (!(child instanceof ASTIdentifierAccess)) {
                    // not an identifier, not antish
                    ptyNode = objectNode;
                    break main;
                }
                final ASTIdentifierAccess achild = (ASTIdentifierAccess) child;
                if (achild.isSafe() || achild.isExpression()) {
                    break main;
                }
                ant.append('.');
                ant.append(achild.getName());
            }
            // solve antish
            object = context.get(ant.toString());
        } else if (c != numChildren - 1) {
            // only the last one may be null
            ptyNode = objectNode;
            // 
            break;
        }
    }
    // dealing with null
    if (object == null) {
        if (ptyNode != null) {
            if (ptyNode.isSafeLhs(isSafe())) {
                return null;
            }
            if (ant != null) {
                final String aname = ant.toString();
                final boolean defined = isVariableDefined(frame, block, aname);
                return unsolvableVariable(node, aname, !defined);
            }
            return unsolvableProperty(node, stringifyProperty(ptyNode), ptyNode == objectNode, null);
        }
        if (antish) {
            if (node.isSafeLhs(isSafe())) {
                return null;
            }
            final String aname = ant != null ? ant.toString() : "?";
            final boolean defined = isVariableDefined(frame, block, aname);
            // defined but null; arg of a strict operator?
            if (defined && !isStrictOperand(node)) {
                return null;
            }
            return unsolvableVariable(node, aname, !defined);
        }
    }
    return object;
}
Also used : JexlNode(org.apache.commons.jexl3.parser.JexlNode) ASTIdentifier(org.apache.commons.jexl3.parser.ASTIdentifier) ASTMethodNode(org.apache.commons.jexl3.parser.ASTMethodNode) ASTReference(org.apache.commons.jexl3.parser.ASTReference) ASTIdentifierAccess(org.apache.commons.jexl3.parser.ASTIdentifierAccess) ASTArrayAccess(org.apache.commons.jexl3.parser.ASTArrayAccess)

Example 2 with ASTArrayAccess

use of org.apache.commons.jexl3.parser.ASTArrayAccess in project commons-jexl by apache.

the class InterpreterBase method setAttribute.

/**
 * Sets an attribute of an object.
 *
 * @param object    to set the value to
 * @param attribute the attribute of the object, e.g. an index (1, 0, 2) or key for a map
 * @param value     the value to assign to the object's attribute
 * @param node      the node that evaluated as the object
 */
protected void setAttribute(final Object object, final Object attribute, final Object value, final JexlNode node) {
    cancelCheck(node);
    final JexlOperator operator = node != null && node.jjtGetParent() instanceof ASTArrayAccess ? JexlOperator.ARRAY_SET : JexlOperator.PROPERTY_SET;
    final Object result = operators.tryOverload(node, operator, object, attribute, value);
    if (result != JexlEngine.TRY_FAILED) {
        return;
    }
    Exception xcause = null;
    try {
        // attempt to reuse last executor cached in volatile JexlNode.value
        if (node != null && cache) {
            final Object cached = node.jjtGetValue();
            if (cached instanceof JexlPropertySet) {
                final JexlPropertySet setter = (JexlPropertySet) cached;
                final Object eval = setter.tryInvoke(object, attribute, value);
                if (!setter.tryFailed(eval)) {
                    return;
                }
            }
        }
        final List<JexlUberspect.PropertyResolver> resolvers = uberspect.getResolvers(operator, object);
        JexlPropertySet vs = uberspect.getPropertySet(resolvers, object, attribute, value);
        // if we can't find an exact match, narrow the value argument and try again
        if (vs == null) {
            // replace all numbers with the smallest type that will fit
            final Object[] narrow = { value };
            if (arithmetic.narrowArguments(narrow)) {
                vs = uberspect.getPropertySet(resolvers, object, attribute, narrow[0]);
            }
        }
        if (vs != null) {
            // cache executor in volatile JexlNode.value
            vs.invoke(object, value);
            if (node != null && cache && vs.isCacheable()) {
                node.jjtSetValue(vs);
            }
            return;
        }
    } catch (final Exception xany) {
        xcause = xany;
    }
    // lets fail
    if (node == null) {
        // direct call
        final String error = "unable to set object property" + ", class: " + object.getClass().getName() + ", property: " + attribute + ", argument: " + value.getClass().getSimpleName();
        throw new UnsupportedOperationException(error, xcause);
    }
    final String attrStr = attribute != null ? attribute.toString() : null;
    unsolvableProperty(node, attrStr, true, xcause);
}
Also used : JexlPropertySet(org.apache.commons.jexl3.introspection.JexlPropertySet) JexlOperator(org.apache.commons.jexl3.JexlOperator) ASTArrayAccess(org.apache.commons.jexl3.parser.ASTArrayAccess) JexlException(org.apache.commons.jexl3.JexlException)

Example 3 with ASTArrayAccess

use of org.apache.commons.jexl3.parser.ASTArrayAccess in project commons-jexl by apache.

the class Engine method getVariables.

/**
 * Fills up the list of variables accessed by a node.
 * @param script the owning script
 * @param node the node
 * @param collector the variable collector
 */
protected void getVariables(final ASTJexlScript script, final JexlNode node, final VarCollector collector) {
    if (node instanceof ASTIdentifier) {
        final JexlNode parent = node.jjtGetParent();
        if (parent instanceof ASTMethodNode || parent instanceof ASTFunctionNode) {
            // skip identifiers for methods and functions
            collector.collect(null);
            return;
        }
        final ASTIdentifier identifier = (ASTIdentifier) node;
        final int symbol = identifier.getSymbol();
        // symbols that are captured are considered "global" variables
        if (symbol >= 0 && script != null && !script.isCapturedSymbol(symbol)) {
            collector.collect(null);
        } else {
            // start collecting from identifier
            collector.collect(identifier);
            collector.add(identifier.getName());
        }
    } else if (node instanceof ASTIdentifierAccess) {
        final JexlNode parent = node.jjtGetParent();
        if (parent instanceof ASTMethodNode || parent instanceof ASTFunctionNode) {
            // skip identifiers for methods and functions
            collector.collect(null);
            return;
        }
        // belt and suspender since an identifier should have been seen first
        if (collector.isCollecting()) {
            collector.add(((ASTIdentifierAccess) node).getName());
        }
    } else if (node instanceof ASTArrayAccess && collector.mode > 0) {
        final int num = node.jjtGetNumChildren();
        // collect only if array access is const and follows an identifier
        boolean collecting = collector.isCollecting();
        for (int i = 0; i < num; ++i) {
            final JexlNode child = node.jjtGetChild(i);
            if (collecting && child.isConstant()) {
                // collect all constants or only string and number literals
                final boolean collect = collector.mode > 1 || (child instanceof ASTStringLiteral || child instanceof ASTNumberLiteral);
                if (collect) {
                    final String image = child.toString();
                    collector.add(image);
                }
            } else {
                collecting = false;
                collector.collect(null);
                getVariables(script, child, collector);
                collector.collect(null);
            }
        }
    } else {
        final int num = node.jjtGetNumChildren();
        for (int i = 0; i < num; ++i) {
            getVariables(script, node.jjtGetChild(i), collector);
        }
        collector.collect(null);
    }
}
Also used : ASTStringLiteral(org.apache.commons.jexl3.parser.ASTStringLiteral) ASTFunctionNode(org.apache.commons.jexl3.parser.ASTFunctionNode) ASTIdentifier(org.apache.commons.jexl3.parser.ASTIdentifier) JexlNode(org.apache.commons.jexl3.parser.JexlNode) ASTMethodNode(org.apache.commons.jexl3.parser.ASTMethodNode) ASTIdentifierAccess(org.apache.commons.jexl3.parser.ASTIdentifierAccess) ASTArrayAccess(org.apache.commons.jexl3.parser.ASTArrayAccess) ASTNumberLiteral(org.apache.commons.jexl3.parser.ASTNumberLiteral)

Example 4 with ASTArrayAccess

use of org.apache.commons.jexl3.parser.ASTArrayAccess in project commons-jexl by apache.

the class InterpreterBase method getAttribute.

/**
 * Gets an attribute of an object.
 *
 * @param object    to retrieve value from
 * @param attribute the attribute of the object, e.g. an index (1, 0, 2) or key for a map
 * @param node      the node that evaluated as the object
 * @return the attribute value
 */
protected Object getAttribute(final Object object, final Object attribute, final JexlNode node) {
    if (object == null) {
        throw new JexlException(node, "object is null");
    }
    cancelCheck(node);
    final JexlOperator operator = node != null && node.jjtGetParent() instanceof ASTArrayAccess ? JexlOperator.ARRAY_GET : JexlOperator.PROPERTY_GET;
    final Object result = operators.tryOverload(node, operator, object, attribute);
    if (result != JexlEngine.TRY_FAILED) {
        return result;
    }
    Exception xcause = null;
    try {
        // attempt to reuse last executor cached in volatile JexlNode.value
        if (node != null && cache) {
            final Object cached = node.jjtGetValue();
            if (cached instanceof JexlPropertyGet) {
                final JexlPropertyGet vg = (JexlPropertyGet) cached;
                final Object value = vg.tryInvoke(object, attribute);
                if (!vg.tryFailed(value)) {
                    return value;
                }
            }
        }
        // resolve that property
        final List<JexlUberspect.PropertyResolver> resolvers = uberspect.getResolvers(operator, object);
        final JexlPropertyGet vg = uberspect.getPropertyGet(resolvers, object, attribute);
        if (vg != null) {
            final Object value = vg.invoke(object);
            // cache executor in volatile JexlNode.value
            if (node != null && cache && vg.isCacheable()) {
                node.jjtSetValue(vg);
            }
            return value;
        }
    } catch (final Exception xany) {
        xcause = xany;
    }
    // lets fail
    if (node == null) {
        // direct call
        final String error = "unable to get object property" + ", class: " + object.getClass().getName() + ", property: " + attribute;
        throw new UnsupportedOperationException(error, xcause);
    }
    final boolean safe = (node instanceof ASTIdentifierAccess) && ((ASTIdentifierAccess) node).isSafe();
    if (safe) {
        return null;
    }
    final String attrStr = attribute != null ? attribute.toString() : null;
    return unsolvableProperty(node, attrStr, true, xcause);
}
Also used : JexlException(org.apache.commons.jexl3.JexlException) JexlOperator(org.apache.commons.jexl3.JexlOperator) JexlPropertyGet(org.apache.commons.jexl3.introspection.JexlPropertyGet) ASTArrayAccess(org.apache.commons.jexl3.parser.ASTArrayAccess) JexlException(org.apache.commons.jexl3.JexlException) ASTIdentifierAccess(org.apache.commons.jexl3.parser.ASTIdentifierAccess)

Example 5 with ASTArrayAccess

use of org.apache.commons.jexl3.parser.ASTArrayAccess in project commons-jexl by apache.

the class Interpreter method visit.

@Override
protected Object visit(final ASTArrayAccess node, final Object data) {
    // first objectNode is the identifier
    Object object = data;
    // can have multiple nodes - either an expression, integer literal or reference
    final int numChildren = node.jjtGetNumChildren();
    for (int i = 0; i < numChildren; i++) {
        final JexlNode nindex = node.jjtGetChild(i);
        if (object == null) {
            return unsolvableProperty(nindex, stringifyProperty(nindex), false, null);
        }
        final Object index = nindex.jjtAccept(this, null);
        cancelCheck(node);
        object = getAttribute(object, index, nindex);
    }
    return object;
}
Also used : JexlNode(org.apache.commons.jexl3.parser.JexlNode)

Aggregations

ASTArrayAccess (org.apache.commons.jexl3.parser.ASTArrayAccess)5 ASTIdentifierAccess (org.apache.commons.jexl3.parser.ASTIdentifierAccess)4 JexlNode (org.apache.commons.jexl3.parser.JexlNode)4 JexlException (org.apache.commons.jexl3.JexlException)3 ASTIdentifier (org.apache.commons.jexl3.parser.ASTIdentifier)3 JexlOperator (org.apache.commons.jexl3.JexlOperator)2 ASTMethodNode (org.apache.commons.jexl3.parser.ASTMethodNode)2 ASTReference (org.apache.commons.jexl3.parser.ASTReference)2 JexlPropertyGet (org.apache.commons.jexl3.introspection.JexlPropertyGet)1 JexlPropertySet (org.apache.commons.jexl3.introspection.JexlPropertySet)1 ASTFunctionNode (org.apache.commons.jexl3.parser.ASTFunctionNode)1 ASTNumberLiteral (org.apache.commons.jexl3.parser.ASTNumberLiteral)1 ASTStringLiteral (org.apache.commons.jexl3.parser.ASTStringLiteral)1 ASTVar (org.apache.commons.jexl3.parser.ASTVar)1