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

package ilog.language.design.kernel;

/**
 * @version     Last modified on Fri Oct 18 17:51:03 2002 by hak
 * @version          modified on Wed Jul 24 12:18:45 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.*;

/**
 * This class is the class of field update expressions.
 */
public class FieldUpdate extends ProtoExpression
{
  /**
   * The object expression whose field is updated.
   */
  private Expression _object;

  /**
   * The field global symbol.
   */
  private Global _field;

  /**
   * The expression whose value is assigned to the object's field.
   */
  private Expression _value;

  /**
   * Constructs a field update with the specified object expression, field
   * name and value expression.
   */
  public FieldUpdate (Expression object, Global field, Expression value)
    {
      _object = object;
      _field = field;
      _value = value; 
    }

  public final int numberOfSubexpressions ()
    {
      return 3;
    }

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

      throw new NoSuchSubexpressionException(this,n);
    }

  /**
   * Sanitizes the names of all expressions in the field update.
   */
  public final Expression sanitizeNames (ParameterStack parameters, ClassTypeHandle handle)
    {
      _object = _object.sanitizeNames(parameters, handle);
      _value = _value.sanitizeNames(parameters, handle);
      return this;
    }

  /**
   * Sanitizes the sorts of all expressions in the field update.
   */
  public final void sanitizeSorts (Enclosure enclosure)
    {
      _object.sanitizeSorts(enclosure);
      _value.sanitizeSorts(enclosure);
    }

  /**
   * Shifts the offsets of all the expressions in this field update.
   */
  public final Expression shiftOffsets (int intShift, int realShift, int objectShift,
                                        int intDepth, int realDepth, int objectDepth)
    {      
      _object = _object.shiftOffsets(intShift,realShift,objectShift,
                                     intDepth,realDepth,objectDepth);

      _value = _value.shiftOffsets(intShift,realShift,objectShift,
                                   intDepth,realDepth,objectDepth);

      return this;
    }

  /**
   * Sets the checked type of the expression of this field update.
   */
  public final void setCheckedType ()
    {
      if (isSetCheckedType()) return;
      setCheckedType(type().copy());
      _object.setCheckedType();
      _field.setCheckedType();
      _value.setCheckedType();
    }

  /**
   * Type-checks this field update in the context of the specified
   * <a href="../types/TypeChecker.html"> <tt>TypeChecker</tt></a>.
   * <b>NB:</b> The type of a field update is that of the object,
   * not of the value. This is to let several updates be performed
   * in sequence on the same object on top of the result stack without
   * having to push/pop. This feature is used explicitly when objects
   * are initialized (see <a href="../types/ClassInfo.html#initialize">
   * <tt>ClassInfo</tt></a>).
   */
  public final void typeCheck (TypeChecker typeChecker) throws TypingErrorException
    {
      if (typeCheckLocked()) return;

      _value.typeCheck(typeChecker);
      new Application(_field,_object).typeCheck(_value.typeRef(),typeChecker);

      if (!(_object.type() instanceof ClassType))
        throw locate(new AssignmentErrorException("bad field update: "+_object.type()+
                                                  " is not a class type"));
      if (!_field.codeEntry().isField())
        throw locate(new AssignmentErrorException("bad field update: "+_field+
                                                  " is not a field for class type "+
                                                  _object.type()));
      typeChecker.typeCheck(this,_object.typeRef());
    }
    
  /**
   * Compiles this field update of expressions in the context of the specified
   * <a href="Compiler.html"><tt>Compiler</tt></a>.
   */
  public final void compile (Compiler compiler)
    {
      _object.compile(compiler);
      _value.compile(compiler);

      DefinedEntry fieldEntry = _field.definedEntry();

      switch(fieldEntry.fieldSort())
        {
        case Type.INT_SORT:
          if (_value.checkedType().isBoxedType())
            compiler.generateUnwrapper(Type.INT_SORT);
          compiler.generate(new SetIntField(fieldEntry));
          return;
        case Type.REAL_SORT:
          if (_value.checkedType().isBoxedType())
            compiler.generateUnwrapper(Type.REAL_SORT);
          compiler.generate(new SetRealField(fieldEntry));
          return;
        default:
          if (!_value.checkedType().isBoxedType())
            compiler.generateWrapper(_value.sort());
          compiler.generate(new SetObjectField(fieldEntry));
          return;
        }
    }
    
  public final String toString ()
    {
      return _object + "." + _field + " = " + _value;
    }

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