//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\
// PLEASE DO NOT EDIT WITHOUT THE EXPLICIT CONSENT OF THE AUTHOR! \\
//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\

package ilog.language.design.kernel;

/**
 * @version     Last modified on Fri Oct 18 17:52:09 2002 by hak
 * @version          modified on Wed Jul 24 12:19:36 2002 by pviry
 * @author      <a href="mailto:hak@ilog.fr">Hassan A&iuml;t-Kaci</a>
 * @copyright   &copy; 2000-2002 <a href="http://www.ilog.fr/">ILOG, S.A.</a>
 */

import ilog.language.design.types.*;
import ilog.language.design.base.*;

import java.util.ArrayList;

/**
 * This is the class of expressions for updating tuple components.
 */
public class TupleUpdate extends ProtoExpression
{
  private Expression _component;
  private Expression _value;

  private boolean _componentIsBoxed = false;
  private boolean _valueIsBoxed = false;

  public TupleUpdate (Expression tupleComponent, Expression value)
    {
      _component = tupleComponent;
      _value = value;
    }

  public final int numberOfSubexpressions ()
    {
      return 2;
    }

  public final Expression subexpression (int n) throws NoSuchSubexpressionException
    {
      switch (n)
        {
        case 0:
          return _component;
        case 1:
          return _value;
        }

      throw new NoSuchSubexpressionException(this,n);
    }

  public final Expression tuple ()
    {
      return ((TupleProjection)_component).tuple();
    }

  public final Expression sanitizeNames (ParameterStack parameters, ClassTypeHandle handle)
    {
      _component = _component.sanitizeNames(parameters, handle);
      _value = _value.sanitizeNames(parameters, handle);
      return this;
    }

  public final void sanitizeSorts (Enclosure enclosure)
    {
      _component.sanitizeSorts(enclosure);
      _value.sanitizeSorts(enclosure);
    }

  public final Expression shiftOffsets (int intShift, int realShift, int objectShift,
                                        int intDepth, int realDepth, int objectDepth)
    {
      _component = _component.shiftOffsets(intShift,realShift,objectShift,
                                                     intDepth,realDepth,objectDepth);
      _value = _value.shiftOffsets(intShift,realShift,objectShift,
                                   intDepth,realDepth,objectDepth);
      return this;
    }

  public final void setCheckedType ()
    {
      if (isSetCheckedType()) return;
      _component.setCheckedType();
      _value.setCheckedType();
      _checkedType = type().copy();
    }

  public final void typeCheck (TypeChecker typeChecker) throws TypingErrorException
    {
      if (typeCheckLocked()) return;

      _component.typeCheck(typeChecker);
      _componentIsBoxed = _component.type().isBoxedType();      // DANGER: this should be trailed!

      _value.typeCheck(typeChecker);
      _valueIsBoxed = _value.type().isBoxedType();              // DANGER: this should be trailed!

      typeChecker.typeCheck(this,_component.typeRef());
      typeChecker.typeCheck(this,_value.typeRef());
      type().setBoxed(_componentIsBoxed);
    }

  /**
   * Compile in this order:
   * <ol>
   * <li> the tuple,
   * <li> the value,
   * <li> possibly un/box the value,
   * <li> the <tt>SET</tt> instruction.
   * </ol>
   */
  public final void compile (Compiler compiler)
    {
      tuple().compile(compiler);
      _value.compile(compiler);
      if (_componentIsBoxed)
        {
          if (!_valueIsBoxed)
            compiler.generateWrapper(sort());
        }
      else
        if (_valueIsBoxed)
          compiler.generateUnwrapper(sort());
      compiler.generate(_setTupleComponent(_componentIsBoxed ? Type.OBJECT_SORT : sort()));
    }

  private final Instruction _setTupleComponent(byte sort)
    {
      int offset = ((TupleProjection)_component).offset();

      switch (sort)
        {
        case Type.INT_SORT:
          return new SetIntTupleComponent(offset);
        case Type.REAL_SORT:
          return new SetRealTupleComponent(offset);
        default:
          return new SetObjectTupleComponent(offset);
        }
    }

  public final String toString ()
    {
      return _component + " = " + _value;
    }

  // Added by PV
  public final String toTypedString ()
    {
        return typed(_component.toTypedString() + " = " + _value.toTypedString());
    }
}
