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

package hlt.language.design.instructions;

/**
 * @version     Last modified on Wed Jun 20 14:29:51 2012 by hak
 * @author      <a href="mailto:hak@acm.org">Hassan A&iuml;t-Kaci</a>
 * @copyright   &copy; <a href="http://www.hassan-ait-kaci.net/">by the author</a>
 */

import hlt.language.design.types.CodeEntry;
import hlt.language.design.backend.Block;
import hlt.language.design.backend.Runtime;

/**
 * A <tt>PushScope</tt> instruction is to a <a href="PushClosure.html"><tt>PushClosure</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 a <tt>PushClosure</tt> that does not need any frame machinery. 
 */
public class PushScope extends Instruction implements PushObject
{
  protected int _address;
  protected int _voidArity;
  protected int _intArity;
  protected int _realArity;
  protected int _objectArity;
  protected Instruction[] _code;

  public PushScope (int voidArity, int intArity, int realArity, int objectArity)
    {
      setName("PUSH_SCOPE");
      _voidArity = voidArity;
      _intArity = intArity;
      _realArity = realArity;
      _objectArity = objectArity;
    }

  public PushScope (int voidArity, int address, int intArity, int realArity, int objectArity)
    {
      this(voidArity,intArity,realArity,objectArity);
      setAddress(address);
    }

  public boolean isExitable ()
    {
      return false;
    }

  final int address ()
    {
      return _address;
    }
  
  final int voidArity ()
    {
      return _voidArity;
    }
  
  final int intArity ()
    {
      return _intArity;
    }
  
  final int realArity ()
    {
      return _realArity;
    }
  
  final int objectArity ()
    {
      return _objectArity;
    }
  
  final Instruction[] code ()
    {
      return _code;
    }
  
  public final PushScope setAddress (int address)
    {
      _address = address;
      return this;
    }

  public final PushScope setCode (Instruction[] code)
    {
      _code = code;
      return this;
    }

  public final Instruction setReferenceCode (Instruction[] code)
    {
      if (_code != null)
        return this;

      _code = code;
      return this;
    }

  public void execute (Runtime r)
    {
      r.pushObject(new Block(_code,
                             _address,
                             _voidArity,
                             _intArity,
                             _realArity,
                             _objectArity));
      r.incIP();
    }

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

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

      PushScope pushScope = (PushScope)object;

      return _name            == pushScope.name()
          && _address         == pushScope.address()
          && _voidArity       == pushScope.voidArity()
          && _intArity        == pushScope.intArity()
          && _realArity       == pushScope.realArity()
          && _objectArity     == pushScope.objectArity()
          && (_code == null ? pushScope.code() == null : _code == pushScope.code());
    }

  public int hashCode ()
    {
      return _name.hashCode() + 2*_address + (_code == null ? 0 : 3*_code.length)
                              + 5*_voidArity + 7*_intArity + 11*_realArity + 13*_objectArity;
    }

  public String toString ()
    {
      return _name
           + "("+ CodeEntry.getId(_code) + "," + _address + ","
           + "<" + _voidArity + "," + _intArity + "," + _realArity + "," + _objectArity + ">)";
    }
}
