// TODO: Store Class AND Type // Describes a value during script optimization/type inference. // In the best case, the exact value is known. // Next best case is we're knowing its precise type (value of object.getClass()). // Third best case is we're knowing it's castable to a certain type. // A completely unknown value is described simply by "new LASValueDescriptor". persistable sclass LASValueDescriptor { bool knownValue() { false; } O value() { null; } Type type() { ret javaClass(); } Class javaClass() { null; } bool javaClassIsExact() { false; } bool canBeNull() { true; } bool canFail() { false; } bool willFail() { false; } srecord Exact(Class c, bool canBeNull) > LASValueDescriptor { Class javaClass() { ret c; } bool javaClassIsExact() { true; } bool canBeNull() { ret canBeNull; } } srecord NonExact(Class c, bool canBeNull) > LASValueDescriptor { Class javaClass() { ret c; } bool javaClassIsExact() { false; } bool canBeNull() { ret canBeNull; } } // only returns a type(), not a javaClass() // (e.g. for LAS classes still being defined) srecord NonExactType(Type type, bool canBeNull) > LASValueDescriptor { Type type() { ret type; } bool javaClassIsExact() { false; } bool canBeNull() { ret canBeNull; } } static LASValueDescriptor nonExactCanBeNull(Type c) { ret new NonExact(typeToClass(c), true); } srecord KnownValue(O value) > LASValueDescriptor { bool knownValue() { true; } O value() { ret value; } Class javaClass() { ret value?.getClass(); } bool javaClassIsExact() { ret value != null; } bool canBeNull() { ret value == null; } } // Indicates an exception can be thrown instead of returning a value. // Probably we don't need this. sclass WillFail > LASValueDescriptor { bool canFail() { true; } bool willFail() { true; } } static LASValueDescriptor fromClass(Class c) { ret new NonExact(c, true); } static LASValueDescriptor fromType(Type type) { ret new NonExact(typeToClass(type), true); } toString { ret "LASValueDescriptor " + javaClass(); } }