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 */ 017package org.apache.commons.jxpath.ri.compiler; 018 019import 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 19:46:46 +0200 (Fr, 02 Mai 2008) $ 027 */ 028public 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}