1 /*
2 * Licensed to the Apache Software Foundation (ASF) under one or more
3 * contributor license agreements. See the NOTICE file distributed with
4 * this work for additional information regarding copyright ownership.
5 * The ASF licenses this file to You under the Apache License, Version 2.0
6 * (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
18 package org.apache.commons.jxpath.ri.compiler;
19
20 import org.apache.commons.jxpath.ri.EvalContext;
21
22 /**
23 * The common subclass for tree elements representing core operations like "+", "- ", "*" etc.
24 */
25 public abstract class CoreOperation extends Operation {
26
27 /** Or precedence */
28 protected static final int OR_PRECEDENCE = 0;
29 /** And precedence */
30 protected static final int AND_PRECEDENCE = 1;
31 /** Compare precedence */
32 protected static final int COMPARE_PRECEDENCE = 2;
33 /** Relational expression precedence */
34 protected static final int RELATIONAL_EXPR_PRECEDENCE = 3;
35 /** Add/subtract precedence */
36 protected static final int ADD_PRECEDENCE = 4;
37 /** Multiply/divide/mod precedence */
38 protected static final int MULTIPLY_PRECEDENCE = 5;
39 /** Negate precedence */
40 protected static final int NEGATE_PRECEDENCE = 6;
41 /** Union precedence */
42 protected static final int UNION_PRECEDENCE = 7;
43
44 /**
45 * Constructs a new CoreOperation.
46 *
47 * @param args Expression[]
48 */
49 public CoreOperation(final Expression[] args) {
50 super(args);
51 }
52
53 @Override
54 public Object compute(final EvalContext context) {
55 return computeValue(context);
56 }
57
58 @Override
59 public abstract Object computeValue(EvalContext context);
60
61 /**
62 * Computes the precedence of the operation.
63 *
64 * @return int precedence
65 */
66 protected abstract int getPrecedence();
67
68 /**
69 * Returns the XPath symbol for this operation, e.g. "+", "div", etc.
70 *
71 * @return String symbol
72 */
73 public abstract String getSymbol();
74
75 /**
76 * 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".
77 *
78 * @return boolean
79 */
80 protected abstract boolean isSymmetric();
81
82 /**
83 * Wrap an expression in parens if necessary.
84 *
85 * @param expression other Expression
86 * @param left whether {@code expression} is left of this one.
87 * @return String
88 */
89 private String parenthesize(final Expression expression, final boolean left) {
90 final String s = expression.toString();
91 if (!(expression instanceof CoreOperation)) {
92 return s;
93 }
94 final int compared = getPrecedence() - ((CoreOperation) expression).getPrecedence();
95 if (compared < 0) {
96 return s;
97 }
98 if (compared == 0 && (isSymmetric() || left)) {
99 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 }