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

package ilog.language.design.kernel;

/**
 * @version     Last modified on Fri Oct 18 17:51:34 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.*;
import ilog.language.design.base.*;

import java.util.ArrayList;

public class Let extends Application
{
  public Let (ArrayList parameters, ArrayList values, Expression body)
    {
      super(new Scope(parameters,body).setNonExitable(),values);
    }

  public Let (ArrayList parameters, ArrayList types, ArrayList values, Expression body)
    {
      super(new Scope(parameters,body).setNonExitable(),values);

      for (int i=parameters.size(); i-->0;)
        ((Scope)function()).parameter(i).setType((Type)types.get(i));
    }

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

      Scope scope = (Scope)function();
      Type[] argumentTypes = new Type[arity()];

      for (int i=arity(); i-->0;)
        {
          typeChecker.unify(scope.parameter(i).typeRef(),_arguments[i].typeRef(),this);
          _arguments[i].typeCheck(typeChecker);
          argumentTypes[i] = _arguments[i].typeRef();
        }

      FunctionType functionType = new FunctionType(argumentTypes,_type).setNoCurrying();

      _function.typeCheck(functionType,typeChecker);
    }

  protected final Instruction _apply (FunctionType type)
    {
      return new Enter(type);
    }    

  public /*final*/ String toString ()
    {
      StringBuffer buf = new StringBuffer("let ");

      Scope scope = (Scope)function();

      for (int i=0; i<arity(); i++)
        buf.append(scope.parameter(i))
           .append(" = ")
           .append(argument(i))
           .append("; ");

      buf.append("in ").append(scope.body());

      return buf.toString();
    }
}
