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))