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

package ilog.language.design.base;

/**
 * @version     Last modified on Sun Nov 03 18:49:49 2002 by hak
 * @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.Type;
import ilog.language.design.types.FunctionType;
import ilog.language.design.backend.Runtime;
import ilog.language.design.backend.Block;
import ilog.language.design.backend.NullValueException;

/**
 * An <tt>Enter</tt> instruction is to an <a href="Apply.html"><tt>Apply</tt></a>
 * instruction what a <a href="../kernel/Scope.html"><tt>Scope</tt></a> expression is to
 * an <a href="../kernel/Abstraction.html"><tt>Abstraction</tt></a> expression. In other words,
 * it is an <tt>Apply</tt> that does not use any frame machinery.
 */
public class Enter extends Instruction
{
  protected int _intArity;
  protected int _realArity;
  protected int _objectArity;

  protected Enter ()
    {
    }

  public Enter (int intArity, int realArity, int objectArity)
    {
      setName("ENTER");
      _intArity = intArity;
      _realArity = realArity;
      _objectArity = objectArity;
    }

  public Enter (FunctionType type)
    {
      setName("ENTER");
      for (int i=0; i<type.arity(); i++)
        switch (type.domain(i).boxSort())
          {
          case Type.INT_SORT:
            _intArity++;
            break;
          case Type.REAL_SORT:
            _realArity++;
            break;
          default:
           _objectArity++;
           break;
          }
    }

  final int intArity ()
    {
      return _intArity;
    }

  final int realArity ()
    {
      return _realArity;
    }

  final int objectArity ()
    {
      return _objectArity;
    }

  public final int arity ()
    {
      return _intArity + _realArity + _objectArity;
    }

  public void execute (Runtime r) throws NullValueException
    {
      _execute((Block)r.popObject("can't enter a null scope"),r);
    }
      
  protected final void _execute (Block b, Runtime r) throws NullValueException
    {
      // Type-checking guarantees that arity() == b.arity().
      int[] intArgs = new int[_intArity];
      for (int i=0; i<_intArity; i++)
        intArgs[i] = r.popInt();

      double[] realArgs = new double[_realArity];
      for (int i=0; i<_realArity; i++)
        realArgs[i] = r.popReal();

      Object[] objectArgs = new Object[_objectArity];
      for (int i=0; i<_objectArity; i++)
        objectArgs[i] = r.popObject();

      if (b.isExitable())
        r.enterExitableScope();
      else
        r.saveState();

      r.pushIntEnv(intArgs);
      r.pushRealEnv(realArgs);
      r.pushObjectEnv(objectArgs);

      r.setCode(b.code());
      r.setIP(b.address());
    }

  public boolean equals (Object object)
    {
      if (this == object)
        return true;

      if (!(object instanceof Enter))
        return false;

      Enter enter = (Enter)object;

      return _intArity    == enter.intArity()
          && _realArity   == enter.realArity()
          && _objectArity == enter.objectArity();
    }

  public final int hashCode ()
    {
      return name().hashCode() + 2*_intArity + 3*_realArity + 5*_objectArity;
    }

  public final String toString ()
    {
      return name() + "(" + _intArity + "," + _realArity + "," + _objectArity + ")";
    }
}
