package typing;
import java.util.Collections;
import java.util.Set;
import java.util.TreeSet;
import expressions.ArithmeticOperator;
import expressions.BooleanConstant;
import expressions.Expression;
import expressions.IntegerConstant;
import expressions.Projection;
import expressions.RelationalOperator;
import expressions.UnitConstant;
/**
* Basic class for all types in the type system.
*
* @author Benedikt Meurer
* @version $Id$
*/
public abstract class Type {
/**
* Returns <code>true</code> if the type contains a type
* variable, whose name is <code>name</code>. Otherwise
* <code>false</code> is returned.
*
* This method is primarily used to implement the unification
* algorithm.
*
* @param name the name of the type variable to check for.
*
* @return <code>true</code> if this type contains a type
* variable named <code>name</code>, else <code>false</code>.
*/
public abstract boolean containsFreeTypeVariable(String name);
/**
* Returns the set of free type variables within this type.
*
* The default implementation for {@link Type} returns the
* empty set, so you will need to override this method in
* all types related to type variables.
*
* @return the set of free type variables within this type.
*/
public abstract Set<String> free();
/**
* Applies the {@link Substitution} <code>s</code> to the
* type and returns the resulting type.
*
* @param s the {@link Substitution} to apply to this type.
*
* @return the resulting {@link Type}.
*/
abstract Type substitute(Substitution s);
/**
* Returns the {@link Type} for the given <code>expression</code>
* if possible, i.e. <b>(BOOL)</b> if <code>expression</code> is
* an instance of {@link BooleanConstant}.
*
* @param expression an expression.
*
* @return the {@link Type} for the <code>expression</code>.
*
* @throws IllegalArgumentException if <code>expression</code> is not a
* simple expression, like a constant,
* for which it is possible to determine
* a type out-of-the-box.
*/
static Type getTypeForExpression(Expression expression) {
if (expression instanceof BooleanConstant)
return PrimitiveType.BOOL;
else if (expression instanceof IntegerConstant)
return PrimitiveType.INT;
else if (expression instanceof UnitConstant)
return PrimitiveType.UNIT;
else if (expression instanceof ArithmeticOperator)
return ArrowType.INT_INT_INT;
else if (expression instanceof RelationalOperator)
return ArrowType.INT_INT_BOOL;
else if (expression instanceof Projection) {
Projection projection = (Projection)expression;
TreeSet<String> quantifiedVariables = new TreeSet<String>();
TypeVariable[] types = new TypeVariable[projection.getArity()];
for (int n = 0; n < types.length; ++n) {
types[n] = new TypeVariable("\u03B1" + n);
quantifiedVariables.add(types[n].getName());
}
TupleType tt = new TupleType(types);
ArrowType at = new ArrowType(tt, types[projection.getIndex() - 1]);
return new PolyType(quantifiedVariables, at);
}
// no primitive type
throw new IllegalArgumentException("Cannot determine the type for " + expression);
}
/**
* Shared empty set as an optimization for the {@link #free()}
* method, so we don't need to allocate too many empty sets.
*/
protected static final Set<String> EMPTY_SET = Collections.unmodifiableSet(Collections.<String>emptySet());
}