    001    /*
    002     * Licensed to the Apache Software Foundation (ASF) under one or more
    003     * contributor license agreements.  See the NOTICE file distributed with
    004     * this work for additional information regarding copyright ownership.
    005     * The ASF licenses this file to You under the Apache License, Version 2.0
    006     * (the "License"); you may not use this file except in compliance with
    007     * the License.  You may obtain a copy of the License at
    008     *
    009     *      http://www.apache.org/licenses/LICENSE-2.0
    010     *
    011     * Unless required by applicable law or agreed to in writing, software
    012     * distributed under the License is distributed on an "AS IS" BASIS,
    013     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    014     * See the License for the specific language governing permissions and
    015     * limitations under the License.
    016     */
    017    package org.apache.commons.jexl2.parser;
    018
    019    import org.apache.commons.jexl2.DebugInfo;
    020    import org.apache.commons.jexl2.JexlInfo;
    021
    022    /**
    023     * Base class for parser nodes - holds an 'image' of the token for later use.
    024     *
    025     * @since 2.0
    026     */
    027    public abstract class JexlNode extends SimpleNode implements JexlInfo {
    028        /** A marker interface for literals.
    029         * @param <T> the literal type
    030         */
    031        public interface Literal<T> {
    032            T getLiteral();
    033        }
    034        /** token value. */
    035        public String image;
    036
    037        public JexlNode(int id) {
    038            super(id);
    039        }
    040
    041        public JexlNode(Parser p, int id) {
    042            super(p, id);
    043        }
    044
    045        /** {@inheritDoc} */
    046        public DebugInfo debugInfo() {
    047            JexlNode node = this;
    048            while (node != null) {
    049                if (node.value instanceof DebugInfo) {
    050                    return (DebugInfo) node.value;
    051                }
    052                node = node.jjtGetParent();
    053            }
    054            return null;
    055        }
    056
    057        /** {@inheritDoc} */
    058        public String debugString() {
    059            DebugInfo info = debugInfo();
    060            return info != null ? info.debugString() : "";
    061        }
    062
    063        /**
    064         * Whether this node is a constant node
    065         * Its value can not change after the first evaluation and can be cached indefinitely.
    066         * @return true if constant, false otherwise
    067         */
    068        public final boolean isConstant() {
    069            return isConstant(this instanceof JexlNode.Literal<?>);
    070        }
    071
    072        protected boolean isConstant(boolean literal) {
    073            if (literal) {
    074                if (children != null) {
    075                    for (JexlNode child : children) {
    076                        if (child instanceof ASTReference) {
    077                            boolean is = child.isConstant(true);
    078                            if (!is) {
    079                                return false;
    080                            }
    081                        } else if (child instanceof ASTMapEntry) {
    082                            boolean is = child.isConstant(true);
    083                            if (!is) {
    084                                return false;
    085                            }
    086                        } else if (!child.isConstant()) {
    087                            return false;
    088                        }
    089                    }
    090                }
    091                return true;
    092            }
    093            return false;
    094        }
    095    }