Package nexj.core.persistence.operator

Source Code of nexj.core.persistence.operator.BinaryOperator

// Copyright 2010 NexJ Systems Inc. This software is licensed under the terms of the Eclipse Public License 1.0
package nexj.core.persistence.operator;

import java.io.IOException;

import nexj.core.meta.Primitive;
import nexj.core.meta.Type;
import nexj.core.meta.TypeMismatchException;
import nexj.core.persistence.Operator;
import nexj.core.persistence.Query;
import nexj.core.scripting.Pair;
import nexj.core.util.PrintWriter;

/**
* Binary operator expression node.
*/
public abstract class BinaryOperator extends Operator
{
   // associations

   /**
    * The left operand.
    */
   protected Operator m_left;

   /**
    * The right operand.
    */
   protected Operator m_right;

   // operations

   /**
    * Sets the left operand.
    * @param left The left operand to set. Can be null.
    * @return False if the operand is null.
    */
   public boolean setLeft(Operator left)
   {
      m_left = left;

      if (left == null)
      {
         return false;
      }

      left.setParent(this);

      return true;
   }

   /**
    * @return The left operand.
    */
   public Operator getLeft()
   {
      return m_left;
   }

   /**
    * Sets the right operand.
    * @param right The right operand to set. Can be null.
    * @return False if the operand is null.
    */
   public boolean setRight(Operator right)
   {
      m_right = right;

      if (right == null)
      {
         return false;
      }

      right.setParent(this);

      return true;
   }

   /**
    * @return The right operand.
    */
   public Operator getRight()
   {
      return m_right;
   }

   /**
    * @see nexj.core.persistence.Operator#visit(nexj.core.persistence.Operator.Visitor, int)
    */
   public boolean visit(Visitor visitor, int nFlags)
   {
      if ((nFlags & VISIT_PREORDER) != 0)
      {
         if (!visitor.visit(this))
         {
            return false;
         }
      }

      if (m_left != null)
      {
         if (visitor.isEligible(m_left))
         {
            if (!m_left.visit(visitor, nFlags))
            {
               return false;
            }
         }
      }

      if (m_right != null)
      {
         if (visitor.isEligible(m_right))
         {
            if (!m_right.visit(visitor, nFlags))
            {
               return false;
            }
         }
      }

      if ((nFlags & VISIT_POSTORDER) != 0)
      {
         if (!visitor.visit(this))
         {
            return false;
         }
      }

      return true;
   }

   /**
    * @see nexj.core.persistence.Operator#normalize(int)
    */
   public Operator normalize(int nFlags)
   {
      if ((nFlags & NORMALIZE_NORECUR) == 0)
      {
         m_left = m_left.normalize(nFlags);
         m_right = m_right.normalize(nFlags);
      }

      Type leftType = m_left.getType();
      Type rightType = m_right.getType();

      if (leftType == null || rightType == null)
      {
         m_type = null;
         setConstantValue(null);
      }
      else if (leftType.isPrimitive())
      {
         if (rightType.isPrimitive())
         {
            setSource(findCommonSource(m_left, m_right), nFlags);

            ConversionMapper mapper = null;
            BinaryDescriptor descriptor = null;
            Primitive resultType = null;

            if (m_source != null)
            {
               mapper = m_source.getAdapter().getConversionMapper();
               descriptor = mapper.getBinaryDescriptor(this);
            }

            if (descriptor == null)
            {
               m_source = null;
               mapper = getConversionMapper();
               descriptor = mapper.getBinaryDescriptor(this);

               if (descriptor == null)
               {
                  throw new TypeMismatchException(getSymbol());
               }
            }
            else
            {
               resultType = getConversionMapper().getBinaryDescriptor(this).getResultType();
            }

            if (mapper.getType((Primitive)leftType) != mapper.getType(descriptor.getLeftType()))
            {
               setLeft(new TypeConversionOperator(descriptor.getLeftType(), m_left));
               m_left = m_left.normalize(nFlags | NORMALIZE_NORECUR);
            }

            if (mapper.getType((Primitive)rightType) != mapper.getType(descriptor.getRightType()))
            {
               setRight(new TypeConversionOperator(descriptor.getRightType(), m_right));
               m_right = m_right.normalize(nFlags | NORMALIZE_NORECUR);
            }

            m_type = descriptor.getResultType();

            if (m_left.isConstant() && m_right.isConstant())
            {
               setConstantValue(evaluate());
            }

            if (m_source != null && mapper.getType((Primitive)m_type) != mapper.getType(resultType))
            {
               TypeConversionOperator result = new TypeConversionOperator(resultType, this);

               result.setParent(m_parent);
               m_parent = result;
               result.normalize(nFlags | NORMALIZE_NORECUR);

               return result;
            }
         }
         else
         {
            normalizeRightMetaclass(nFlags);
         }
      }
      else
      {
         return normalizeLeftMetaclass(nFlags);
      }

      return this;
   }

   /**
    * Normalizes the left operand with class type.
    * @see nexj.core.persistence.Operator#normalize(int)
    */
   protected Operator normalizeLeftMetaclass(int nFlags)
   {
      throw new TypeMismatchException(getSymbol());
   }

   /**
    * Normalizes the right operand with class type.
    * The left one if primitive.
    * @see nexj.core.persistence.Operator#normalize(int)
    */
   protected Operator normalizeRightMetaclass(int nFlags)
   {
      throw new TypeMismatchException(getSymbol());
   }

   /**
    * @see nexj.core.persistence.Operator#copy(nexj.core.persistence.Operator)
    */
   public void copy(Operator src)
   {
      super.copy(src);

      BinaryOperator op = (BinaryOperator)src;

      m_left = op.m_left;

      if (m_left != null)
      {
         m_left.setParent(this);
      }

      m_right = op.m_right;

      if (m_right != null)
      {
         m_right.setParent(this);
      }
   }

   /**
    * @see java.lang.Object#clone()
    */
   public Object clone()
   {
      BinaryOperator op = (BinaryOperator)super.clone();

      if (m_left != null)
      {
         op.setLeft((Operator)m_left.clone());
      }

      if (m_right != null)
      {
         op.setRight((Operator)m_right.clone());
      }

      return op;
   }

   /**
    * @see nexj.core.persistence.Operator#getExpression(nexj.core.persistence.Query)
    */
   public Object getExpression(Query root)
   {
      return Pair.binary(getSymbol(), m_left.getExpression(root), m_right.getExpression(root));
   }

   /**
    * @see nexj.core.persistence.Operator#compareTo(java.lang.Object)
    */
   public int compareTo(Object obj)
   {
      int n = super.compareTo(obj);

      if (n != 0)
      {
         return n;
      }

      BinaryOperator op = (BinaryOperator)obj;

      n = m_left.compareTo(op.getLeft());

      if (n != 0)
      {
         return n;
      }

      return m_right.compareTo(op.getRight());
   }

   /**
    * @see nexj.core.util.Printable#printOn(PrintWriter)
    */
   public void printOn(PrintWriter writer) throws IOException
   {
      writer.write('(');
  &#x