View Javadoc
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 }