// $Id: ArrayExpr.java,v 1.1.1.1 1999/12/05 22:19:50 mpp Exp $

package IR2;

import java.util.*;

public class ArrayExpr extends LValue {
  protected ArrayVarDescriptor var;
  protected RValue index;


  public ArrayExpr(ArrayVarDescriptor v, RValue i)
    throws SemanticTypeException {
    var = v; index = i;
    if (i != null && i.get_type() != Typed.INT)
      throw new SemanticTypeException("non-integer subscript passed to array");
  }

  /* Typed implementation. */
  public int get_type() { return var.get_type(); }

  /* [RL]Value implementation. */
  public DelocalizedRValue
    generate_rvalue_asm(MethodDescriptor d,
                        Codegen c,
                        CFG output) {
    DelocalizedRValue delocalized_index
      = index.generate_rvalue_asm(d, c, output);

    generate_bounds_check(d, c, output, delocalized_index);

    DelocalizedLValue result = new TempVarDescriptor(d);
    output.addElement(new DelocalizedArrayFetchInstruction
                      (result, var, delocalized_index));
    return result;
  }
  public void generate_lvalue_asm(MethodDescriptor d,
                           Codegen c, CFG output, 
                           DelocalizedRValue s) {
    DelocalizedRValue delocalized_index
      = index.generate_rvalue_asm(d, c, output);

    generate_bounds_check(d, c, output, delocalized_index);

    output.addElement(new DelocalizedArrayStoreInstruction
                         (var, delocalized_index, s));
  }
  private void generate_bounds_check(MethodDescriptor d,
                                     Codegen c,
                                     CFG output,
                                     DelocalizedRValue delocalized_index) {
    // Runtime bounds checking.
    DelocalizedLValue check = new TempVarDescriptor(d);
    output.addElement(new DelocalizedBinaryOpInstruction
                      (DelocalizedBinaryOpInstruction.GE,
                       check, delocalized_index,
                       new DelocalizedImmed(var.get_length())));
    output.addElement(new DelocalizedCondBranchInstruction
                      (check, "array_bounds_runtime_exception"));
    output.addElement(new DelocalizedBinaryOpInstruction
                      (DelocalizedBinaryOpInstruction.LT,
                       check, delocalized_index,
                       new DelocalizedImmed(0)));
    output.addElement(new DelocalizedCondBranchInstruction
                      (check, "array_bounds_runtime_exception"));
  }


  /* Algebraic simplification optimization. */
  public RValue algebraic_simplify() {
    index = index.algebraic_simplify();
    return this;
  }


  /* Walkable implementation. */
  public String node_name() {
    return "array_expr";
  }
  public Enumeration neighbors() {
    return new ShortEnumeration(var, index);
  }
  public String pretty_print(int indent, boolean recursive) {
    String output = new String();
	
    for (int i = 0; i < indent; i++) output += " ";
    if (recursive) {
      indent += 2;
      output += "(" + this.node_name() + "\n";
      /* stuff - calls to prettyprints of internals of this node*/
      for (Enumeration e = this.neighbors(); e.hasMoreElements();) {
        Walkable foo = (Walkable)e.nextElement();
        if (foo == null) 
          output += "-error-";
        else
          output += foo.pretty_print(indent, true);
      }
      for (int i = 0; i < indent; i++) output += " ";
      output += ") /* "+ this.node_name() + " */\n";
    } else {
      output += "(" + this.node_name() + ")\n";
    }
    return output;
  }
}
