package de.skuzzle.polly.core.parser.ast.declarations.types;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import de.skuzzle.polly.core.parser.ast.Identifier;
/**
* A product type represents the Cartesian product of a set of types.
*
* @author Simon Taddiken
*/
public class ProductType extends Type implements Iterable<Type> {
private static Identifier typeName(Collection<Type> types) {
final StringBuilder b = new StringBuilder();
//b.append("(");
final Iterator<Type> typeIt = types.iterator();
while (typeIt.hasNext()) {
b.append(typeIt.next().getName().getId());
if (typeIt.hasNext()) {
b.append(" ");
}
}
//b.append(")");
return new Identifier(b.toString());
}
private final List<Type> types;
/**
* Creates a new product type with the given types.
*
* @param types List of types in this product.
*/
public ProductType(List<Type> types) {
super(typeName(types), true, false);
this.types = types;
}
/**
* Creates a new product type from the given array.
*
* @param types Array of types in this product.
*/
public ProductType(Type...types) {
this(Arrays.asList(types));
}
@Override
public Type subst(Substitution s) {
final List<Type> types = new ArrayList<Type>(this.types.size());
for (final Type t : this.types) {
types.add(t.subst(s));
}
return new ProductType(types);
}
/**
* Gets the types in this product.
*
* @return The types.
*/
public List<Type> getTypes() {
return this.types;
}
@Override
public String toString() {
return typeName(this.types).toString();
}
@Override
public boolean visit(TypeVisitor visitor) {
return visitor.visit(this);
}
@Override
public Iterator<Type> iterator() {
return this.types.iterator();
}
@Override
public int compareTo(Type o) {
if (!(o instanceof ProductType)) {
throw new IllegalArgumentException("types can not be compared");
}
final ProductType other = (ProductType) o;
assert this.types.size() == other.types.size();
final Iterator<Type> thisIt = this.iterator();
final Iterator<Type> otherIt = other.iterator();
int thisI = 0;
int otherI = 0;
while (thisIt.hasNext()) {
final Type thisNext = thisIt.next();
final Type otherNext = otherIt.next();
final int c = thisNext.compareTo(otherNext);
if (c < 0) {
++otherI;
} else if (c > 0) {
++thisI;
}
}
return thisI - otherI;
}
}