//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\
// 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:15 2002 by hak
 * @author      <a href="mailto:hak@ilog.fr">Hassan A&iuml;t-Kaci</a>
 * @copyright   &copy; 2002 <a href="http://www.ilog.fr/">ILOG, S.A.</a>
 */

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

/**
 * This class denotes an expression as a yet undecided choice between two
 * expressions. It is used for an expression that may be either of two options
 * depending of their types when their respective types can be determined only
 * from the syntactic nature of these expressions. Therefore, <i>this construct
 * is only safe to use on two expressions that may not be simultaneously
 * well-typed based on their internal structures</i> (as opposed to the
 * preceding typing context). The semantics of this construct is simply that of
 * the first expression if it can be type-checked without backtracking to an
 * earlier state; otherwise it is that of the second expression.
 *
 * <p>
 *
 * If more than two options are to be considered, this expression may be nested
 * within similar expressions. The typechecker maintains a stack of cut-point
 * states to ensure that the correct typing context is recovered for each such
 * undecided expression choice.
 */
public class UndecidedExpression extends Expression
{
  private Expression _fstOption;
  private Expression _sndOption;
  private Expression _actualChoice;

  public UndecidedExpression (Expression first, Expression second)
    {
      _fstOption = first;
      _sndOption = second;
      _actualChoice = _fstOption;
    }

  public final int numberOfSubexpressions ()
    {
      return 2;
    }

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

      throw new NoSuchSubexpressionException(this,n);
    }

  public final Type type ()
    {
      return _actualChoice.type();
    }

  public final void setType (Type type)
    {
      _actualChoice.setType(type);
    }

  public final Type typeRef ()
    {
      return _actualChoice.typeRef();
    }

  public final Type checkedType ()
    {
      return _actualChoice.checkedType();
    }

  public final void setCheckedType ()
    {
      if (isSetCheckedType()) return;
      _actualChoice.setCheckedType();
    }

  public final void setCheckedType (Type type)
    {
      _actualChoice.setCheckedType(type);
    }

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

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

  public final Expression shiftOffsets (int intShift, int realShift, int objectShift,
                                        int intDepth, int realDepth, int objectDepth)
    {
      return _actualChoice.shiftOffsets(intShift,realShift,objectShift,intDepth,realDepth, objectDepth);
    }

  /**
   * Type-checking an <tt>UndecidedExpression</tt> works as follows:
   * <ol>
   * <li> a <a href="../types/TypingSTate.html"><tt>TypingSTate</tt></a> is pushed on
   *      the typechecker's cut-point stack in order to inhibit backtracking before
   *      this point;
   * <li> the first option expression is typechecked;
   * <li> if type-checking succeeds, the typechecker's cut-point stack is popped;
   * <li> if it fails:
   *      <ol>
   *      <li> all the typechecker's goals trailed after the latest cut-point
   *           are thrown away;
   *      <li> all the other typechecker's trails are unwound up to the points
   *           indicated by the latest cut-point;
   *      <li> the cut-point stack is popped;
   *      <li> the second option is typechecked as the actual expression.
   *      </ol>
   * </ol>
   * Note that if later bactracking comes back before this expression, only the previously
   * selected  option will be considered. This is fine for this construct's purpose since
   * the decision to choose between the two options must depend only on the syntactic nature
   * of the two expressions, and not the preceding typing context. Hence, a second pass of
   * type-checking is bound to give the same choice.
   */
  public final void typeCheck (TypeChecker typeChecker) throws TypingErrorException
    {
      if (typeCheckLocked()) return;

      typeChecker.pushCutPoint();

      try
        {
          _fstOption.typeCheck(typeChecker);
          typeChecker.popCutPoint();
        }
      catch (TypingErrorException error)
        {
          typeChecker.undoCutPoint(); // this will also pop the cut-point
          (_actualChoice = _sndOption).typeCheck(typeChecker);
        }
    }

  public final void compile (Compiler compiler)
    {
      _actualChoice.compile(compiler);
    }

  final public String toString ()
    {
      return _actualChoice.toString();
    }

  final public String toTypedString ()
    {
      return _actualChoice.toTypedString();
    }
}
