1 /*
   2  * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
   3  */
   4 /*
   5  * Licensed to the Apache Software Foundation (ASF) under one or more
   6  * contributor license agreements.  See the NOTICE file distributed with
   7  * this work for additional information regarding copyright ownership.
   8  * The ASF licenses this file to You under the Apache License, Version 2.0
   9  * (the "License"); you may not use this file except in compliance with
  10  * the License.  You may obtain a copy of the License at
  11  *
  12  *      http://www.apache.org/licenses/LICENSE-2.0
  13  *
  14  * Unless required by applicable law or agreed to in writing, software
  15  * distributed under the License is distributed on an "AS IS" BASIS,
  16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  17  * See the License for the specific language governing permissions and
  18  * limitations under the License.
  19  */
  20 
  21 package com.sun.org.apache.xpath.internal.operations;
  22 
  23 import com.sun.org.apache.xml.internal.utils.QName;
  24 import com.sun.org.apache.xpath.internal.Expression;
  25 import com.sun.org.apache.xpath.internal.ExpressionOwner;
  26 import com.sun.org.apache.xpath.internal.XPathContext;
  27 import com.sun.org.apache.xpath.internal.XPathVisitor;
  28 import com.sun.org.apache.xpath.internal.objects.XObject;
  29 import java.util.List;
  30 
  31 /**
  32  * The baseclass for a binary operation.
  33  *
  34  * @LastModified: Oct 2017
  35  */
  36 public class Operation extends Expression implements ExpressionOwner
  37 {
  38     static final long serialVersionUID = -3037139537171050430L;
  39 
  40   /** The left operand expression.
  41    *  @serial */
  42   protected Expression m_left;
  43 
  44   /** The right operand expression.
  45    *  @serial */
  46   protected Expression m_right;
  47 
  48   /**
  49    * This function is used to fixup variables from QNames to stack frame
  50    * indexes at stylesheet build time.
  51    * @param vars List of QNames that correspond to variables.  This list
  52    * should be searched backwards for the first qualified name that
  53    * corresponds to the variable reference qname.  The position of the
  54    * QName in the vector from the start of the vector will be its position
  55    * in the stack frame (but variables above the globalsTop value will need
  56    * to be offset to the current stack frame).
  57    */
  58   public void fixupVariables(List<QName> vars, int globalsSize)
  59   {
  60     m_left.fixupVariables(vars, globalsSize);
  61     m_right.fixupVariables(vars, globalsSize);
  62   }
  63 
  64 
  65   /**
  66    * Tell if this expression or it's subexpressions can traverse outside
  67    * the current subtree.
  68    *
  69    * @return true if traversal outside the context node's subtree can occur.
  70    */
  71   public boolean canTraverseOutsideSubtree()
  72   {
  73 
  74     if (null != m_left && m_left.canTraverseOutsideSubtree())
  75       return true;
  76 
  77     if (null != m_right && m_right.canTraverseOutsideSubtree())
  78       return true;
  79 
  80     return false;
  81   }
  82 
  83   /**
  84    * Set the left and right operand expressions for this operation.
  85    *
  86    *
  87    * @param l The left expression operand.
  88    * @param r The right expression operand.
  89    */
  90   public void setLeftRight(Expression l, Expression r)
  91   {
  92     m_left = l;
  93     m_right = r;
  94     l.exprSetParent(this);
  95     r.exprSetParent(this);
  96   }
  97 
  98   /**
  99    * Execute a binary operation by calling execute on each of the operands,
 100    * and then calling the operate method on the derived class.
 101    *
 102    *
 103    * @param xctxt The runtime execution context.
 104    *
 105    * @return The XObject result of the operation.
 106    *
 107    * @throws javax.xml.transform.TransformerException
 108    */
 109   public XObject execute(XPathContext xctxt)
 110           throws javax.xml.transform.TransformerException
 111   {
 112 
 113     XObject left = m_left.execute(xctxt, true);
 114     XObject right = m_right.execute(xctxt, true);
 115 
 116     XObject result = operate(left, right);
 117     left.detach();
 118     right.detach();
 119     return result;
 120   }
 121 
 122   /**
 123    * Apply the operation to two operands, and return the result.
 124    *
 125    *
 126    * @param left non-null reference to the evaluated left operand.
 127    * @param right non-null reference to the evaluated right operand.
 128    *
 129    * @return non-null reference to the XObject that represents the result of the operation.
 130    *
 131    * @throws javax.xml.transform.TransformerException
 132    */
 133   public XObject operate(XObject left, XObject right)
 134           throws javax.xml.transform.TransformerException
 135   {
 136     return null;  // no-op
 137   }
 138 
 139   /** @return the left operand of binary operation, as an Expression.
 140    */
 141   public Expression getLeftOperand(){
 142     return m_left;
 143   }
 144 
 145   /** @return the right operand of binary operation, as an Expression.
 146    */
 147   public Expression getRightOperand(){
 148     return m_right;
 149   }
 150 
 151   class LeftExprOwner implements ExpressionOwner
 152   {
 153     /**
 154      * @see ExpressionOwner#getExpression()
 155      */
 156     public Expression getExpression()
 157     {
 158       return m_left;
 159     }
 160 
 161     /**
 162      * @see ExpressionOwner#setExpression(Expression)
 163      */
 164     public void setExpression(Expression exp)
 165     {
 166         exp.exprSetParent(Operation.this);
 167         m_left = exp;
 168     }
 169   }
 170 
 171   /**
 172    * @see com.sun.org.apache.xpath.internal.XPathVisitable#callVisitors(ExpressionOwner, XPathVisitor)
 173    */
 174   public void callVisitors(ExpressionOwner owner, XPathVisitor visitor)
 175   {
 176         if(visitor.visitBinaryOperation(owner, this))
 177         {
 178                 m_left.callVisitors(new LeftExprOwner(), visitor);
 179                 m_right.callVisitors(this, visitor);
 180         }
 181   }
 182 
 183   /**
 184    * @see ExpressionOwner#getExpression()
 185    */
 186   public Expression getExpression()
 187   {
 188     return m_right;
 189   }
 190 
 191   /**
 192    * @see ExpressionOwner#setExpression(Expression)
 193    */
 194   public void setExpression(Expression exp)
 195   {
 196         exp.exprSetParent(this);
 197         m_right = exp;
 198   }
 199 
 200   /**
 201    * @see Expression#deepEquals(Expression)
 202    */
 203   public boolean deepEquals(Expression expr)
 204   {
 205         if(!isSameClass(expr))
 206                 return false;
 207 
 208         if(!m_left.deepEquals(((Operation)expr).m_left))
 209                 return false;
 210 
 211         if(!m_right.deepEquals(((Operation)expr).m_right))
 212                 return false;
 213 
 214         return true;
 215   }
 216 }