package ilog.language.design.types;

/**
 * @version     Last modified on Sat Aug 24 13:48: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.util.ObjectToIntMap;
import ilog.language.design.base.Instruction;

import java.util.HashMap;

/**
 * Objects of this class associate a <a href="./Symbol.html"><tt>Symbol</tt></a>
 * and a <a href="./Type.html"><tt>Type</tt></a> to code that may be executed
 * for it.  This code is either an array of instructions (if the symbol with
 * this type is user-defined) or a built-in <a href="../base/Instruction.html">
 * <tt>Instruction</tt></a> otherwise. The two concrete classes <a
 * href="./DefinedEntry.html"><tt>DefinedEntry</tt></a> and <a
 * href="./BuiltinEntry.html"><tt>BuiltinEntry</tt></a> correspond to each case,
 * respectively.
 */
public abstract class CodeEntry
{
  protected Symbol _symbol;      // symbol for this entry - or null if anonymous
  protected Type _type;          // this entry's type

  private final static ObjectToIntMap _codeIds = new ObjectToIntMap();

  public final static int getId (Instruction[] code)
    {
      int id = _codeIds.get(code);

      if (id == ObjectToIntMap.NOT_FOUND_VALUE)
        _codeIds.put(code,id =_codeIds.size());

      return id;
    }

  public final static void showCode (Instruction[] code)
    {
      showCode(code,-1);
    }

  public final static void showCode (Instruction[] code, int ip)
    {
      System.out.println();
      System.out.println("CODE ID: #"+CodeEntry.getId(code));
      System.out.println();
      for (int i = 0; i < code.length; i++)
        {
          if (i == ip) System.out.print("====>");
          System.out.println("\t[" + i + "]\t" + code[i]);
        }
      System.out.println();
    }

  public final Symbol symbol ()
    {
      return _symbol;
    }

  public final Type type ()
    {
      return _type;
    }

  public final boolean isBuiltIn ()
    {
      return (this instanceof BuiltinEntry);
    }

  public boolean isField ()
    {
      return (this instanceof DefinedEntry && ((DefinedEntry)this).isField());
    }

  public boolean isDefinedField ()
    {
      return (this instanceof DefinedEntry && ((DefinedEntry)this).isDefinedField());
    }

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

      if (!(o instanceof CodeEntry))
        return false;

      return _symbol == ((CodeEntry)o).symbol()
          && _type.isEqualTo(((CodeEntry)o).type(),new HashMap());
    }

  public String toString ()
    {
      Type.resetNames();
      StringBuffer buf = new StringBuffer();

      String name = _symbol != null ? _symbol.toString() : "<no name>";

      buf.append(name+" : "+_type.toQuantifiedString());
      return buf.toString();
    }
}
