227 lines
5.6 KiB
Plaintext
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());
|
|
}
|
|
}
|
|
}
|