//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\
// 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:37 2002 by hak
 * @version          modified on Wed Jul 24 12:19:02 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 conditional looping expressions.
 *
 */
public class Loop extends Expression
{
  /**
   * The loop's condition being assigned.
   */
  private Expression _condition;

  /**
   * The loop's body.
   */
  private Expression _body;

  private Type _type = Type.VOID();

  /**
   * Constructs a loop with the specified condition and body.
   */
  public Loop (Expression condition, Expression body)
    {
      _condition = condition;
      _body = body; 
    }

  public final int numberOfSubexpressions ()
    {
      return 2;
    }

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

      throw new NoSuchSubexpressionException(this,n);
    }

  /**
   * Sanitizes the names of this loop.
   */
  public final Expression sanitizeNames (ParameterStack parameters, ClassTypeHandle handle)
    {
      _condition = _condition.sanitizeNames(parameters, handle);
      _body = _body.sanitizeNames(parameters, handle);
      return this;
    }

  /**
   * Sanitizes the sorts of this loop.
   */
  public final void sanitizeSorts (Enclosure enclosure)
    {
      _condition.sanitizeSorts(enclosure);
      _body.sanitizeSorts(enclosure);
    }
    
  /**
   * Shifts the offsets of all the expressions in this localAssignment.
   */
  public final Expression shiftOffsets (int intShift, int realShift, int objectShift,
                                        int intDepth, int realDepth, int objectDepth)
    {      
      _condition = _condition.shiftOffsets(intShift,realShift,objectShift,
                                           intDepth,realDepth,objectDepth);

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

      return this;
    }

  /**
   * The type of a loop is void.
   */
  public final Type type ()
    {
      return _type;
    }

  /**
   * No-op...
   */
  public final void setType (Type type)
    {
    }

  /**
   * The type reference of a loop is its type.
   */
  public final Type typeRef ()
    {
      return type();
    }

  /**
   * The checked type of a loop is its type.
   */
  public final Type checkedType ()
    {
      return type();
    }

  /**
   * Sets the checked type of the condition and body.
   */
  public final void setCheckedType ()
    {
      if (isSetCheckedType()) return;
      _condition.setCheckedType();
      _body.setCheckedType();
    }

  /**
   * No-op...
   */
  public final void setCheckedType (Type type)
    {
    }

  /**
   * Type-checks this loop in the context of the specified
   * <a href="./TypeChecker.html"> <tt>TypeChecker</tt></a>.
   */
  public final void typeCheck (TypeChecker typeChecker) throws TypingErrorException
    {
      if (typeCheckLocked()) return;

      _condition.typeCheck(Type.BOOLEAN(),typeChecker);   
      _body.typeCheck(typeChecker);
    }

  /**
   * Compiles this loop expression in the context of the specified
   * <a href="./Compiler.html"><tt>Compiler</tt></a>.
   */
  public final void compile (Compiler compiler)
    {
      int loop = compiler.targetAddress();

      _condition.compile(compiler);
      if (_condition.checkedType().isBoxedType())
        compiler.generateUnwrapper(Type.INT_SORT);

      JumpOnFalse jof = new JumpOnFalse();
      compiler.generate(jof);

      _body.compile(compiler);
      compiler.generateStackPop(_body.boxSort());

      compiler.generate(new Jump(loop));

      jof.setAddress(compiler.targetAddress());

      if (checkedType().isBoxedType())
        compiler.generate(Instruction.PUSH_BOXED_VOID);
      else
        compiler.generate(Instruction.PUSH_VOID);
    }
    
  final public String toString ()
    {
      return "while " + _condition + " do " + _body;
    }

  // Added by PV
  final public String toTypedString ()
    {
        return typed("while " + _condition.toTypedString() + " do " + _body.toTypedString());
    }
}
