protected Object visit()

in src/main/java/org/apache/commons/jexl3/internal/Interpreter.java [1824:1939]


    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) && options.isAntish();
        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());
                    continue;
                    // skip the first node case since it was trialed in jjtAccept above and returned null
                }
                // 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 = c == 0 && numChildren > 1 ? node.jjtGetChild(1) : 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 = Objects.toString(ant, "?");
                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;
    }