package slangc.model; /** * An abstraction over the result of an expression, which might be a typeName known * at compile time but more generally just holds knowledge of the resulting type * of an expression. There may also be some edge cases where the type can't be * determined until later (but may not be an error). * * @author Zak * */ public abstract class ExpressionResult { public static enum Kind { INVALID, /// Failed for some reason VOID, /// This expression is actually invoking a void method (or similar) and has no result NULL, /// This is a null expression, so can be assigned to any normal object but otherwise has no type // Not yet implemented: DUCK, /// This could be anything TYPED_VALUE, /// We have some idea of it's type but not of it's typeName POINTS_TO_TYPE, /// This isn't really an expression as such, just a subexpression pointing to a type START_OF_NAME, /// This isn't really an expression as such, just a subexpression pointing to a package name POINTS_TO_STORAGE_SLOT, /// This points to a storage slot, so it has a typeName type and may also be assignable CONSTANT // We know the exact typeName of the result } public static class StartOfName extends ExpressionResult { String name; public StartOfName(String name) { this.name = name; } @Override public Kind getKind() { return Kind.START_OF_NAME; } public String getNameSoFar() { return name; } } public static class PointsToType extends ExpressionResult { private TypeModel type; public PointsToType(TypeModel type) { this.type = type; if (type == null) { throw new Error("Type cannot be null"); } } @Override public Kind getKind() { return Kind.POINTS_TO_TYPE; } public TypeModel getType() { return type.simplify(); } @Override public String toString() { return super.toString() + "(" + getType() + ")"; } } public static class TypedValue extends ExpressionResult { TypeModel type; public TypedValue(TypeModel type) { this.type = type.simplify(); if (this.type == null) { throw new Error("Type cannot be null"); } } @Override public Kind getKind() { return Kind.TYPED_VALUE; } @Override public boolean resolvesToValueOrNull() { return true; } @Override public TypeModel getValueType() { return type.simplify(); } @Override public String toString() { return super.toString() + "(" + getValueType() + ")"; } } public static class PointsToStorageSlot extends ExpressionResult { private ArrayTypeModel arrayType; private StorageSlot slot; public PointsToStorageSlot(ArrayTypeModel arrayType) { this.arrayType = arrayType; } public PointsToStorageSlot(StorageSlot slot) { this.slot = slot; } @Override public Kind getKind() { return Kind.POINTS_TO_STORAGE_SLOT; } @Override public boolean resolvesToValueOrNull() { return true; } public ArrayTypeModel getArrayType() { return arrayType; } public StorageSlot getSlot() { return slot; } @Override public TypeModel getValueType() { if (arrayType != null) { if (arrayType.getElementType() == null) { throw new Error("Type cannot be null"); } return arrayType.getElementType(); } if (slot.getStorageType() == null) { throw new Error("Type cannot be null"); } return slot.getStorageType(); } @Override public String toString() { return super.toString() + "(" + getValueType() + ")"; } } private static class SimpleExpressionResult extends ExpressionResult { private final Kind kind; SimpleExpressionResult(Kind kind) { this.kind = kind; } public Kind getKind() { return kind; } } public static final ExpressionResult INVALID = new SimpleExpressionResult(Kind.INVALID); public static final ExpressionResult VOID = new SimpleExpressionResult(Kind.VOID); public static final ExpressionResult NULL = new NullExpressionResult(); private static class NullExpressionResult extends ExpressionResult { @Override public Kind getKind() { return Kind.NULL; } @Override public boolean resolvesToValueOrNull() { return true; } @Override public boolean resolvesToNull() { return true; } @Override public TypeModel getValueTypeWithNullType(TypeModel nullType) { return nullType; } }; /* Not yet implemented public static final ExpressionResult DUCK = new SimpleExpressionResult(Kind.DUCK); /*/ //TypeModel typeOrNull; //Named pointedTo; //String constantValue; public ExpressionResult() { // TODO Auto-generated constructor stub } public abstract Kind getKind(); @Override public String toString() { return "" + getKind(); } public boolean resolvesToNull() { return false; } public boolean resolvesToValueOrNull() { return false; } public final boolean resolvesToValue() { return resolvesToValueOrNull() && !resolvesToNull(); } public TypeModel getValueType() { throw new Error("Can't get typeName type from a " + getKind()); } public TypeModel getValueTypeWithNullType(TypeModel nullType) { return getValueType(); } public static ExpressionResult fromMethodResult(MethodModel targetMethod) { if (targetMethod == null) { return ExpressionResult.INVALID; } else if (!targetMethod.hasReturnType()) { return ExpressionResult.VOID; } else { return new ExpressionResult.TypedValue(targetMethod.getReturnType()); } } }