slcom/slangc/model/TypeModel.sauce

380 lines
9.6 KiB
Plaintext
Raw Permalink Normal View History

package slangc.model;
import slang.data.ComparisonOp;
import slang.data.List;
import slang.data.Mappable;
import slangc.api.Reporter;
import slangc.bytecode.TypeSignature;
import slangc.model.clauses.Arguments;
import slangc.model.statements.CaseLabelStatement;
import slangc.parser.Branch;
public abstract class TypeModel extends InnerTypeScope implements Named, AttributeOwner, Mappable {
PackageModel pkg;
String name;
TypeLevel level;
private int nextUntitledNumber = 0;
private ArrayTypeModel arrayOfThis = null;
AttributeSet attributes = null;
public TypeModel(PackageModel packageModel, String name, TypeLevel level, InnerTypeScope owner) {
super(owner);
this.pkg = packageModel;
this.name = name;
this.level = level;
this.owner = owner;
if (level != TypeLevel.OUTER) {
if (owner.innerTypes.hasKey(name)) {
throw new Error("Internal error/TODO: Type '" + fullName() + "' includes inner type '" + name + "' twice");
}
if (level == TypeLevel.INNER_INNER) {
// The public name is given using a # but for the purpose of scoped lookup we keep it simple
owner.innerTypes.set(name.sub(0, name.searchFirst("#")), this);
} else {
owner.innerTypes.set(name, this);
}
}
}
public String fullName() {
return (pkg.getName() == "" ? "" : (pkg.getName() + ".")) + getOuterName();
}
public String baseName() {
return (pkg.getName() == "" ? "" : (pkg.getName() + ".")) + getOuterBaseName();
}
@Override
public PackageModel getPackage() {
return pkg;
}
public TypeLevel getTypeLevel() {
return level;
}
/** Gets the outer-level equivalent of this name. E.g. For the class foo.Bar it would be bar, but for foo.Bar.Baz it might be "Bar:Baz". */
@Override
public String getOuterName() {
if (level == TypeLevel.OUTER) {
return name;
} else {
return owner.getOuterName() + ":" + name;
}
}
public String getStartOfName() {
if (level == TypeLevel.OUTER) {
return "";
} else {
return owner.getOuterName() + ":";
}
}
public String getOuterBaseName() {
if (level == TypeLevel.OUTER) {
return getInnerBaseName();
} else {
return owner.getOuterName() + ":" + getInnerBaseName();
}
}
public String getInnerName() {
return name;
}
/** Returns the name minus any template arguments or placeholders. */
public String getInnerBaseName() {
if (name.search("<")) {
return name.sub(0, name.searchLast("<"));
} else {
return name;
}
}
public int nextUntitledNumber() {
int result = nextUntitledNumber;
nextUntitledNumber++;
return result;
}
public abstract boolean isSynthetic();
public abstract TypeType getTypeType();
public abstract int expand();
public void dump(Reporter reporter, String indent, String incr) {
reporter.note("DUMP", indent + "> Type '" + getOuterName() + "' (" + getTypeType() + ", " + getTypeLevel() + ")" + (existsAtRuntime() ? "" : " [doesn't exist at runtime]"));
}
@Override
public TypeModel resolveTypeName(String name) {
TypeModel simpleLookup = super.resolveTypeName(name);
if (simpleLookup != null) {
return simpleLookup;
}
if (innerTypes.hasKey(name)) {
return innerTypes.get(name);
} else {
TypeModel[] models = innerTypes.values().arrayCopy();
for (int mi = 0; mi < models.length; mi++) {
TypeModel m = models[mi];
if (m.matchesName(name)) {
return m;
}
}
if (owner != null) {
return owner.resolveTypeName(name);
} else if (getPackage().hasType(name)) {
return getPackage().getType(name);
} else {
// TODO: Handle super-types here?
return null;
}
}
}
public abstract int resolveTypes();
public TypeModel getOrCreateTemplateInstance(TemplateArguments targs) {
return null; // This error is handled by the (main) caller
//throw new Error("Internal error/TODO: This isn't a template type or instantiation hasn't been implemented here");
}
public boolean hasInnerType(String innerName, boolean includeBase) {
return innerTypes.hasKey(innerName);
}
public boolean hasInnerType(String innerName) {
return hasInnerType(innerName, true);
}
public TypeModel getInnerType(String innerName, boolean includeBase) {
return innerTypes.get(innerName);
}
public TypeModel getInnerType(String innerName) {
return getInnerType(innerName, true);
}
public String[] getInnerTypeNames() {
List<String> result = new List<String>();
result.appendList(innerTypes.keys());
result.sort(String.getDefaultComparisonOp());
return result.arrayCopy();
}
public boolean existsAtRuntime() {
if (getTypeLevel() == TypeLevel.OUTER) {
return true;
} else {
return getOwner().getNearestType().existsAtRuntime();
}
}
public boolean isReferenceOnly() {
return false;
}
@Override
public String toString() {
return fullName();
}
/**
* For an alias type (or similar), the simplify method should return the actual target type.
* This means that if an alias points to another alias (which eventually points to a concrete type)
* this method must traverse every alias.
*
* @return
*/
public TypeModel simplify() {
return this;
}
public TypeModel getOrCreateArrayInstance() {
if (simplify() != this && simplify() != null) {
return simplify().getOrCreateArrayInstance();
}
if (arrayOfThis == null) {
arrayOfThis = new ArrayTypeModel(this);
getPackage().addSyntheticType(arrayOfThis);
}
return arrayOfThis;
}
//@Override
public String getName() {
return getInnerName();
}
public boolean isAssignableFrom(TypeModel otherType) {
if (otherType == null) {
return false;
} else if (this.simplify() == otherType.simplify()) {
return true;
} else {
return otherType.inherits(this);
}
}
/**
* Should return true if and only if this type inherits from the other type.
*
* <p/>Note, for the purposes of being specific, "this" type shouldn't be considered
* to inherit itself. This test should only match if a base class or interface is the
* other type or inherits it indirectly.
*
* <p/>If this is a class definition and "otherType" is the root class then this should
* always return true (provided the type model is actually set up correctly!). If this
* is an interface and "otherType" is a class then this should always return false (in
* particular, an interface type is not considered to inherit from the root class).
* TODO: Check interface behaviour is correct.
*/
public boolean inherits(TypeModel otherType) {
return false;
}
public abstract int resolveExpressions();
public boolean hasField(String name, boolean includeBase) {
return false;
}
public FieldModel getField(String name, boolean includeBase) {
return null;
}
public final boolean hasField(String name) {
return hasField(name, true);
}
public final FieldModel getField(String name) {
return getField(name, true);
}
public boolean hasMethods(String name, boolean includeBase) {
return countMethods(name, includeBase) > 0;
}
public int countMethods(String name, boolean includeBase) {
return getMethods(name, includeBase).length;
}
public MethodModel[] getMethods(String name, boolean includeBase) {
return new MethodModel[0];
}
public Named lookupSimpleName(String name) {
return lookupSimpleName(name, true);
}
public Named lookupSimpleName(String name, boolean includeOuterScopes) {
throw new Error("TODO");
}
public MethodModel[] lookupSimpleMethod(String name) {
return lookupSimpleMethod(name, true);
}
public MethodModel[] lookupSimpleMethod(String name, boolean includeOuterScopes) {
throw new Error("TODO");
}
public MethodModel[] getInstanceConstructors() {
return new MethodModel[0];
}
public MethodModel getDefaultInstanceConstructor() {
MethodModel[] constrs = getInstanceConstructors();
for (int i = 0; i < constrs.length; i++) {
if (constrs[i].countParameters() == 0) {
return constrs[i];
}
}
return null;
}
public abstract boolean isObjectType();
public int countInterfaces() {
return 0;
}
public TypeModel getInterface(int n) {
throw new Error("This type has no interfaces");
}
public int countFieldMembers() {
return 0;
}
public FieldModel getFieldMember(int i) {
throw new Error("This type has no fields");
}
public int countMethodMembers() {
return 0;
}
public MethodModel getMethodMember(int i) {
throw new Error("This type has no methods");
}
public TypeSignature getTypeSignature() {
return new TypeSignature(getPackage().getName(), getOuterName());
}
public AttributeSet getAttributes() {
if (attributes == null) {
attributes = new AttributeSet(this, null);
}
return attributes;
}
public int getFlags() {
int f = getAttributes().getFlags();
switch (getTypeType()) {
case TypeType.CLASS:
case TypeType.CLASS_TEMPLATE:
f |= Flags.MASK_CLASS;
break;
case TypeType.INTERFACE:
case TypeType.INTERFACE_TEMPLATE:
f |= Flags.MASK_INTERFACE;
break;
case TypeType.ENUM:
f |= Flags.MASK_ENUM;
break;
}
if (isSynthetic()) {
f |= Flags.MASK_SYNTHETIC;
}
return f;
}
protected void setAttributes(AttributeSet attributes) {
this.attributes = attributes;
}
public boolean matchesName(String n) {
return this.name.equals(n);
}
public boolean mappableEquals(Mappable o) {
throw new Error("TODO");
}
public int mappableHash() {
throw new Error("TODO");
}
}