diff --git a/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjClass.kt b/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjClass.kt index d7384bf..fd108f3 100644 --- a/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjClass.kt +++ b/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjClass.kt @@ -11,6 +11,8 @@ open class ObjClass( vararg parents: ObjClass, ) : Obj() { + val classNameObj by lazy { ObjString(className) } + var constructorMeta: ArgsDeclaration? = null var instanceConstructor: Statement? = null @@ -100,6 +102,7 @@ open class ObjClass( } open suspend fun deserialize(scope: Scope, decoder: LynonDecoder, lynonType: LynonType?): Obj = scope.raiseNotImplemented() + } diff --git a/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjMap.kt b/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjMap.kt index 769888b..8ee2665 100644 --- a/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjMap.kt +++ b/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjMap.kt @@ -2,6 +2,9 @@ package net.sergeych.lyng.obj import net.sergeych.lyng.Scope import net.sergeych.lyng.Statement +import net.sergeych.lynon.LynonDecoder +import net.sergeych.lynon.LynonEncoder +import net.sergeych.lynon.LynonType class ObjMapEntry(val key: Obj, val value: Obj) : Obj() { @@ -12,6 +15,14 @@ class ObjMapEntry(val key: Obj, val value: Obj) : Obj() { return value.compareTo(scope, other.value) } + override fun hashCode(): Int { + return key.hashCode() + value.hashCode() + } + + override fun equals(other: Any?): Boolean { + return other is ObjMapEntry && key == other.key && value == other.value + } + override suspend fun getAt(scope: Scope, index: Obj): Obj = when (index.toInt()) { 0 -> key 1 -> value @@ -24,11 +35,23 @@ class ObjMapEntry(val key: Obj, val value: Obj) : Obj() { override val objClass = type + override suspend fun serialize(scope: Scope, encoder: LynonEncoder, lynonType: LynonType?) { + encoder.encodeAny(scope,key) + encoder.encodeAny(scope,value) + } + companion object { val type = object : ObjClass("MapEntry", ObjArray) { override suspend fun callOn(scope: Scope): Obj { return ObjMapEntry(scope.requiredArg(0), scope.requiredArg(1)) } + + override suspend fun deserialize(scope: Scope, decoder: LynonDecoder, lynonType: LynonType?): Obj { + return ObjMapEntry( + decoder.decodeAny(scope), + decoder.decodeAny(scope) + ) + } }.apply { addFn("key") { thisAs().key } addFn("value") { thisAs().value } diff --git a/lynglib/src/commonMain/kotlin/net/sergeych/lynon/LynonDecoder.kt b/lynglib/src/commonMain/kotlin/net/sergeych/lynon/LynonDecoder.kt index 2915fd3..b431419 100644 --- a/lynglib/src/commonMain/kotlin/net/sergeych/lynon/LynonDecoder.kt +++ b/lynglib/src/commonMain/kotlin/net/sergeych/lynon/LynonDecoder.kt @@ -3,6 +3,7 @@ package net.sergeych.lynon import net.sergeych.lyng.Scope import net.sergeych.lyng.obj.Obj import net.sergeych.lyng.obj.ObjClass +import net.sergeych.lyng.obj.ObjString open class LynonDecoder(val bin: BitInput, val settings: LynonSettings = LynonSettings.default) { @@ -17,7 +18,7 @@ open class LynonDecoder(val bin: BitInput, val settings: LynonSettings = LynonSe val cache = mutableListOf() - inline fun decodeCached(f: LynonDecoder.() -> T): T { + inline fun decodeCached(f: LynonDecoder.() -> T): T { return if (bin.getBit() == 0) { // unpack and cache f().also { @@ -38,32 +39,47 @@ open class LynonDecoder(val bin: BitInput, val settings: LynonSettings = LynonSe suspend fun decodeAny(scope: Scope): Obj = decodeCached { val type = LynonType.entries[bin.getBits(4).toInt()] - type.objClass.deserialize(scope, this, type) + if (type != LynonType.Other) { + type.objClass.deserialize(scope, this, type) + } else { + decodeClassObj(scope).deserialize(scope, this, null) + } + } + + private suspend fun decodeClassObj(scope: Scope): ObjClass { + val className = decodeObject(scope, ObjString.type, null) as ObjString + println("expected class name $className") + return scope.get(className.value)?.value?.let { + if (it !is ObjClass) + scope.raiseClassCastError("Expected obj class but got ${it::class.qualifiedName}") + it + } ?: scope.raiseSymbolNotFound("can't deserialize: not found type $className") } suspend fun decodeAnyList(scope: Scope): MutableList { - return if( bin.getBit() == 1) { + return if (bin.getBit() == 1) { // homogenous val type = LynonType.entries[getBitsAsInt(4)] + val list = mutableListOf() + val objClass = if (type == LynonType.Other) + decodeClassObj(scope).also { println("detected class obj: $it") } + else type.objClass val size = bin.unpackUnsigned().toInt() println("detected homogenous list type $type, $size items") - val list = mutableListOf() - val objClass = type.objClass - for( i in 0 ..< size) { + for (i in 0.. 6""") + assert(x is ObjMapEntry) + val bout = MemoryBitOutput() + val e = LynonEncoder(bout) + e.encodeAny(s, x) + val bin = bout.toBitInput() + val d = LynonDecoder(bin) + val x2 = d.decodeAny(s) + println(x) + println(x2) + assertTrue { x.compareTo(s, x2) == 0} + assertEquals(x, x2) + + s.eval(""" + testEncode( 1 => "one" ) + testEncode( [1 => "one", 1 => "one"] ) + testEncode( [1 => "one", 1 => "one", "foo" => "MapEntry"] ) + """.trimIndent()) + } } + +