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

package ilog.language.design.base;

/**
 * @version     Last modified on Mon Sep 09 17:47:55 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.CodeEntry;
import ilog.language.design.backend.Closure;
import ilog.language.design.backend.Runtime;

/**
 * A <tt>PushClosure</tt> instruction is to a <a href="PushScope.html"><tt>PushScope</tt></a>
 * instruction what an <a href="../kernel/Abstraction.html"><tt>Abstraction</tt></a> expression
 * is to an <a href="../kernel/Scope.html"><tt>Scope</tt></a> expression. In other words, it is
 * a <tt>PushScope</tt> with the added frame machinery.
 */
public class PushClosure extends PushScope
{
  private int _intFrameSize;
  private int _realFrameSize;
  private int _objectFrameSize;

  public PushClosure (int intArity, int realArity, int objectArity,
                      int intFrameSize, int realFrameSize, int objectFrameSize)
    {
      super(intArity,realArity,objectArity);
      _intFrameSize = intFrameSize;
      _realFrameSize = realFrameSize;
      _objectFrameSize = objectFrameSize;
      setName("PUSH_CLOSURE");
    }

  public PushClosure (int address, int intArity, int realArity, int objectArity,
                      int intFrameSize, int realFrameSize, int objectFrameSize)
    {
      this(intArity,realArity,objectArity,intFrameSize,realFrameSize,objectFrameSize);
      setAddress(address);
    }

  final int intFrameSize ()
    {
      return _intFrameSize;
    }
  
  final int realFrameSize ()
    {
      return _realFrameSize;
    }
  
  final int objectFrameSize ()
    {
      return _objectFrameSize;
    }
  
  public final Instruction apply ()
    {
      return new Apply(_intArity,_realArity,_objectArity);
    }

  public final void execute (Runtime r)
    {
      r.pushObject(new Closure(_isExitable,
                               _code,
                               _address,
                               _intArity,
                               _realArity,
                               _objectArity,
                               r.copyIntEnv(_intFrameSize),
                               r.copyRealEnv(_realFrameSize),
                               r.copyObjectEnv(_objectFrameSize)));
      r.incIP();
    }

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

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

      PushClosure pushClosure = (PushClosure)object;

      return _address         == pushClosure.address()
          && _intArity        == pushClosure.intArity()
          && _realArity       == pushClosure.realArity()
          && _objectArity     == pushClosure.objectArity()
          && _intFrameSize    == pushClosure.intFrameSize()
          && _realFrameSize   == pushClosure.realFrameSize()
          && _objectFrameSize == pushClosure.objectFrameSize()
          && (_code == null ? pushClosure.code() == null : _code == pushClosure.code());
    }

  public final int hashCode ()
    {
      return name().hashCode() + 2*_address + (_code == null ? 0 : 3*_code.length)
           + 5*_intArity + 7*_realArity + 11*_objectArity
           + 13*_intFrameSize + 17*_realFrameSize + 19*_objectFrameSize;           
    }

  public final String toString ()
    {
      return name()
           + "(#"+ CodeEntry.getId(_code) + "," + _address + ","
           + "<" + _intArity + "," + _realArity + "," + _objectArity + ">,"
           + "<" + _intFrameSize + "," + _realFrameSize + "," + _objectFrameSize + ">)";
    }

}

