Type.java

package edu.udel.cis.vsl.abc.ast.type.IF;

import java.io.PrintStream;

/**
 * <p>
 * An instance of Type represents a C type. A type is a conceptual entity, not a
 * syntactic element. This class is the root of the type hierarchy for all types
 * used to represent C types.
 * </p>
 * 
 * <p>
 * There may also be additional types that are not part of C, but are part of
 * some extension to C (such as CIVL-C).
 * </p>
 * 
 * <p>
 * Summary of type hierarchy:
 * </p>
 * 
 * {@link Type}
 * <ul>
 * <li>{@link FunctionType}
 * <li>{@link ObjectType}
 * <ul>
 * <li>{@link UnqualifiedObjectType}
 * <ul>
 * <li>{@link ArithmeticType}</li>
 * <li>{@link ArrayType}</li>
 * <li>{@link AtomicType}</li>
 * <li>{@link StandardBasicType}</li>
 * <li>etc.</li>
 * </ul>
 * </li>
 * <li>{@link QualifiedObjectType}
 * <ul>
 * <li>uses one or more of <code>const</code>, <code>volatile</code>,
 * <code>restrict</code>, etc.</li>
 * </ul>
 * </li>
 * </ul>
 * </ul>
 * 
 * <p>
 * Note: {@link AtomicType} and {@link QualifiedObjectType} constructors take an
 * {@link UnqualifiedObjectType}.
 * </p>
 * 
 * 
 * <p>
 * Equivalence relations: there are 3 equivalence relations on the set of types.
 * From strongest to weakest, they are: equality, equivalence, and
 * compatibility. If T1 equals (according to the equals method) T2, then T1 is
 * also equivalent to T2. If T1 is equivalent to T2 then T1 is compatible with
 * T2.
 * <p>
 * 
 * <p>
 * The differences mainly involve tagged entities (structs, unions, enums). In
 * C, it is possible for two structs (for example) to have the same tag, fields,
 * and field types, but still represent two distinct types. This happens if they
 * are declared in two different scopes. Hence it is necessary to specify some
 * other "hidden" component of a struct type to determine when two are equal. We
 * call this the "key": this is any Object, whose "equals" method is used to
 * determine when two tagged types are equal. For any key, there can be at most
 * one struct type using that key. Hence two structs are equal if and only if
 * their keys are equal. Since there can be only one struct object with that
 * key, it follows that they are ==. This invariant is enforced by the type
 * factory.
 * </p>
 * 
 * <p>
 * Two structs which are not equal may still be "equivalent". This means they
 * have equal tags (equal as strings), and, they are either both complete or
 * both incomplete. If they are complete, they must have equivalent fields with
 * the same names and in the same order.
 * </p>
 * 
 * <p>
 * Two structs which are not equal may nevertheless be "compatible". An
 * incomplete struct with tag T is compatible with any struct with tag T. An
 * incomplete array type is compatible with a complete array type which has a
 * compatible element type.
 * </p>
 * 
 * @author siegel
 * 
 */
public interface Type {

	/**
	 * The different kinds of types.
	 */
	public static enum TypeKind {
		/**
		 * An array type; an instance of {@link ArrayType}
		 */
		ARRAY,
		/**
		 * An atomic type; an instance of {@link AtomicType}
		 */
		ATOMIC,
		/**
		 * A "standard basic type"; an instance of {@link StandardBasicType}
		 */
		BASIC,
		/**
		 * The CIVL-C domain type, <code>$domain</code> or
		 * <code>$domain(n)</code>.
		 */
		DOMAIN,
		/**
		 * An enumeration type; an instance of {@link EnumerationType}
		 */
		ENUMERATION,
		/**
		 * A function type; an instance of {@link FunctionType}
		 */
		FUNCTION,
		/**
		 * The CIVL-C heap type, represented by <code>$heap</code>
		 */
		HEAP,
		/**
		 * The CIVL-C $lambda type, represented by <code>$lambda_t</code>
		 */
		LAMBDA,
		/**
		 * The CIVL-C memory type, represented by <code>$memory</code>
		 */
		MEM,
		/**
		 * An integer type which is not a standard basic type. The C Standard
		 * allows a C implementation to provide additional integer types beyond
		 * those specified in the Standard.
		 */
		OTHER_INTEGER,
		/**
		 * A pointer type; an instance of {@link PointerType}
		 */
		POINTER,
		/**
		 * The CIVL-C process type, represented by <code>$proc</code>
		 */
		PROCESS,
		/**
		 * A qualified object type; an instance of {@link QualifiedObjectType}
		 */
		QUALIFIED,
		/**
		 * The CIVL-C range type, denoted <code>$range</code>
		 */
		RANGE,
		/**
		 * The CIVL-C set type. Expressions may have set type but one cannot declare a variable or a function has (or returns) a set type. 
		 */
		SET,
		/**
		 * The CIVL-C scope type, represented by <code>$scope</code>
		 */
		SCOPE,
		/**
		 * The CIVL-C state type, represented by <code>$state</code>
		 */
		STATE,
		/**
		 * A structure or union type; an instance of
		 * {@link StructureOrUnionType}
		 */
		STRUCTURE_OR_UNION,
		/**
		 * The <code>void</code> type, used to represent no type in places where
		 * a type is syntactically required.
		 */
		VOID
	};

	/**
	 * <p>
	 * Is this type "compatible" with the given type? See C11 Sec. 6.2.7 for the
	 * definition of "compatible".
	 * </p>
	 * 
	 * <p>
	 * Special handling for tags that begin with "$anon"--all of these are
	 * treated as identical. These are the names given to anonymous entities by
	 * ABC for convenience.
	 * </p>
	 * 
	 * @param type
	 *            the type to compare with this one for compatibility
	 * @return true iff the two types are compatible
	 */
	boolean compatibleWith(Type type);

	/**
	 * <p>
	 * Is this type "equivalent to" the given type. Two equivalent types should
	 * be interchangeable in any situation. Note that an incomplete struct type
	 * (for example) will never be equivalent to a complete struct type, though
	 * they may be compatible.
	 * </p>
	 * 
	 * <p>
	 * Special handling for tags that begin with "$anon"--all of these are
	 * treated as identical. These are the names given to anonymous entities by
	 * ABC for convenience.
	 * </p>
	 * 
	 * @param type
	 *            any type
	 * @return true iff the two types are equivalent.
	 */
	boolean equivalentTo(Type type);

	/**
	 * The types created by the type factories are given unique id numbers. This
	 * method returns the id number of this type.
	 * 
	 * @return the id number of this type
	 */
	int getId();

	/**
	 * C11 6.2.4(21):
	 * 
	 * "Arithmetic types and pointer types are collectively called scalar types."
	 * 
	 * @return true iff type is scalar
	 */
	boolean isScalar();

	/**
	 * Is this type a "VM" type (variable modified type)? This is defined in the
	 * C11 Standard Sec. 6.7.6:
	 * 
	 * <blockquote> If, in the nested sequence of declarators in a full
	 * declarator, there is a declarator specifying a variable length array
	 * type, the type specified by the full declarator is said to be variably
	 * modified. Furthermore, any type derived by declarator type derivation
	 * from a variably modified type is itself variably modified. </blockquote>
	 * 
	 * The definition of "variable length array type" is given in Sec. 6.7.6.2:
	 * 
	 * <blockquote> If the size is not present, the array type is an incomplete
	 * type. If the size is * instead of being an expression, the array type is
	 * a variable length array type of unspecified size, which can only be used
	 * in declarations or type names with function prototype scope;143) such
	 * arrays are nonetheless complete types. If the size is an integer constant
	 * expression and the element type has a known constant size, the array type
	 * is not a variable length array type; otherwise, the array type is a
	 * variable length array type. (Variable length arrays are a conditional
	 * feature that implementations need not support; see
	 * 6.10.8.3.) </blockquote>
	 * 
	 * @return true iff this type is a VM type
	 */
	boolean isVariablyModified();

	/**
	 * The kind of type this is. See definition of the enumerated type
	 * {@link TypeKind}. These kinds partition the set of all types.
	 * 
	 * @return the kind of this type
	 */
	TypeKind kind();

	/**
	 * Prints the type in a tree-formatted style. The prefix string is prepended
	 * to each line of output other than the first. Output for structure or
	 * union types may leave out the fields by setting abbrv to true.
	 * 
	 * @param prefix
	 *            string to preprend to lines after first
	 * @param out
	 *            PrintStream to which output should be sent
	 * @param abbrv
	 *            if true, abbreviate representations of structure or union
	 *            types by leaving out their fields
	 */
	void print(String prefix, PrintStream out, boolean abbrv);

}