    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.jxpath.ri.compiler;
    018
    019    import org.apache.commons.jxpath.ri.EvalContext;
    020
    021    /**
    022     * The common subclass for tree elements representing core operations like "+",
    023     * "- ", "*" etc.
    024     *
    025     * @author Dmitri Plotnikov
    026     * @version $Revision: 652845 $ $Date: 2008-05-02 12:46:46 -0500 (Fri, 02 May 2008) $
    027     */
    028    public abstract class CoreOperation extends Operation {
    029
    030        /** or precedence */
    031        protected static final int OR_PRECEDENCE = 0;
    032        /** and precedence */
    033        protected static final int AND_PRECEDENCE = 1;
    034        /** compare precedence */
    035        protected static final int COMPARE_PRECEDENCE = 2;
    036        /** relational expression precedence */
    037        protected static final int RELATIONAL_EXPR_PRECEDENCE = 3;
    038        /** add/subtract precedence */
    039        protected static final int ADD_PRECEDENCE = 4;
    040        /** multiply/divide/mod precedence */
    041        protected static final int MULTIPLY_PRECEDENCE = 5;
    042        /** negate precedence */
    043        protected static final int NEGATE_PRECEDENCE = 6;
    044        /** union precedence */
    045        protected static final int UNION_PRECEDENCE = 7;
    046
    047        /**
    048         * Create a new CoreOperation.
    049         * @param args Expression[]
    050         */
    051        public CoreOperation(Expression[] args) {
    052            super(args);
    053        }
    054
    055        public Object compute(EvalContext context) {
    056            return computeValue(context);
    057        }
    058
    059        public abstract Object computeValue(EvalContext context);
    060
    061        /**
    062         * Returns the XPath symbol for this operation, e.g. "+", "div", etc.
    063         * @return String symbol
    064         */
    065        public abstract String getSymbol();
    066
    067        /**
    068         * Returns true if the operation is not sensitive to the order of arguments,
    069         * e.g. "=", "and" etc, and false if it is, e.g. "&lt;=", "div".
    070         * @return boolean
    071         */
    072        protected abstract boolean isSymmetric();
    073
    074        /**
    075         * Computes the precedence of the operation.
    076         * @return int precedence
    077         */
    078        protected abstract int getPrecedence();
    079
    080        public String toString() {
    081            if (args.length == 1) {
    082                return getSymbol() + parenthesize(args[0], false);
    083            }
    084            StringBuffer buffer = new StringBuffer();
    085            for (int i = 0; i < args.length; i++) {
    086                if (i > 0) {
    087                    buffer.append(' ');
    088                    buffer.append(getSymbol());
    089                    buffer.append(' ');
    090                }
    091                buffer.append(parenthesize(args[i], i == 0));
    092            }
    093            return buffer.toString();
    094        }
    095
    096        /**
    097         * Wrap an expression in parens if necessary.
    098         * @param expression other Expression
    099         * @param left whether <code>expression</code> is left of this one.
    100         * @return String
    101         */
    102        private String parenthesize(Expression expression, boolean left) {
    103            String s = expression.toString();
    104            if (!(expression instanceof CoreOperation)) {
    105                return s;
    106            }
    107            int compared = getPrecedence() - ((CoreOperation) expression).getPrecedence();
    108
    109            if (compared < 0) {
    110                return s;
    111            }
    112            if (compared == 0 && (isSymmetric() || left)) {
    113                return s;
    114            }
    115            return '(' + s + ')';
    116        }
    117    }