package org.reldb.rel.v0.types;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.Vector;
import org.reldb.rel.exceptions.ExceptionFatal;
import org.reldb.rel.exceptions.ExceptionSemantic;
import org.reldb.rel.v0.generator.Generator;
import org.reldb.rel.v0.storage.RelDatabase;
import org.reldb.rel.v0.types.userdefined.MultipleInheritance;
import org.reldb.rel.v0.types.userdefined.Possrep;
import org.reldb.rel.v0.values.*;
import org.reldb.rel.v0.vm.Context;
import org.reldb.rel.v0.vm.Operator;
import org.reldb.rel.v0.vm.VirtualMachine;
public class TypeAlpha extends TypeAbstract implements Comparable<TypeAlpha> {
private static TypeAlpha emptyAlpha = new TypeAlpha("ALPHA");
private String typeName;
private boolean isOrdinal;
private boolean isOrdered;
private boolean isUnion;
private TypeAlpha superType = null;
private MultipleInheritance multipleInheritanceDefinition = null;
private Operator specialisationConstraintFn = null;
private HashSet<TypeAlpha> subTypes = new HashSet<TypeAlpha>();
private Vector<Possrep> possreps = new Vector<Possrep>();
private int nextComponentIndex = 0;
public TypeAlpha(String typeName) {
this.typeName = typeName;
}
public static Type getEmptyAlphaType() {
return emptyAlpha;
}
public boolean isBuiltin() {
return false;
}
public String getTypeName() {
return this.typeName;
}
public void setOrdinal(boolean ordinal) {
isOrdinal = ordinal;
}
public boolean isOrdinal() {
return isOrdinal;
}
public void setOrdered(boolean ordered) {
isOrdered = ordered;
}
public boolean isOrdered() {
return isOrdered;
}
public void setUnion(boolean union) {
isUnion = union;
}
public boolean isUnion() {
return isUnion;
}
public Type getRootType() {
if (superType == null)
return this;
else
return superType.getRootType();
}
public void setSupertype(TypeAlpha superType) {
this.superType = superType;
superType.addSubtype(this);
multipleInheritanceDefinition = null;
}
public TypeAlpha getSupertype() {
return superType;
}
public LinkedList<TypeAlpha> getSupertypes() {
LinkedList<TypeAlpha> list = new LinkedList<TypeAlpha>();
TypeAlpha type = superType;
while (type != null) {
list.add(type);
type = type.superType;
}
return list;
}
public TypeAlpha getMostSpecificCommonSupertype(TypeAlpha t) {
if (this == t)
return this;
// TODO - optimise this some day (maybe)
if (superType == t.superType)
return superType;
LinkedList<TypeAlpha> parentsOfThisNode = getSupertypes();
TypeAlpha parent = t.superType;
while (parent != null) {
for (TypeAlpha listItem: parentsOfThisNode)
if (listItem == parent)
return listItem;
parent = parent.superType;
}
throw new ExceptionFatal("RS0383: Unable to find most specific common supertype.");
}
public void addSubtype(TypeAlpha subType) {
subTypes.add(subType);
}
public void removeSubtype(TypeAlpha subType) {
subTypes.remove(subType);
}
public void removeFromSupertype() {
superType.removeSubtype(this);
}
public HashSet<TypeAlpha> getSubtypes() {
return subTypes;
}
public void setMultipleInheritance(MultipleInheritance miDefinition) {
multipleInheritanceDefinition = miDefinition;
superType = null;
possreps.clear();
}
public MultipleInheritance getMultipleInheritanceDefinition() {
return multipleInheritanceDefinition;
}
public boolean isSubtype() {
return superType != null || multipleInheritanceDefinition != null;
}
public int getNextComponentIndex() {
if (isSubtype())
return superType.getNextComponentIndex();
return nextComponentIndex++;
}
/** Locate POSSREP by name. Return null if not found. */
public Possrep locatePossrep(String name) {
for (Possrep p: possreps)
if (p.getName().equals(name))
return p;
return null;
}
public void addPossrep(Possrep possrep) {
if (locatePossrep(possrep.getName()) != null)
throw new ExceptionSemantic("RS0256: A POSSREP named '" + possrep.getName() + "' has already been defined in TYPE " + getSignature() + ".");
for (int i=0; i<possrep.getComponentCount(); i++) {
for (Possrep p: possreps) {
String name = possrep.getComponent(i).getName();
if (p.locateComponent(name) != null)
throw new ExceptionSemantic("RS0257: Component '" + name + "' appears in POSSREP '" + p.getName() + "' and POSSREP '" + possrep.getName() + "'.");
}
}
possreps.add(possrep);
}
public Possrep getPossrep(int i) {
if (i>=possreps.size())
return null;
return possreps.get(i);
}
public int getPossrepCount() {
return possreps.size();
}
public void clear() {
possreps.clear();
}
// Make sure all POSSREPs have INITialisation.
public void checkPossrepInitialisation() {
for (int i=0; i<getPossrepCount(); i++) {
Possrep possrep = getPossrep(i);
if (!possrep.hasInitialiser())
throw new ExceptionSemantic("RS0258: POSSREP '" + possrep.getName() + "' has no INITialisation.");
}
}
private int getLocalComponentCount() {
return nextComponentIndex;
}
public int getComponentCount() {
if (superType != null)
return getLocalComponentCount() + superType.getComponentCount();
else if (multipleInheritanceDefinition != null)
throw new ExceptionFatal("TypeUserdefined: Multiple inheritance is not yet supported.");
else
return getLocalComponentCount();
}
/** Obtain this type's signature. */
public String getSignature() {
return typeName;
}
/** Return true if source can be assigned to variables of this type. */
public boolean canAccept(Type source) {
// TODO - rewrite this canAccept to deal with multiple inheritance.
if (!(source instanceof TypeAlpha))
return false;
if (((TypeAlpha)source).superType == null)
return (source.getSignature().equals(getSignature()));
TypeAlpha subtypeType = (TypeAlpha)source;
while (subtypeType != null) {
if (subtypeType.getSignature().equals(getSignature()))
return true;
subtypeType = subtypeType.superType;
}
return false;
}
/** Obtain a default value of this type. */
public Value getDefaultValue(Generator generator) {
return new ValueAlpha(generator, this);
}
public boolean checkSpecialisationConstraint(Generator generator, ValueAlpha value, RelDatabase database) {
if (specialisationConstraintFn == null)
return true;
// TODO - optimise by not creating new VirtualMachine and Context on each invocation
VirtualMachine vm = new VirtualMachine(generator, database, System.out);
Context context = new Context(generator, vm);
context.push(value);
context.call(specialisationConstraintFn);
return ((ValueBoolean)context.pop()).booleanValue();
}
public void setSpecialisationConstraint(Operator operator) {
specialisationConstraintFn = operator;
}
public boolean hasSpecialisationConstraint() {
return specialisationConstraintFn != null;
}
public int hashCode() {
return typeName.hashCode();
}
public int compareTo(TypeAlpha arg0) {
return typeName.compareTo(arg0.typeName);
}
}