001    package daikon;
002    
003    import utilMDE.*;
004    
005    import java.util.logging.Logger;
006    
007    // Internally, we use the names "array[]", "array[]-element", and
008    // "array[]-indexn".  These may be different depending on the programming
009    // language; for instance, C uses "*array" in place of "array[]-element".
010    
011    
012    /**
013     * Represents the comparability of variables, including methods to
014     * determine if two VarComparabilities are comparable.
015     * VarComparability types have two formats: implicit and none.<p>
016     *
017     * A VarComparabilityImplicit is an arbitrary string, and comparisons
018     * succeed exactly if the two VarComparabilitys are identical.<p>
019     *
020     * VarComparabilityNone means no comparability information was provided.<p>
021     **/
022    public abstract class VarComparability {
023    
024      /** Debug tracer. **/
025      public static final Logger debug =
026        Logger.getLogger("daikon.VarComparability");
027    
028    
029      public static final int NONE = 0;
030      public static final int IMPLICIT = 1;
031    
032      /**
033       * Create a VarComparability representing the given arguments with
034       * respect to a variable.
035       * @param format the type of comparability, either NONE or IMPLICIT
036       * @param rep a regular expression indicating
037       * how to match.  The form is "(a)[b][c]..." where each variable is
038       * string (or number) that is a UID for a basic type.  a is the type
039       * of the element, b is the type of the first index, c the type of
040       * the second, etc.  Index variables only apply if this is an array.
041       * @param vartype the declared type of the variable
042       **/
043      public static VarComparability parse(int format, String rep, ProglangType vartype) {
044        if (format == NONE) {
045          return VarComparabilityNone.parse(rep, vartype);
046        } else if (format == IMPLICIT) {
047          return VarComparabilityImplicit.parse(rep, vartype);
048        } else {
049          throw new IllegalArgumentException("bad format argument " + format
050                          + " should have been in {0, 1, 2}");
051        }
052      }
053    
054      /**
055       * Create a VarComparability based on comparabilities of indices.
056       * @return a new comparability that is an array with the same dimensionality
057       * and indices as given, but with a different element type.
058       *
059       * @param elemTypeName the new type of the elements of return value.
060       * @param old the varcomparability that this is derived from; has
061       * the same indices as this.
062       **/
063      public static VarComparability makeComparabilitySameIndices (String elemTypeName,
064                                                                   VarComparability old) {
065        if (old instanceof VarComparabilityNone) {
066          return VarComparabilityNone.it;
067        } else {
068          throw new Error ("makeComparabilitySameIndices not implemented for implicit comparables");
069        }
070      }
071    
072      public static VarComparability makeAlias(VarInfo vi) {
073        return vi.comparability.makeAlias();
074      }
075      public abstract VarComparability makeAlias();
076    
077      public abstract VarComparability elementType();
078      public abstract VarComparability indexType(int dim);
079    
080      /** Return the comparability for the length of this string**/
081      public abstract VarComparability string_length_type();
082    
083      /**
084       * Returns true if this is comparable to everything else.
085       */
086      public abstract boolean alwaysComparable();
087    
088      /** Returns whether two variables are comparable. **/
089      public static boolean comparable(VarInfo v1, VarInfo v2) {
090        return comparable(v1.comparability, v2.comparability);
091      }
092    
093      /** Returns whether two comparabilities are comparable. **/
094      public static boolean comparable (VarComparability type1,
095                                        VarComparability type2) {
096    
097        if (type1 != null && type2 != null && type1.getClass() != type2.getClass())
098          throw new Error(String.format ("Trying to compare VarComparabilities " +
099                          "of different types: %s (%s) and %s (%s)", type1,
100                          type1.getClass(), type2, type2.getClass()));
101    
102        if (type1 instanceof VarComparabilityNone || type1 == null || type2 == null) {
103          return VarComparabilityNone.comparable ((VarComparabilityNone)type1,
104                                                  (VarComparabilityNone)type2);
105        } else if (type1 instanceof VarComparabilityImplicit) {
106            return VarComparabilityImplicit.comparable
107              ((VarComparabilityImplicit)type1,
108               (VarComparabilityImplicit)type2);
109        } else {
110          throw new Error("Unrecognized subtype of VarComparability: " + type1);
111        }
112      }
113    
114      /**
115       * In general, if two items are comparable, they can be placed in the
116       * same equality set.  This is not always true for some comparabilities
117       * (because they are not always transitive).  They can override this
118       * method to provide the correct results
119       */
120      public boolean equality_set_ok (VarComparability other) {
121        return comparable (this, other);
122      }
123    
124    }