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

package ilog.language.design.kernel;

/**
 * @version     Last modified on Fri Oct 18 17:49:54 2002 by hak
 * @version          modified on Wed Jul 24 12:17:47 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.*;

public class ArraySlot extends ProtoExpression 
{
  private Expression _array;
  private Expression _index;

  public ArraySlot (Expression array, Expression index)
    {
      _array = array;
      _index = index;
    }  

  public final int numberOfSubexpressions ()
    {
      return 2;
    }

  public final Expression subexpression (int n) throws NoSuchSubexpressionException
    {
      switch (n)
        {
        case 0:
          return _array;
        case 1:
          return _index;
        }

      throw new NoSuchSubexpressionException(this,n);
    }

  public final Expression array ()
    {
      return _array;
    }

  public final Expression index ()
    {
      return _index;
    }

  public final Expression sanitizeNames (ParameterStack parameters, ClassTypeHandle handle)
    {
      _array = _array.sanitizeNames(parameters, handle);
      _index = _index.sanitizeNames(parameters, handle);
      return this;
    }

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

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

  public final void setCheckedType ()    
    {
      if (isSetCheckedType()) return;
      setCheckedType(type().copy());
      _array.setCheckedType();
      _index.setCheckedType();
    }

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

      TypeParameter indexSetTypeRef = new TypeParameter();
      ArrayType arrayType = new ArrayType(typeRef(),indexSetTypeRef);
      _array.typeCheck(arrayType,typeChecker);

      Global indexSet = Global.dummyIndexSet();
      typeChecker.prune(indexSet,indexSetTypeRef,_array);

      _index.typeCheck(arrayType.indexType(),typeChecker);
    }

  public final void compile (Compiler compiler)
    { // compile the index first, then the array, then the 'get' instruction:

      ArrayType arrayType = (ArrayType)_array.checkedType();
      boolean isMap = arrayType.isMap();
      boolean isIntIndexed = arrayType.indexType().boxSort() == Type.INT_SORT;

      _index.compile(compiler);
      if (isIntIndexed && _index.checkedType().isBoxedType())
        compiler.generateUnwrapper(Type.INT_SORT);

      _array.compile(compiler);

      switch (boxSort())
        {
        case Type.INT_SORT:
          if (isMap)
            if (isIntIndexed)
              compiler.generate(Instruction.GET_INT_INDEXED_MAP_I);
            else
              compiler.generate(Instruction.GET_MAP_I);
          else
            compiler.generate(Instruction.GET_ARRAY_I);
          return;
          
        case Type.REAL_SORT:
          if (isMap)
            if (isIntIndexed)
              compiler.generate(Instruction.GET_INT_INDEXED_MAP_R);
            else
              compiler.generate(Instruction.GET_MAP_R);
          else
            compiler.generate(Instruction.GET_ARRAY_R);
          return;
          
        default:
          if (isMap)
            if (isIntIndexed)
              compiler.generate(Instruction.GET_INT_INDEXED_MAP_O);
            else
              compiler.generate(Instruction.GET_MAP_O);
          else
            compiler.generate(Instruction.GET_ARRAY_O);
          return;
        }           
    }

  public final String toString ()
    {
      return _array + "[" + _index + "]";
    }

  // Added by PV
  public final String toTypedString ()
    {
        return typed(_array.toTypedString() + "[" + _index.toTypedString() + "]");
    }
}
