Support extensions on singleton objects
This commit is contained in:
1 parent
671583638b
commit
35628c8453
5 files changed
+56
-9
No files matched your search
@@ -85,8 +85,7 @@ internal suspend fun executeFunctionDecl(
|
||||
}
|
||||
|
||||
if (spec.extTypeName != null) {
|
||||
val type = scope[spec.extTypeName]?.value ?: scope.raiseSymbolNotFound("class ${spec.extTypeName} not found")
|
||||
if (type !is ObjClass) scope.raiseClassCastError("${spec.extTypeName} is not the class instance")
|
||||
val type = scope.resolveExtensionReceiverClass(spec.extTypeName)
|
||||
scope.addExtension(
|
||||
type,
|
||||
spec.name,
|
||||
@@ -167,8 +166,7 @@ internal suspend fun executeFunctionDecl(
|
||||
val compiledFnBody = annotatedFnBody
|
||||
|
||||
spec.extTypeName?.let { typeName ->
|
||||
val type = scope[typeName]?.value ?: scope.raiseSymbolNotFound("class $typeName not found")
|
||||
if (type !is ObjClass) scope.raiseClassCastError("$typeName is not the class instance")
|
||||
val type = scope.resolveExtensionReceiverClass(typeName)
|
||||
if (spec.isStatic) {
|
||||
type.createClassField(
|
||||
spec.name,
|
||||
|
||||
@@ -1004,4 +1004,13 @@ open class Scope(
|
||||
return rec.value as? net.sergeych.lyng.obj.ObjClass
|
||||
?: raiseClassCastError("Expected class $name, got ${rec.value.objClass.className}")
|
||||
}
|
||||
|
||||
internal fun resolveExtensionReceiverClass(name: String): net.sergeych.lyng.obj.ObjClass {
|
||||
val value = get(name)?.value ?: raiseSymbolNotFound("class $name not found")
|
||||
return when (value) {
|
||||
is net.sergeych.lyng.obj.ObjClass -> value
|
||||
is net.sergeych.lyng.obj.ObjInstance -> value.objClass
|
||||
else -> raiseClassCastError("$name is not the class instance")
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3094,11 +3094,7 @@ class CmdDeclExtProperty(internal val constId: Int, internal val slot: Int) : Cm
|
||||
override suspend fun perform(frame: CmdFrame) {
|
||||
val decl = frame.fn.constants[constId] as? BytecodeConst.ExtensionPropertyDecl
|
||||
?: error("DECL_EXT_PROPERTY expects ExtensionPropertyDecl at $constId")
|
||||
val type = frame.ensureScope()[decl.extTypeName]?.value
|
||||
?: frame.ensureScope().raiseSymbolNotFound("class ${decl.extTypeName} not found")
|
||||
if (type !is ObjClass) {
|
||||
frame.ensureScope().raiseClassCastError("${decl.extTypeName} is not the class instance")
|
||||
}
|
||||
val type = frame.ensureScope().resolveExtensionReceiverClass(decl.extTypeName)
|
||||
frame.ensureScope().addExtension(
|
||||
type,
|
||||
decl.property.name,
|
||||
|
||||
@@ -384,6 +384,32 @@ class OOTest {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testObjectSingletonSupportsExtensions() = runTest {
|
||||
val scope = Script.newScope()
|
||||
scope.eval(
|
||||
"""
|
||||
object X {
|
||||
fun base() = "base"
|
||||
}
|
||||
|
||||
fun X.decorate(value): String {
|
||||
this.base() + ":" + value.toString()
|
||||
}
|
||||
val X.tag get() = this.base() + ":tag"
|
||||
|
||||
assertEquals("base", X.base())
|
||||
assertEquals("base:42", X.decorate(42))
|
||||
assertEquals("base:ok", X.decorate("ok"))
|
||||
assertEquals("base:tag", X.tag)
|
||||
|
||||
// Wrapper names should be generated for singleton-object receivers too.
|
||||
assertEquals("base:17", __ext__X__decorate(X, 17))
|
||||
assertEquals("base:tag", __ext_get__X__tag(X))
|
||||
""".trimIndent()
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testExtensionsAreScopeIsolated() = runTest {
|
||||
val scope1 = Script.newScope()
|
||||
|
||||
Reference in new issue
Block a user