code: /**
   * Copyright (c) 2005, Regents of the University of California
   * All rights reserved.
   *
   * Redistribution and use in source and binary forms, with or without
   * modification, are permitted provided that the following conditions
   * are met:
   *
   * Redistributions of source code must retain the above copyright notice,
   * this list of conditions and the following disclaimer.
   *
   * Redistributions in binary form must reproduce the above copyright
   * notice, this list of conditions and the following disclaimer in the
   * documentation and/or other materials provided with the distribution.
   *
   * Neither the name of the University of California, Los Angeles nor the
   * names of its contributors may be used to endorse or promote products
   * derived from this software without specific prior written permission.
   *
   * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
   * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
   * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
   * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
   * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
   * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
   * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
   * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
   * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
   * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   *
   * Creation date: Oct 3, 2005
   */
  
  package jintgen.jigir;
  
  import jintgen.isdl.EnumDecl;
  import jintgen.isdl.OperandTypeDecl;
  import jintgen.isdl.parser.Token;
  import jintgen.isdl.verifier.JIGIRErrorReporter;
  import jintgen.types.*;
  import java.util.*;
  
  /**
   * The <code>JIGIRTypeEnv</code> class represents a type environment for
   * JIGIR code. It supports void, boolean, integers, maps, and function
   * types.
   *
   * @author Ben L. Titzer
   */
  public class JIGIRTypeEnv extends TypeEnv {
      public final Type VOID;
      public final Type BOOLEAN;
      public final TypeCon INT;
      public final TypeCon MAP;
      public final TypeCon FUNCTION;
      public final TypeCon ADDRESS;
      public final Relation ASSIGNABLE;
      public final Relation COMPARABLE;
      public final Relation PROMOTABLE;
      public final Relation CONVERTIBLE;
      public Arith.SHL SHL;
      public Arith.SHR SHR;
      public Arith.AND AND;
  
      /**
       * The <code>TYPECON_int</code> class represents the type constructor for types
       * based on "int". In JIGIR, such types have both a sign and a size.
       */
      protected class TYPECON_int extends TypeCon {
          final SignDimension sign;
          final SizeDimension size;
  
          TYPECON_int() {
              super("int");
              sign = new SignDimension();
              size = new SizeDimension();
              addDimension(sign);
              addDimension(size);
          }
  
          public Type newType(TypeEnv te, HashMap<String, List<Object>> dims) {
              HashMap<String, Object> dimInst = buildDimensions(te, dims);
              Type type = types.get(dimInst);
              if ( type != null ) return type;
              else return buildIntType(dimInst);
          }
  
          private Type buildIntType(HashMap<String, Object> dimInst) {
              Boolean sign = (Boolean) dimInst.get("sign");
              if ( sign == null ) sign = true; // signed by default
              Integer len = (Integer) dimInst.get("size");
              if ( len == null ) len = 32; // default size is 32 bits
              TYPE_int type_int = new TYPE_int(sign, len, dimInst);
              types.put(dimInst, type_int);
              return type_int;
          }
  
      }
  
      /**
       * The <code>TYPECON_int</code> class represents the type constructor for types
       * based on "int". In JIGIR, such types have both a sign and a size.
       */
      protected class TYPECON_addr extends TypeCon {
          final SignDimension relative;
          final SizeDimension align;
  
          TYPECON_addr() {
              super("address");
              relative = new SignDimension();
              align = new SizeDimension();
              addDimension(relative);
              addDimension(align);
          }
  
          public Type newType(TypeEnv te, HashMap<String, List<Object>> dims) {
              HashMap<String, Object> dimInst = buildDimensions(te, dims);
              Type type = types.get(dimInst);
              if ( type != null ) return type;
              else return buildAddrType(dimInst);
          }
  
          private Type buildAddrType(HashMap<String, Object> dimInst) {
              Boolean rel = (Boolean) dimInst.get("sign");
              if ( rel == null ) rel = false; // absolute by  default
              Integer align = (Integer) dimInst.get("size");
              if ( align == null ) align = 1; // default alignment is 1 unit
              TYPE_addr type_addr = new TYPE_addr(rel, align, dimInst);
              types.put(dimInst, type_addr);
              return type_addr;
          }
  
      }
  
  
      /**
       * The <code>TYPE_int</code> class represents integer types that
       * include a sign and a size.
       */
      public class TYPE_int extends Type {
          protected final boolean signed;
          protected final int size;
  
          protected TYPE_int(boolean sign, int len, HashMap<String, Object> dims) {
              super(INT, dims);
              signed = sign;
              size = len;
          }
  
          protected TYPE_int(boolean sign, int len) {
              super(INT, new HashMap<String, Object>());
              signed = sign;
              size = len;
          }
  
          public boolean isSigned() {
              return signed;
          }
  
          public int getSize() {
              return size;
          }
  
          public String toString() {
              return (signed ? "-int." : "+int.") + size;
          }
      }
  
      /**
       * The <code>TYPE_addr</code> class represents integer types that
       * include a sign and a size.
       */
      public class TYPE_addr extends Type {
          protected final boolean relative;
          protected final int align;
  
          protected TYPE_addr(boolean sign, int len, HashMap<String, Object> dims) {
              super(ADDRESS, dims);
              relative = sign;
              align = len;
          }
  
          protected TYPE_addr(boolean sign, int len) {
              super(ADDRESS, new HashMap<String, Object>());
              relative = sign;
              align = len;
          }
  
          public boolean isRelative() {
              return relative;
          }
  
          public int getAlign() {
              return align;
          }
  
          public String toString() {
              return (relative ? "-address." : "address.") + align;
          }
      }
  
  
      public class TYPE_enum extends TypeCon {
          public final EnumDecl decl;
          protected TYPE_enum(EnumDecl decl) {
              super(decl.name.image);
              this.decl = decl;
          }
      }
  
      public class TYPE_enum_kind extends TypeCon {
          public final EnumDecl decl;
          protected TYPE_enum_kind(EnumDecl decl) {
              super(decl.name.image+"$kind");
              this.decl = decl;
          }
      }
  
      public class TYPE_operand extends TypeCon {
          public final OperandTypeDecl decl;
          protected TYPE_operand(OperandTypeDecl decl) {
              super(decl.name.image);
              this.decl = decl;
          }
      }
  
      public JIGIRTypeEnv(JIGIRErrorReporter er) {
          super(er);
  
          ASSIGNABLE = new TransitiveRelation("assignable");
          COMPARABLE = new TransitiveRelation("comparable");
          PROMOTABLE = new Relation("promotable");
          CONVERTIBLE = new Relation("convertible");
  
          // initialize the boolean type constructor
          TypeCon VTC = new TypeCon("void");
          VOID = VTC.newType(this);
          // initialize the boolean type constructor
          TypeCon BOOL = new TypeCon("boolean");
          BOOLEAN = BOOL.newType(this);
  
          // initialize the integer type constructor
          INT = new TYPECON_int();
  
          // initialize the address type constructor
          ADDRESS = new TYPECON_addr();
  
          // initialize the map type constructor
          MAP = new TypeCon("map");
          MAP.addDimension(new ParamDimension("types", variance(ParamDimension.INVARIANT, ParamDimension.INVARIANT)));
  
          // initialize the function type constructor
          FUNCTION = new TypeCon("function");
          FUNCTION.addDimension(new ParamDimension("param", ParamDimension.CONTRAVARIANT));
          FUNCTION.addDimension(new ParamDimension("return", variance(ParamDimension.COVARIANT)));
  
          // add the global type constructors
          addTypeCon(VTC);
          addTypeCon(BOOL, COMPARABLE, ASSIGNABLE, PROMOTABLE, CONVERTIBLE);
          addTypeCon(INT, COMPARABLE, ASSIGNABLE, PROMOTABLE, CONVERTIBLE);
          addTypeCon(ADDRESS, COMPARABLE, ASSIGNABLE, PROMOTABLE);
          addTypeCon(MAP, ASSIGNABLE);
          addTypeCon(FUNCTION);
  
          // add the relations
          addRelation(ASSIGNABLE);
          addRelation(COMPARABLE);
          addRelation(PROMOTABLE);
  
          // add binops for booleans
          addBinOp(BOOL, BOOL, new Logical.AND());
          addBinOp(BOOL, BOOL, new Logical.OR());
          addBinOp(BOOL, BOOL, new Logical.XOR());
          addBinOp(BOOL, BOOL, new Logical.EQU());
          addBinOp(BOOL, BOOL, new Logical.NEQU());
  
          // add comparisons for booleans
          addBinOp(BOOL, BOOL, new Logical.EQU());
          addBinOp(BOOL, BOOL, new Logical.NEQU());
  
          // add comparisons for integers
          addBinOp(INT, INT, new Logical.EQU());
          addBinOp(INT, INT, new Logical.NEQU());
          addBinOp(INT, INT, new Logical.GR());
          addBinOp(INT, INT, new Logical.GREQ());
          addBinOp(INT, INT, new Logical.LESS());
          addBinOp(INT, INT, new Logical.LESSEQU());
  
          // add binops for integers
          addBinOp(INT, INT, new Arith.ADD());
          addBinOp(INT, INT, new Arith.SUB());
          addBinOp(INT, INT, new Arith.DIV());
          addBinOp(INT, INT, new Arith.MOD());
          addBinOp(INT, INT, new Arith.MUL());
          AND = new Arith.AND();
          addBinOp(INT, INT, AND);
          addBinOp(INT, INT, new Arith.OR());
          addBinOp(INT, INT, new Arith.XOR());
          SHL = new Arith.SHL();
          addBinOp(INT, INT, SHL);
          SHR = new Arith.SHR();
          addBinOp(INT, INT, SHR);
  
          // add logical not operator
          addUnOp(BOOL, new Logical.NOT());
  
          // add unary integer operators
          addUnOp(INT, new Arith.NEG());
          addUnOp(INT, new Arith.COMP());
          addUnOp(INT, new Arith.UNSIGN());
  
          // add convertibility relations
          CONVERTIBLE.add(BOOL, INT);
          CONVERTIBLE.add(ADDRESS, INT);
          CONVERTIBLE.add(INT, ADDRESS);
      }
  
      List<Integer> variance(int... i) {
          List<Integer> l = new LinkedList<Integer>();
          for ( int j : i) l.add(j);
          return l;
      }
  
      public TypeRef newIntTypeRef(Token sign, Token n, Token size) {
          List<Object> sign_list = new LinkedList<Object>();
          sign_list.add(sign);
          List<Object> size_list = new LinkedList<Object>();
          size_list.add(size);
          TypeRef ref = new TypeRef(n);
          ref.addDimension("sign", sign_list);
          ref.addDimension("size", size_list);
          return ref;
      }
  
      public TYPE_int newIntType(boolean sign, int size) {
          List<Object> sign_list = new LinkedList<Object>();
          sign_list.add(sign);
          List<Object> size_list = new LinkedList<Object>();
          size_list.add(size);
          HashMap<String, List<Object>> map = new HashMap<String, List<Object>>();
          map.put("size", size_list);
          map.put("sign", sign_list);
          return (TYPE_int)INT.newType(this, map);
      }
  
      public Type resolveOperandType(OperandTypeDecl ot) {
          TypeCon tc = resolveTypeCon(ot.name.image);
          return tc.newType(this);
      }
  
      public Type resolveType(Token tok) {
          TypeCon tc = resolveTypeCon(tok.image);
          if ( tc == null ) ERROR.UnresolvedType(tok);
          return tc.newType(this);
      }
  
      public void addOperandType(OperandTypeDecl ot) {
          TypeCon tycon = new TYPE_operand(ot);
          addTypeCon(tycon, ASSIGNABLE, COMPARABLE);
  	if (ot.isValue()) {
  	    // Value types may be converted to their underlying type.
  	    TypeCon baseCon = 
  		((OperandTypeDecl.Value) ot).typeRef.resolveTypeCon(this);
  	    CONVERTIBLE.add(tycon, baseCon);
  	}
  
      }
  
      public Type addEnum(EnumDecl ot) {
          addTypeCon(new TYPE_enum(ot), ASSIGNABLE, COMPARABLE);
          TYPE_enum_kind tc = new TYPE_enum_kind(ot);
          addTypeCon(tc);
          return tc.newType(this);
      }
  }
  