slcom/slangc/model/ExpressionResult.sauce

227 lines
5.6 KiB
Plaintext

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());
}
}
}