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. "<=", "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 }