From 71a37a29061397470037198bf30f5ad0cd008d19 Mon Sep 17 00:00:00 2001 From: sergeych Date: Sat, 13 Dec 2025 23:14:12 +0100 Subject: [PATCH] Revert "Improve `decodeClassObj` class resolution in `LynonDecoder`, add fallback lookup mechanisms, and refine related tests" This reverts commit dd1a1544c6d49641783d221b15e23c7150010161. --- ...yng_site [jsBrowserDevelopmentRun].run.xml | 20 ------ .../kotlin/net/sergeych/lynon/LynonDecoder.kt | 71 ++---------------- lynglib/src/jvmTest/kotlin/LynonTests.kt | 72 ++----------------- 3 files changed, 11 insertions(+), 152 deletions(-) diff --git a/.run/lyng_site [jsBrowserDevelopmentRun].run.xml b/.run/lyng_site [jsBrowserDevelopmentRun].run.xml index 5518148..548e319 100644 --- a/.run/lyng_site [jsBrowserDevelopmentRun].run.xml +++ b/.run/lyng_site [jsBrowserDevelopmentRun].run.xml @@ -1,20 +1,3 @@ - - @@ -34,11 +17,8 @@ true true - false false false - true - true \ No newline at end of file diff --git a/lynglib/src/commonMain/kotlin/net/sergeych/lynon/LynonDecoder.kt b/lynglib/src/commonMain/kotlin/net/sergeych/lynon/LynonDecoder.kt index 40d3268..6e230d1 100644 --- a/lynglib/src/commonMain/kotlin/net/sergeych/lynon/LynonDecoder.kt +++ b/lynglib/src/commonMain/kotlin/net/sergeych/lynon/LynonDecoder.kt @@ -78,72 +78,15 @@ open class LynonDecoder(val bin: BitInput, val settings: LynonSettings = LynonSe private suspend fun decodeClassObj(scope: Scope): ObjClass { val className = decodeObject(scope, ObjString.type, null) as ObjString - val name = className.value - // 1) Try direct lookup in this scope (locals/parents/this members) - scope.get(name)?.value?.let { + return scope.get(className.value)?.value?.let { if (it !is ObjClass) scope.raiseClassCastError("Expected obj class but got ${it::class.simpleName}") - return it - } - // 2) Try ancestry lookup including instance/class members, but without invoking overridden get - scope.chainLookupWithMembers(name)?.value?.let { - if (it !is ObjClass) - scope.raiseClassCastError("Expected obj class but got ${it::class.simpleName}") - return it - } - // 3) Try to find nearest ModuleScope and check its locals and its parent (root) locals - run { - var s: Scope? = scope - val visited = HashSet(4) - while (s != null) { - if (!visited.add(s.frameId)) break - if (s is net.sergeych.lyng.ModuleScope) { - s.objects[name]?.value?.let { - if (it !is ObjClass) - scope.raiseClassCastError("Expected obj class but got ${it::class.simpleName}") - return it - } - s.localBindings[name]?.value?.let { - if (it !is ObjClass) - scope.raiseClassCastError("Expected obj class but got ${it::class.simpleName}") - return it - } - s.parent?.let { p -> - p.objects[name]?.value?.let { - if (it !is ObjClass) - scope.raiseClassCastError("Expected obj class but got ${it::class.simpleName}") - return it - } - p.localBindings[name]?.value?.let { - if (it !is ObjClass) - scope.raiseClassCastError("Expected obj class but got ${it::class.simpleName}") - return it - } - p.thisObj.objClass.getInstanceMemberOrNull(name)?.value?.let { - if (it !is ObjClass) - scope.raiseClassCastError("Expected obj class but got ${it::class.simpleName}") - return it - } - } - break - } - s = s.parent - } - } - // 4) Try ImportProvider root scope globals (e.g., stdlib) - runCatching { scope.currentImportProvider.rootScope.objects[name]?.value }.getOrNull()?.let { - if (it !is ObjClass) - scope.raiseClassCastError("Expected obj class but got ${it::class.simpleName}") - return it - } -// // 5) As a final fallback, try to evaluate the name in this scope using the compiler -// runCatching { scope.eval(name) }.getOrNull()?.let { -// if (it !is ObjClass) -// scope.raiseClassCastError("Expected obj class but got ${it::class.simpleName}") -// return it -// } - // If everything failed, raise an informative error - scope.raiseSymbolNotFound("can't deserialize: not found type ${className}") + it + } ?: scope.also { + println("Class not found: $className") + println("::: ${runCatching { scope.eval("Vault")}.getOrNull() }") + println("::2 [${className}]: ${scope.get(className.value)}") + }.raiseSymbolNotFound("can't deserialize: not found type $className") } suspend fun decodeAnyList(scope: Scope, fixedSize: Int? = null): MutableList { diff --git a/lynglib/src/jvmTest/kotlin/LynonTests.kt b/lynglib/src/jvmTest/kotlin/LynonTests.kt index cf8eb0e..f597c5d 100644 --- a/lynglib/src/jvmTest/kotlin/LynonTests.kt +++ b/lynglib/src/jvmTest/kotlin/LynonTests.kt @@ -25,7 +25,10 @@ import net.sergeych.lyng.obj.* import net.sergeych.lynon.* import java.nio.file.Files import java.nio.file.Path -import kotlin.test.* +import kotlin.test.Test +import kotlin.test.assertContentEquals +import kotlin.test.assertEquals +import kotlin.test.assertTrue class LynonTests { @@ -41,73 +44,6 @@ class LynonTests { assertEquals(3, sizeInTetrades(257u)) } - @Ignore("This is not yet implemented") - @Test - fun decodeClassObj_shouldResolveDottedQualifiedNames() = runTest { - // Define nested namespaces and a class with a qualified name via eval - val module = net.sergeych.lyng.Script.defaultImportManager.newModule() - module.eval( - """ - package ns.sub - class Vault() { fun toString() { "ns.sub.Vault" } } - """.trimIndent() - ) - - val child = module.createChildScope(module.pos) - - // Sanity: eval resolves both qualified and unqualified in the same module context - val qualified = child.eval("ns.sub.Vault") - assertTrue(qualified is ObjClass) - - val inst = child.eval("ns.sub.Vault()") - assertTrue(inst is ObjInstance) - - // Encode and decode instance; decoder should resolve class by its encoded name - val bout = MemoryBitOutput() - val enc = LynonEncoder(bout) - enc.encodeAny(child, inst) - val bin = MemoryBitInput(bout.toBitArray()) - val dec = LynonDecoder(bin) - - val decoded = dec.decodeAny(child) - assertTrue(decoded is ObjInstance) - val decObj = decoded as ObjInstance - assertEquals("Vault", decObj.objClass.className) - } - - @Test - fun decodeClassObj_shouldResolveWhenEvalFindsButGetMisses() = runTest { - // Build a module scope and define a class there via eval (simulating imported/user code) - val module = net.sergeych.lyng.Script.defaultImportManager.newModule() - module.eval("class Vault() { fun toString() { \"Vault\" } }") - - // Build a child scope where local bindings do not include the class name explicitly - val child = module.createChildScope(module.pos) - - // Sanity: eval in the child must resolve the class by name - val evalResolved = child.eval("Vault") - assertTrue(evalResolved is ObjClass) - - // Create an instance so that encoder will write type Other + class name and constructor args - val inst = child.eval("Vault()") - assertTrue(inst is ObjInstance) - - // Encode the instance and then decode it with our decoder that contains robust class lookup - val bout = MemoryBitOutput() - val enc = LynonEncoder(bout) - enc.encodeAny(child, inst) - val bin = MemoryBitInput(bout.toBitArray()) - val dec = LynonDecoder(bin) - - val decoded = dec.decodeAny(child) - assertTrue(decoded is ObjInstance) - // Class should be resolvable and preserved - val instObj = inst as ObjInstance - val decObj = decoded as ObjInstance - assertEquals(instObj.objClass.className, decObj.objClass.className) - assertEquals("Vault", decObj.objClass.className) - } - @Test fun testSizeInBits() { assertEquals(1, sizeInBits(0u))