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: Sep 28, 2005
   */
  
  package jintgen.types;
  
  import java.util.*;
  
  /**
   * The <code>TypeCon</code> class represents a type constructor that given a list
   * of type qualifiers (e.g. non-null, positive, etc), and a list of type parameters
   * (e.g. parameters to HashMap), can create a new <code>Type</code> instance.
   *
   * </p>
   * <code>TypeCon</code> instances correspond to flexible types. For example,
   * "array" is a type constructor which accepts an element type, "function"
   * constructs function types from parameter and return types, and each new
   * class in the program creates a new type constructor corresponding to its
   * name.
   *
   * </p>
   * <code>TypeCon</code> instances also contain information about what types
   * of operations are supported by values of types constructed by this type
   * constructor. For example, arrays support the <code>[]</code> indexing operation
   * and the <code>.length</code> member access, while function types support
   * the application operation.
   *
   * @author Ben L. Titzer
   */
  public class TypeCon {
  
      protected static final HashMap<String, List<Object>> EMPTY_DIMS = new HashMap<String, List<Object>>();
      protected final String name;
      protected final HashMap<String, Dimension> dimensions;
      protected final HashMap<HashMap<String, Object>, Type> types;
  
      /**
       * The <code>Dimension</code> class represents a new type dimension that applies
       * to a type constructor. A dimension might be the size of an integer type,
       * the types of parameters to a function, the element type of an array, or a
       * qualifier that has been introduced by the user.
       */
      protected abstract static class Dimension {
  
          protected final String name;
  
          /**
           * The default constructor for the <code>Dimension</code> class simply accepts
           * the name of the dimension as a string that is used to distinguish it from
           * other type dimensions.
           * @param n the name of the type dimension as a string
           */
          protected Dimension(String n) {
              name = n;
          }
  
          public abstract Object build(TypeEnv env, List<Object> params);
      }
  
      public interface BinOp {
          public Type typeCheck(TypeEnv env, Typeable left, Typeable right);
          public String getOperation();
      }
  
      public interface UnOp {
          public abstract Type typeCheck(TypeEnv env, Typeable inner);
          public String getOperation();
      }
  
      /**
       * The protected constructor for the <code>TypeCon</code> class initializes
       * the name field.
       * @param n the name of this type constructor
       */
      public TypeCon(String n) {
          name = n;
          dimensions = new LinkedHashMap<String, Dimension>();
          types = new HashMap<HashMap<String, Object>, Type>();
      }
  
      public Type newType(TypeEnv te) {
          return newType(te, EMPTY_DIMS);
      }
  
      public Type newType(TypeEnv te, HashMap<String, List<Object>> dims) {
          HashMap<String, Object> d = buildDimensions(te, dims);
          Type type = types.get(d);
          if ( type != null ) return type;
          type = new Type(this, d);
          types.put(d, type);
          return type;
      }
  
      public boolean isAssignableFrom(TypeCon other) {
          return other == this;
      }
  
      public boolean isComparableTo(TypeCon other) {
          return other == this;
      }
  
      protected HashMap<String, Object> buildDimensions(TypeEnv env, HashMap<String, List<Object>> dims) {
          HashMap<String, Object> m = new HashMap<String, Object>();
          for ( Map.Entry<String, List<Object>> e : dims.entrySet() ) {
              String name = e.getKey();
              Dimension d = dimensions.get(name);
              Object o = d.build(env, e.getValue());
              m.put(name, o);
          }
          return m;
      }
  
      /**
       * The <code>addDimension()</code> method adds a new dimension to this type constructor.
       * The new dimension has a string name that can be used to retrieve the dimension later.
       * @param d the new type dimension to add to this type constructor
       */
      public void addDimension(Dimension d) {
          dimensions.put(d.name, d);
      }
  
      /**
       * The <code>getDimension()</code> method looks up the specified type dimension for this
       * type constructor given the name of the dimension as a string.
       * @param name the name of the type dimension as a string
       * @return a reference to the <code>Dimension</code> instance if this type constructor
       * supports the dimension; null otherwise
       */
      public Dimension getDimension(String name) {
          return dimensions.get(name);
      }
  
      /**
       * The <code>getName()</code> method returns the name of this type constructor.
       * @return a string representing the name of this type constructor
       */
      public String getName() {
          return name;
      }
  
      public String toString() {
          StringBuffer buf = new StringBuffer();
          buf.append(name);
          buf.append('(');
          boolean first = true;
          for ( Dimension d : dimensions.values() ) {
              if ( !first ) buf.append(", ");
              buf.append(d.name);
              first = false;
          }
          buf.append('(');
          return name;
      }
  
      /**
       * The <code>supportsIndex()</code> method checks whether this type constructor
       * supports indexing with the <code>[]</code> brackets. Not all types support
       * indexing; for example, in Java, only array types support this type
       * of indexing.
       * @return true if types constructed by this <code>TypeCon</code> can legally
       * support indexing with the <code>[]</code> brackets
       */
      public boolean supportsIndex() {
          return false;
      }
  
      /**
       * The <code>supportsRange()</code> method checks whether this type constructor
       * supports sub-range addressing with <code>[h:l]</code>. Not all types support
       * indexing; for example, in Virgil, only integer types support this type
       * of indexing.
       * @return true if types constructed by this <code>TypeCon</code> can legally
       * support range indexing with the <code>[h:l]</code> brackets
       */
      public boolean supportsRange() {
          return false;
      }
  
      /**
       * The <code>supportsMembers()</code> method checks whether this type constructor
       * supports access of members with the <code>.</code> operator. Not all types support
       * member access; for example, in Java, object types support field access and
       * array types support the <code>.length</code> idiom.
       * @return true if types constructed by this <code>TypeCon</code> can legally
       * support member access
       */
      public boolean supportsMembers() {
          return false;
      }
  
      /**
       * The <code>supportsApplication()</code> method checks whether this type constructor
       * supports function application. Few types support application to an expression
       * or list of expressions; in Virgil, only the "function" family of types do.
       * @return true if types constructed by this <code>TypeCon</code> can legally
       * support application
       */
      public boolean supportsApplication() {
          return false;
      }
  }
  