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

package ilog.language.design.kernel;

/**
 * @version     Last modified on Fri Oct 18 17:50:47 2002 by hak
 * @version          modified on Wed Jul 24 12:18:16 2002 by pviry
 * @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.*;
import ilog.language.design.base.*;

import java.util.ArrayList;

public class Definition extends ProtoExpression
{
  private Symbol _symbol;
  private Expression _body;

  private DefinedEntry _codeEntry;
  private boolean _isField = false;
  private boolean _isSetOnEvaluation = false;

  public Definition (Tables tables, String symbol, Expression body)
    {
      _symbol = tables.symbol(symbol);
      _body = body;
    }

  public Definition (Tables tables, String symbol, ArrayList args, Expression body)
    {
      this(tables,symbol,new Abstraction(args,body));
    }

  public Definition (Tables tables, String symbol, Expression body, boolean isField)
    {
      this(tables,symbol,body);
      _isField = isField;
    }

  public Definition (Tables tables, String symbol, ArrayList args, Expression body, boolean isField)
    {
      this(tables,symbol,args,body);
      _isField = isField;
    }

  public final int numberOfSubexpressions ()
    {
      return 1;
    }

  public final Expression subexpression (int n) throws NoSuchSubexpressionException
    {
      if (n == 0)
          return _body;

      throw new NoSuchSubexpressionException(this,n);
    }

  public final Symbol symbol ()
    {
      return _symbol;
    }

  public final void setCheckedType ()
    {
      if (isSetCheckedType()) return;
      _body.setCheckedType();
      setCheckedType(type().standardize());
    }

  public final DefinedEntry codeEntry ()
    {
      return _codeEntry;
    }

  public final Definition setOnEvaluation ()
    {
      _isSetOnEvaluation = true;
      return this;
    }

  public final void registerCodeEntry () throws DefinitionException
    {
      _codeEntry = _symbol.registerCodeEntry(_checkedType);
      if (_isSetOnEvaluation)
        _codeEntry.setOnEvaluation();
    }

  public final void typeCheck (TypeChecker typeChecker) throws TypingErrorException
    {
      if (typeCheckLocked()) return;

      _body.typeCheck(typeChecker);
      typeChecker.unify(_type,_body.typeRef(),this);
    }

  public final Expression sanitizeNames (ParameterStack parameters, ClassTypeHandle handle)
    {
      _body = _body.sanitizeNames(parameters, handle);

      return this;
    }

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

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

  /**
   * Compiling a definition amounts to assigning a code array to the defined symbol
   * for its type and compiling its body into this code array. This also make the
   * compiler be aware that it is compiling a definition (as opposed to an
   * expression to evaluate), by setting its "<tt>codeEntry</tt>" field to the
   * defined symbol's <a href="./DefinedEntry.html><tt>DefinedEntry</tt></a>. This
   * allows keeping track of unsafe call dependencies (in cases like mutual
   * recursion) that need to be released later. Thus, a compiled definition's code
   * is deemed <i>unsafe</i> as long as it contains such unsafe code. Clearly,
   * unsafe code must never be allowed to run.  A new definition will release any
   * unsafe code that need it by following dependency pointers established from the
   * <a href="./DefinedEntry.html><tt>DefinedEntry</tt></a> of any unsafe definition
   * where calls to it appear.
   */
  public final void compile (Compiler compiler)
    {
      if (_isField)
        _codeEntry.setFieldInfo();

      compiler.setCodeEntry(_codeEntry);
      _body.compile(compiler);
    }

  public final String toString ()
    {
      return _symbol + " = " + _body;
    }

  // Added by PV
  public final String toTypedString ()
    {
      return typed(_symbol + " =def= " + _body.toTypedString());
    }
}
