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