diff --git a/lyng/src/commonMain/kotlin/Common.kt b/lyng/src/commonMain/kotlin/Common.kt index 888f1c2..ff3b304 100644 --- a/lyng/src/commonMain/kotlin/Common.kt +++ b/lyng/src/commonMain/kotlin/Common.kt @@ -9,7 +9,11 @@ import com.github.ajalt.clikt.parameters.arguments.optional import com.github.ajalt.clikt.parameters.options.flag import com.github.ajalt.clikt.parameters.options.option import kotlinx.coroutines.runBlocking -import net.sergeych.lyng.* +import net.sergeych.lyng.LyngVersion +import net.sergeych.lyng.Scope +import net.sergeych.lyng.ScriptError +import net.sergeych.lyng.Source +import net.sergeych.lyng.obj.* import okio.FileSystem import okio.Path.Companion.toPath import okio.SYSTEM diff --git a/lynglib/src/commonMain/kotlin/net/sergeych/lyng/AppliedScope.kt b/lynglib/src/commonMain/kotlin/net/sergeych/lyng/AppliedScope.kt index 8980fec..8ff1abf 100644 --- a/lynglib/src/commonMain/kotlin/net/sergeych/lyng/AppliedScope.kt +++ b/lynglib/src/commonMain/kotlin/net/sergeych/lyng/AppliedScope.kt @@ -1,5 +1,7 @@ package net.sergeych.lyng +import net.sergeych.lyng.obj.ObjRecord + /** * Special version of the [Scope] used to `apply` new this object to * _parent context property. diff --git a/lynglib/src/commonMain/kotlin/net/sergeych/lyng/ArgsDeclaration.kt b/lynglib/src/commonMain/kotlin/net/sergeych/lyng/ArgsDeclaration.kt index 798899a..8016547 100644 --- a/lynglib/src/commonMain/kotlin/net/sergeych/lyng/ArgsDeclaration.kt +++ b/lynglib/src/commonMain/kotlin/net/sergeych/lyng/ArgsDeclaration.kt @@ -1,5 +1,8 @@ package net.sergeych.lyng +import net.sergeych.lyng.obj.Obj +import net.sergeych.lyng.obj.ObjList + /** * List of argument declarations in the __definition__ of the lambda, class constructor, * function, etc. It is created by [Compiler.parseArgsDeclaration] diff --git a/lynglib/src/commonMain/kotlin/net/sergeych/lyng/Arguments.kt b/lynglib/src/commonMain/kotlin/net/sergeych/lyng/Arguments.kt index ae909e8..5886af1 100644 --- a/lynglib/src/commonMain/kotlin/net/sergeych/lyng/Arguments.kt +++ b/lynglib/src/commonMain/kotlin/net/sergeych/lyng/Arguments.kt @@ -1,5 +1,9 @@ package net.sergeych.lyng +import net.sergeych.lyng.obj.Obj +import net.sergeych.lyng.obj.ObjIterable +import net.sergeych.lyng.obj.ObjList + data class ParsedArgument(val value: Statement, val pos: Pos, val isSplat: Boolean = false) suspend fun Collection.toArguments(scope: Scope, tailBlockMode: Boolean): Arguments { @@ -26,7 +30,7 @@ suspend fun Collection.toArguments(scope: Scope, tailBlockMode: return Arguments(list,tailBlockMode) } -data class Arguments(val list: List,val tailBlockMode: Boolean = false) : List by list { +data class Arguments(val list: List, val tailBlockMode: Boolean = false) : List by list { constructor(vararg values: Obj) : this(values.toList()) diff --git a/lynglib/src/commonMain/kotlin/net/sergeych/lyng/Compiler.kt b/lynglib/src/commonMain/kotlin/net/sergeych/lyng/Compiler.kt index 85d0186..c15727d 100644 --- a/lynglib/src/commonMain/kotlin/net/sergeych/lyng/Compiler.kt +++ b/lynglib/src/commonMain/kotlin/net/sergeych/lyng/Compiler.kt @@ -1,5 +1,6 @@ package net.sergeych.lyng +import net.sergeych.lyng.obj.* import net.sergeych.lyng.pacman.ImportProvider /** diff --git a/lynglib/src/commonMain/kotlin/net/sergeych/lyng/ListEntry.kt b/lynglib/src/commonMain/kotlin/net/sergeych/lyng/ListEntry.kt index 8b9463a..2001aa7 100644 --- a/lynglib/src/commonMain/kotlin/net/sergeych/lyng/ListEntry.kt +++ b/lynglib/src/commonMain/kotlin/net/sergeych/lyng/ListEntry.kt @@ -1,5 +1,7 @@ package net.sergeych.lyng +import net.sergeych.lyng.obj.Accessor + sealed class ListEntry { data class Element(val accessor: Accessor) : ListEntry() diff --git a/lynglib/src/commonMain/kotlin/net/sergeych/lyng/LoopBreakContinueException.kt b/lynglib/src/commonMain/kotlin/net/sergeych/lyng/LoopBreakContinueException.kt index e31faca..ffacea5 100644 --- a/lynglib/src/commonMain/kotlin/net/sergeych/lyng/LoopBreakContinueException.kt +++ b/lynglib/src/commonMain/kotlin/net/sergeych/lyng/LoopBreakContinueException.kt @@ -1,5 +1,8 @@ package net.sergeych.lyng +import net.sergeych.lyng.obj.Obj +import net.sergeych.lyng.obj.ObjVoid + class LoopBreakContinueException( val doContinue: Boolean, val result: Obj = ObjVoid, diff --git a/lynglib/src/commonMain/kotlin/net/sergeych/lyng/ModuleScope.kt b/lynglib/src/commonMain/kotlin/net/sergeych/lyng/ModuleScope.kt index a106da6..9741c95 100644 --- a/lynglib/src/commonMain/kotlin/net/sergeych/lyng/ModuleScope.kt +++ b/lynglib/src/commonMain/kotlin/net/sergeych/lyng/ModuleScope.kt @@ -1,5 +1,7 @@ package net.sergeych.lyng +import net.sergeych.lyng.obj.ObjRecord +import net.sergeych.lyng.obj.ObjString import net.sergeych.lyng.pacman.ImportProvider /** diff --git a/lynglib/src/commonMain/kotlin/net/sergeych/lyng/ObjIterator.kt b/lynglib/src/commonMain/kotlin/net/sergeych/lyng/ObjIterator.kt deleted file mode 100644 index 6136868..0000000 --- a/lynglib/src/commonMain/kotlin/net/sergeych/lyng/ObjIterator.kt +++ /dev/null @@ -1,3 +0,0 @@ -package net.sergeych.lyng - -val ObjIterator by lazy { ObjClass("Iterator") } \ No newline at end of file diff --git a/lynglib/src/commonMain/kotlin/net/sergeych/lyng/Scope.kt b/lynglib/src/commonMain/kotlin/net/sergeych/lyng/Scope.kt index 29a5e28..01909f2 100644 --- a/lynglib/src/commonMain/kotlin/net/sergeych/lyng/Scope.kt +++ b/lynglib/src/commonMain/kotlin/net/sergeych/lyng/Scope.kt @@ -1,5 +1,6 @@ package net.sergeych.lyng +import net.sergeych.lyng.obj.* import net.sergeych.lyng.pacman.ImportManager import net.sergeych.lyng.pacman.ImportProvider diff --git a/lynglib/src/commonMain/kotlin/net/sergeych/lyng/Script.kt b/lynglib/src/commonMain/kotlin/net/sergeych/lyng/Script.kt index a6b118d..45bd970 100644 --- a/lynglib/src/commonMain/kotlin/net/sergeych/lyng/Script.kt +++ b/lynglib/src/commonMain/kotlin/net/sergeych/lyng/Script.kt @@ -1,6 +1,7 @@ package net.sergeych.lyng import kotlinx.coroutines.delay +import net.sergeych.lyng.obj.* import net.sergeych.lyng.pacman.ImportManager import kotlin.math.* @@ -114,7 +115,7 @@ class Script( } addFn( "abs" ) { val x = args.firstAndOnly() - if( x is ObjInt ) ObjInt( x.value.absoluteValue ) else ObjReal( x.toDouble().absoluteValue ) + if( x is ObjInt) ObjInt( x.value.absoluteValue ) else ObjReal( x.toDouble().absoluteValue ) } addVoidFn("assert") { diff --git a/lynglib/src/commonMain/kotlin/net/sergeych/lyng/ScriptError.kt b/lynglib/src/commonMain/kotlin/net/sergeych/lyng/ScriptError.kt index 79ba39a..67f0ffe 100644 --- a/lynglib/src/commonMain/kotlin/net/sergeych/lyng/ScriptError.kt +++ b/lynglib/src/commonMain/kotlin/net/sergeych/lyng/ScriptError.kt @@ -2,6 +2,8 @@ package net.sergeych.lyng +import net.sergeych.lyng.obj.ObjException + open class ScriptError(val pos: Pos, val errorMessage: String, cause: Throwable? = null) : Exception( """ $pos: Error: $errorMessage diff --git a/lynglib/src/commonMain/kotlin/net/sergeych/lyng/Obj.kt b/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/Obj.kt similarity index 98% rename from lynglib/src/commonMain/kotlin/net/sergeych/lyng/Obj.kt rename to lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/Obj.kt index d783a13..4151619 100644 --- a/lynglib/src/commonMain/kotlin/net/sergeych/lyng/Obj.kt +++ b/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/Obj.kt @@ -1,10 +1,12 @@ -package net.sergeych.lyng +package net.sergeych.lyng.obj import kotlinx.coroutines.sync.Mutex import kotlinx.coroutines.sync.withLock import kotlinx.serialization.SerialName import kotlinx.serialization.Serializable import net.sergeych.bintools.encodeToHex +import net.sergeych.lyng.* +import net.sergeych.lynon.LynonEncoder import net.sergeych.synctools.ProtectedOp import net.sergeych.synctools.withLock import kotlin.contracts.ExperimentalContracts @@ -267,6 +269,9 @@ open class Obj { val asReadonly: ObjRecord by lazy { ObjRecord(this, false) } val asMutable: ObjRecord by lazy { ObjRecord(this, true) } + open suspend fun serialize(scope: Scope, encoder: LynonEncoder) { + scope.raiseNotImplemented() + } companion object { diff --git a/lynglib/src/commonMain/kotlin/net/sergeych/lyng/ObjArray.kt b/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjArray.kt similarity index 97% rename from lynglib/src/commonMain/kotlin/net/sergeych/lyng/ObjArray.kt rename to lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjArray.kt index 8484b43..6c6cc40 100644 --- a/lynglib/src/commonMain/kotlin/net/sergeych/lyng/ObjArray.kt +++ b/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjArray.kt @@ -1,4 +1,4 @@ -package net.sergeych.lyng +package net.sergeych.lyng.obj val ObjArray by lazy { diff --git a/lynglib/src/commonMain/kotlin/net/sergeych/lyng/ObjArrayIterator.kt b/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjArrayIterator.kt similarity index 94% rename from lynglib/src/commonMain/kotlin/net/sergeych/lyng/ObjArrayIterator.kt rename to lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjArrayIterator.kt index be75dac..82d0e7a 100644 --- a/lynglib/src/commonMain/kotlin/net/sergeych/lyng/ObjArrayIterator.kt +++ b/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjArrayIterator.kt @@ -1,4 +1,6 @@ -package net.sergeych.lyng +package net.sergeych.lyng.obj + +import net.sergeych.lyng.Scope class ObjArrayIterator(val array: Obj) : Obj() { diff --git a/lynglib/src/commonMain/kotlin/net/sergeych/lyng/ObjBool.kt b/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjBool.kt similarity index 50% rename from lynglib/src/commonMain/kotlin/net/sergeych/lyng/ObjBool.kt rename to lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjBool.kt index 5f2d510..95e2549 100644 --- a/lynglib/src/commonMain/kotlin/net/sergeych/lyng/ObjBool.kt +++ b/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjBool.kt @@ -1,4 +1,8 @@ -package net.sergeych.lyng +package net.sergeych.lyng.obj + +import net.sergeych.lyng.Scope +import net.sergeych.lynon.LynonDecoder +import net.sergeych.lynon.LynonEncoder data class ObjBool(val value: Boolean) : Obj() { override val asStr by lazy { ObjString(value.toString()) } @@ -8,6 +12,10 @@ data class ObjBool(val value: Boolean) : Obj() { return value.compareTo(other.value) } + override fun hashCode(): Int { + return value.hashCode() + } + override fun toString(): String = value.toString() override val objClass: ObjClass = type @@ -22,8 +30,25 @@ data class ObjBool(val value: Boolean) : Obj() { return value } + override suspend fun serialize(scope: Scope, encoder: LynonEncoder) { + encoder.packBoolean(value) + } + + override fun equals(other: Any?): Boolean { + if (this === other) return true + if (other == null || this::class != other::class) return false + + other as ObjBool + + return value == other.value + } + companion object { - val type = ObjClass("Bool") + val type = object : ObjClass("Bool") { + override fun deserialize(scope: Scope, decoder: LynonDecoder): Obj { + return ObjBool(decoder.unpackBoolean()) + } + } } } diff --git a/lynglib/src/commonMain/kotlin/net/sergeych/lyng/ObjBuffer.kt b/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjBuffer.kt similarity index 92% rename from lynglib/src/commonMain/kotlin/net/sergeych/lyng/ObjBuffer.kt rename to lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjBuffer.kt index 9054481..01c204e 100644 --- a/lynglib/src/commonMain/kotlin/net/sergeych/lyng/ObjBuffer.kt +++ b/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjBuffer.kt @@ -1,7 +1,9 @@ -package net.sergeych.lyng +package net.sergeych.lyng.obj import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.toList +import net.sergeych.lyng.Scope +import net.sergeych.lyng.statement import kotlin.math.min class ObjBuffer(val byteArray: UByteArray) : Obj() { @@ -40,6 +42,10 @@ class ObjBuffer(val byteArray: UByteArray) : Obj() { val size by byteArray::size + override fun hashCode(): Int { + return byteArray.hashCode() + } + override suspend fun compareTo(scope: Scope, other: Obj): Int { if (other !is ObjBuffer) return super.compareTo(scope, other) val limit = min(size, other.size) @@ -69,6 +75,15 @@ class ObjBuffer(val byteArray: UByteArray) : Obj() { return "Buffer(${byteArray.toList()})" } + override fun equals(other: Any?): Boolean { + if (this === other) return true + if (other == null || this::class != other::class) return false + + other as ObjBuffer + + return byteArray contentEquals other.byteArray + } + companion object { private suspend fun createBufferFrom(scope: Scope, obj: Obj): ObjBuffer = when (obj) { diff --git a/lynglib/src/commonMain/kotlin/net/sergeych/lyng/ObjChar.kt b/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjChar.kt similarity index 57% rename from lynglib/src/commonMain/kotlin/net/sergeych/lyng/ObjChar.kt rename to lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjChar.kt index 593e9d5..77f79ad 100644 --- a/lynglib/src/commonMain/kotlin/net/sergeych/lyng/ObjChar.kt +++ b/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjChar.kt @@ -1,4 +1,6 @@ -package net.sergeych.lyng +package net.sergeych.lyng.obj + +import net.sergeych.lyng.Scope class ObjChar(val value: Char): Obj() { @@ -11,6 +13,19 @@ class ObjChar(val value: Char): Obj() { override fun inspect(): String = "'$value'" + override fun hashCode(): Int { + return value.hashCode() + } + + override fun equals(other: Any?): Boolean { + if (this === other) return true + if (other == null || this::class != other::class) return false + + other as ObjChar + + return value == other.value + } + companion object { val type = ObjClass("Char").apply { addFn("code") { ObjInt(thisAs().value.code.toLong()) } diff --git a/lynglib/src/commonMain/kotlin/net/sergeych/lyng/ObjClass.kt b/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjClass.kt similarity index 94% rename from lynglib/src/commonMain/kotlin/net/sergeych/lyng/ObjClass.kt rename to lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjClass.kt index a4944d5..81d7183 100644 --- a/lynglib/src/commonMain/kotlin/net/sergeych/lyng/ObjClass.kt +++ b/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjClass.kt @@ -1,4 +1,7 @@ -package net.sergeych.lyng +package net.sergeych.lyng.obj + +import net.sergeych.lyng.* +import net.sergeych.lynon.LynonDecoder val ObjClassType by lazy { ObjClass("Class") } @@ -86,6 +89,8 @@ open class ObjClass( } return super.readField(scope, name) } + + open fun deserialize(scope: Scope, decoder: LynonDecoder): Obj = scope.raiseNotImplemented() } diff --git a/lynglib/src/commonMain/kotlin/net/sergeych/lyng/ObjCollection.kt b/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjCollection.kt similarity index 76% rename from lynglib/src/commonMain/kotlin/net/sergeych/lyng/ObjCollection.kt rename to lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjCollection.kt index d1c8fc6..a577261 100644 --- a/lynglib/src/commonMain/kotlin/net/sergeych/lyng/ObjCollection.kt +++ b/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjCollection.kt @@ -1,4 +1,4 @@ -package net.sergeych.lyng +package net.sergeych.lyng.obj /** * Collection is an iterator with `size`] diff --git a/lynglib/src/commonMain/kotlin/net/sergeych/lyng/ObjDuration.kt b/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjDuration.kt similarity index 92% rename from lynglib/src/commonMain/kotlin/net/sergeych/lyng/ObjDuration.kt rename to lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjDuration.kt index 9975601..bdea02d 100644 --- a/lynglib/src/commonMain/kotlin/net/sergeych/lyng/ObjDuration.kt +++ b/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjDuration.kt @@ -1,5 +1,6 @@ -package net.sergeych.lyng +package net.sergeych.lyng.obj +import net.sergeych.lyng.Scope import kotlin.time.Duration import kotlin.time.Duration.Companion.days import kotlin.time.Duration.Companion.hours @@ -21,6 +22,19 @@ class ObjDuration(val duration: Duration) : Obj() { else -1 } + override fun hashCode(): Int { + return duration.hashCode() + } + + override fun equals(other: Any?): Boolean { + if (this === other) return true + if (other == null || this::class != other::class) return false + + other as ObjDuration + + return duration == other.duration + } + companion object { val type = object : ObjClass("Duration") { override suspend fun callOn(scope: Scope): Obj { diff --git a/lynglib/src/commonMain/kotlin/net/sergeych/lyng/ObjInstance.kt b/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjInstance.kt similarity index 95% rename from lynglib/src/commonMain/kotlin/net/sergeych/lyng/ObjInstance.kt rename to lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjInstance.kt index e9989df..cbef791 100644 --- a/lynglib/src/commonMain/kotlin/net/sergeych/lyng/ObjInstance.kt +++ b/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjInstance.kt @@ -1,4 +1,7 @@ -package net.sergeych.lyng +package net.sergeych.lyng.obj + +import net.sergeych.lyng.Arguments +import net.sergeych.lyng.Scope class ObjInstance(override val objClass: ObjClass) : Obj() { diff --git a/lynglib/src/commonMain/kotlin/net/sergeych/lyng/ObjInstant.kt b/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjInstant.kt similarity index 90% rename from lynglib/src/commonMain/kotlin/net/sergeych/lyng/ObjInstant.kt rename to lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjInstant.kt index fdc7498..63f1c90 100644 --- a/lynglib/src/commonMain/kotlin/net/sergeych/lyng/ObjInstant.kt +++ b/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjInstant.kt @@ -1,9 +1,10 @@ -package net.sergeych.lyng +package net.sergeych.lyng.obj import kotlinx.datetime.Clock import kotlinx.datetime.Instant import kotlinx.datetime.isDistantFuture import kotlinx.datetime.isDistantPast +import net.sergeych.lyng.Scope class ObjInstant(val instant: Instant) : Obj() { override val objClass: ObjClass get() = type @@ -38,6 +39,19 @@ class ObjInstant(val instant: Instant) : Obj() { return instant } + override fun hashCode(): Int { + return instant.hashCode() + } + + override fun equals(other: Any?): Boolean { + if (this === other) return true + if (other == null || this::class != other::class) return false + + other as ObjInstant + + return instant == other.instant + } + companion object { val distantFuture by lazy { ObjInstant(Instant.DISTANT_FUTURE) diff --git a/lynglib/src/commonMain/kotlin/net/sergeych/lyng/ObjInt.kt b/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjInt.kt similarity index 86% rename from lynglib/src/commonMain/kotlin/net/sergeych/lyng/ObjInt.kt rename to lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjInt.kt index 8f59877..e97f098 100644 --- a/lynglib/src/commonMain/kotlin/net/sergeych/lyng/ObjInt.kt +++ b/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjInt.kt @@ -1,4 +1,8 @@ -package net.sergeych.lyng +package net.sergeych.lyng.obj + +import net.sergeych.lyng.Scope +import net.sergeych.lynon.LynonDecoder +import net.sergeych.lynon.LynonEncoder class ObjInt(var value: Long,override val isConst: Boolean = false) : Obj(), Numeric { override val asStr get() = ObjString(value.toString()) @@ -93,10 +97,17 @@ class ObjInt(var value: Long,override val isConst: Boolean = false) : Obj(), Num return value == other.value } + override suspend fun serialize(scope: Scope, encoder: LynonEncoder) { + encoder.packSigned(value) + } + companion object { val Zero = ObjInt(0, true) val One = ObjInt(1, true) - val type = ObjClass("Int") + val type = object: ObjClass("Int") { + override fun deserialize(scope: Scope, decoder: LynonDecoder): Obj = + ObjInt(decoder.unpackSigned()) + } } } diff --git a/lynglib/src/commonMain/kotlin/net/sergeych/lyng/ObjIterable.kt b/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjIterable.kt similarity index 96% rename from lynglib/src/commonMain/kotlin/net/sergeych/lyng/ObjIterable.kt rename to lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjIterable.kt index 3bdb25e..8788905 100644 --- a/lynglib/src/commonMain/kotlin/net/sergeych/lyng/ObjIterable.kt +++ b/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjIterable.kt @@ -1,4 +1,7 @@ -package net.sergeych.lyng +package net.sergeych.lyng.obj + +import net.sergeych.lyng.Arguments +import net.sergeych.lyng.Statement /** * Abstract class that must provide `iterator` method that returns [ObjIterator] instance. diff --git a/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjIterator.kt b/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjIterator.kt new file mode 100644 index 0000000..f14f4db --- /dev/null +++ b/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjIterator.kt @@ -0,0 +1,3 @@ +package net.sergeych.lyng.obj + +val ObjIterator by lazy { ObjClass("Iterator") } \ No newline at end of file diff --git a/lynglib/src/commonMain/kotlin/net/sergeych/lyng/ObjKotlinIterator.kt b/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjKotlinIterator.kt similarity index 96% rename from lynglib/src/commonMain/kotlin/net/sergeych/lyng/ObjKotlinIterator.kt rename to lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjKotlinIterator.kt index e739f36..686a2db 100644 --- a/lynglib/src/commonMain/kotlin/net/sergeych/lyng/ObjKotlinIterator.kt +++ b/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjKotlinIterator.kt @@ -1,9 +1,10 @@ @file:Suppress("unused") -package net.sergeych.lyng +package net.sergeych.lyng.obj import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.flow +import net.sergeych.lyng.Scope /** * Iterator wrapper to allow Kotlin collections to be returned from Lyng objects; diff --git a/lynglib/src/commonMain/kotlin/net/sergeych/lyng/ObjList.kt b/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjList.kt similarity index 98% rename from lynglib/src/commonMain/kotlin/net/sergeych/lyng/ObjList.kt rename to lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjList.kt index c062a2b..93a9816 100644 --- a/lynglib/src/commonMain/kotlin/net/sergeych/lyng/ObjList.kt +++ b/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjList.kt @@ -1,4 +1,7 @@ -package net.sergeych.lyng +package net.sergeych.lyng.obj + +import net.sergeych.lyng.Scope +import net.sergeych.lyng.statement class ObjList(val list: MutableList = mutableListOf()) : Obj() { diff --git a/lynglib/src/commonMain/kotlin/net/sergeych/lyng/ObjMap.kt b/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjMap.kt similarity index 90% rename from lynglib/src/commonMain/kotlin/net/sergeych/lyng/ObjMap.kt rename to lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjMap.kt index aa232b4..769888b 100644 --- a/lynglib/src/commonMain/kotlin/net/sergeych/lyng/ObjMap.kt +++ b/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjMap.kt @@ -1,4 +1,7 @@ -package net.sergeych.lyng +package net.sergeych.lyng.obj + +import net.sergeych.lyng.Scope +import net.sergeych.lyng.Statement class ObjMapEntry(val key: Obj, val value: Obj) : Obj() { @@ -55,6 +58,19 @@ class ObjMap(val map: MutableMap = mutableMapOf()) : Obj() { } override fun toString(): String = map.toString() + override fun hashCode(): Int { + return map.hashCode() + } + + override fun equals(other: Any?): Boolean { + if (this === other) return true + if (other == null || this::class != other::class) return false + + other as ObjMap + + return map == other.map + } + companion object { suspend fun listToMap(scope: Scope, list: List): MutableMap { diff --git a/lynglib/src/commonMain/kotlin/net/sergeych/lyng/ObjRange.kt b/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjRange.kt similarity index 84% rename from lynglib/src/commonMain/kotlin/net/sergeych/lyng/ObjRange.kt rename to lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjRange.kt index c80c5e4..5e4677f 100644 --- a/lynglib/src/commonMain/kotlin/net/sergeych/lyng/ObjRange.kt +++ b/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjRange.kt @@ -1,4 +1,6 @@ -package net.sergeych.lyng +package net.sergeych.lyng.obj + +import net.sergeych.lyng.Scope class ObjRange(val start: Obj?, val end: Obj?, val isEndInclusive: Boolean) : Obj() { @@ -34,9 +36,9 @@ class ObjRange(val start: Obj?, val end: Obj?, val isEndInclusive: Boolean) : Ob * otherwise returns start.value.toInt() */ fun startInt(scope: Scope): Int = - if( start == null || start is ObjNull ) 0 + if( start == null || start is ObjNull) 0 else { - if( start is ObjInt ) start.value.toInt() + if( start is ObjInt) start.value.toInt() else scope.raiseIllegalArgument("start is not Int: ${start.inspect()}") } @@ -99,6 +101,27 @@ class ObjRange(val start: Obj?, val end: Obj?, val isEndInclusive: Boolean) : Ob ?: -1 } + override fun hashCode(): Int { + var result = start?.hashCode() ?: 0 + result = 31 * result + (end?.hashCode() ?: 0) + result = 31 * result + isEndInclusive.hashCode() + return result + } + + override fun equals(other: Any?): Boolean { + if (this === other) return true + if (other == null || this::class != other::class) return false + + other as ObjRange + + if (start != other.start) return false + if (end != other.end) return false + if (isEndInclusive != other.isEndInclusive) return false + + return true + } + + companion object { val type = ObjClass("Range", ObjIterable).apply { addFn("start") { diff --git a/lynglib/src/commonMain/kotlin/net/sergeych/lyng/ObjRangeIterator.kt b/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjRangeIterator.kt similarity index 95% rename from lynglib/src/commonMain/kotlin/net/sergeych/lyng/ObjRangeIterator.kt rename to lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjRangeIterator.kt index bffeac0..73dba67 100644 --- a/lynglib/src/commonMain/kotlin/net/sergeych/lyng/ObjRangeIterator.kt +++ b/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjRangeIterator.kt @@ -1,4 +1,6 @@ -package net.sergeych.lyng +package net.sergeych.lyng.obj + +import net.sergeych.lyng.Scope class ObjRangeIterator(val self: ObjRange) : Obj() { diff --git a/lynglib/src/commonMain/kotlin/net/sergeych/lyng/ObjReal.kt b/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjReal.kt similarity index 79% rename from lynglib/src/commonMain/kotlin/net/sergeych/lyng/ObjReal.kt rename to lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjReal.kt index 63785af..c47bb0f 100644 --- a/lynglib/src/commonMain/kotlin/net/sergeych/lyng/ObjReal.kt +++ b/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjReal.kt @@ -1,5 +1,10 @@ -package net.sergeych.lyng +package net.sergeych.lyng.obj +import net.sergeych.lyng.Pos +import net.sergeych.lyng.Scope +import net.sergeych.lyng.statement +import net.sergeych.lynon.LynonDecoder +import net.sergeych.lynon.LynonEncoder import kotlin.math.floor import kotlin.math.roundToLong @@ -56,8 +61,15 @@ data class ObjReal(val value: Double) : Obj(), Numeric { return value == other.value } + override suspend fun serialize(scope: Scope, encoder: LynonEncoder) { + encoder.packReal(value) + } + companion object { - val type: ObjClass = ObjClass("Real").apply { + val type: ObjClass = object : ObjClass("Real") { + override fun deserialize(scope: Scope, decoder: LynonDecoder): Obj = + ObjReal(decoder.unpackDouble()) + }.apply { createField( "roundToInt", statement(Pos.builtIn) { diff --git a/lynglib/src/commonMain/kotlin/net/sergeych/lyng/ObjSet.kt b/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjSet.kt similarity index 89% rename from lynglib/src/commonMain/kotlin/net/sergeych/lyng/ObjSet.kt rename to lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjSet.kt index b4b9a86..68f7eec 100644 --- a/lynglib/src/commonMain/kotlin/net/sergeych/lyng/ObjSet.kt +++ b/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjSet.kt @@ -1,4 +1,6 @@ -package net.sergeych.lyng +package net.sergeych.lyng.obj + +import net.sergeych.lyng.Scope class ObjSet(val set: MutableSet = mutableSetOf()) : Obj() { @@ -65,6 +67,19 @@ class ObjSet(val set: MutableSet = mutableSetOf()) : Obj() { } } + override fun hashCode(): Int { + return set.hashCode() + } + + override fun equals(other: Any?): Boolean { + if (this === other) return true + if (other == null || this::class != other::class) return false + + other as ObjSet + + return set == other.set + } + companion object { diff --git a/lynglib/src/commonMain/kotlin/net/sergeych/lyng/ObjString.kt b/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjString.kt similarity index 84% rename from lynglib/src/commonMain/kotlin/net/sergeych/lyng/ObjString.kt rename to lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjString.kt index 8ad39a9..42b9cfa 100644 --- a/lynglib/src/commonMain/kotlin/net/sergeych/lyng/ObjString.kt +++ b/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjString.kt @@ -1,7 +1,11 @@ -package net.sergeych.lyng +package net.sergeych.lyng.obj import kotlinx.serialization.SerialName import kotlinx.serialization.Serializable +import net.sergeych.lyng.Scope +import net.sergeych.lyng.statement +import net.sergeych.lynon.LynonDecoder +import net.sergeych.lynon.LynonEncoder import net.sergeych.sprintf.sprintf @Serializable @@ -36,8 +40,8 @@ data class ObjString(val value: String) : Obj() { } override suspend fun getAt(scope: Scope, index: Obj): Obj { - if( index is ObjInt ) return ObjChar(value[index.toInt()]) - if( index is ObjRange ) { + if( index is ObjInt) return ObjChar(value[index.toInt()]) + if( index is ObjRange) { val start = if(index.start == null || index.start.isNull) 0 else index.start.toInt() val end = if( index.end == null || index.end.isNull ) value.length else { val e = index.end.toInt() @@ -73,8 +77,18 @@ data class ObjString(val value: String) : Obj() { return value == other.value } + override suspend fun serialize(scope: Scope, encoder: LynonEncoder) { + encoder.packBinaryData(value.encodeToByteArray()) + } + companion object { - val type = ObjClass("String").apply { + val type = object : ObjClass("String") { + override fun deserialize(scope: Scope, decoder: LynonDecoder): Obj = + ObjString( + decoder.unpackBinaryData()?.decodeToString() + ?: scope.raiseError("unexpected end of data") + ) + }.apply { addFn("toInt") { ObjInt(thisAs().value.toLong()) } @@ -119,7 +133,7 @@ data class ObjString(val value: String) : Obj() { ) } addFn("size") { ObjInt(thisAs().value.length.toLong()) } - addFn("toReal") { ObjReal(thisAs().value.toDouble())} + addFn("toReal") { ObjReal(thisAs().value.toDouble()) } } } } \ No newline at end of file diff --git a/lynglib/src/commonMain/kotlin/net/sergeych/lyng/statements.kt b/lynglib/src/commonMain/kotlin/net/sergeych/lyng/statements.kt index 4860d1e..7154a4d 100644 --- a/lynglib/src/commonMain/kotlin/net/sergeych/lyng/statements.kt +++ b/lynglib/src/commonMain/kotlin/net/sergeych/lyng/statements.kt @@ -1,5 +1,8 @@ package net.sergeych.lyng +import net.sergeych.lyng.obj.Obj +import net.sergeych.lyng.obj.ObjClass + fun String.toSource(name: String = "eval"): Source = Source(name, this) sealed class ObjType { diff --git a/lynglib/src/commonMain/kotlin/net/sergeych/lynon/BitInput.kt b/lynglib/src/commonMain/kotlin/net/sergeych/lynon/BitInput.kt index f2f2ada..92a5a1f 100644 --- a/lynglib/src/commonMain/kotlin/net/sergeych/lynon/BitInput.kt +++ b/lynglib/src/commonMain/kotlin/net/sergeych/lynon/BitInput.kt @@ -55,7 +55,7 @@ abstract class BitInput { val tetrades = getBits(4).toInt() var result = 0UL var shift = 0 - for (i in 0..() + + fun unpackObject(scope: Scope, type: ObjClass): Obj { + return if( bin.getBit() == 0 ) { + // unpack and cache + val cached = bin.getBool() + type.deserialize(scope, this).also { + if( cached ) cache.add(it) + } + } + else { + // get cache reference + val size = sizeInBits(cache.size) + val id = bin.getBitsOrNull(size)?.toInt() ?: scope.raiseError("Invalid object id: unexpected end of stream") + if( id >= cache.size ) scope.raiseError("Invalid object id: $id should be in 0..<${cache.size}") + cache[id] + } + } + + fun unpackBinaryData(): ByteArray? { + val size = bin.unpackUnsigned() + return bin.getBytes(size.toInt()) + } + + fun unpackBoolean(): Boolean { + return bin.getBit() == 1 + } + + fun unpackDouble(): Double { + return Double.fromBits(bin.getBits(64).toLong()) + } + + fun unpackSigned(): Long { + return bin.unpackSigned() + } + +} \ No newline at end of file diff --git a/lynglib/src/commonMain/kotlin/net/sergeych/lynon/LynonEncoder.kt b/lynglib/src/commonMain/kotlin/net/sergeych/lynon/LynonEncoder.kt new file mode 100644 index 0000000..083e32b --- /dev/null +++ b/lynglib/src/commonMain/kotlin/net/sergeych/lynon/LynonEncoder.kt @@ -0,0 +1,62 @@ +package net.sergeych.lynon + +import net.sergeych.lyng.Scope +import net.sergeych.lyng.obj.Obj +import net.sergeych.lyng.obj.ObjBool +import net.sergeych.lyng.obj.ObjChar +import net.sergeych.lyng.obj.ObjInt + +class LynonPacker(private val bout: MemoryBitOutput= MemoryBitOutput()) : LynonEncoder(bout) { + fun toUByteArray(): UByteArray = bout.toUByteArray() +} + +class LynonUnpacker(source: UByteArray) : LynonDecoder(MemoryBitInput(source)) + +open class LynonEncoder(private val bout: BitOutput) { + + fun shouldCache(obj: Obj): Boolean = when (obj) { + is ObjChar -> false + is ObjInt -> obj.value > 0x10000FF + is ObjBool -> false + else -> true + } + + val cache = mutableMapOf() + + suspend fun packObject(scope: Scope,obj: Obj) { + cache[obj]?.let { cacheId -> + val size = sizeInBits(cache.size) + bout.putBit(1) + bout.putBits(cacheId, size) + } ?: run { + bout.putBit(0) + if( shouldCache(obj) ) { + bout.putBit(1) + cache[obj] = cache.size + } + else + bout.putBit(0) + obj.serialize(scope, this) + } + } + + fun packBinaryData(data: ByteArray) { + bout.packUnsigned(data.size.toULong()) + bout.putBytes(data) + } + + fun packSigned(value: Long) { bout.packSigned(value) } + @Suppress("unused") + fun packUnsigned(value: ULong) { bout.packUnsigned(value) } + + @Suppress("unused") + fun packBool(value: Boolean) { bout.putBit(if (value) 1 else 0) } + fun packReal(value: Double) { + bout.putBits(value.toRawBits().toULong(), 64) + } + + fun packBoolean(value: Boolean) { + bout.putBit(if (value) 1 else 0) + } + +} \ No newline at end of file diff --git a/lynglib/src/commonMain/kotlin/net/sergeych/lynon/MemoryBitInput.kt b/lynglib/src/commonMain/kotlin/net/sergeych/lynon/MemoryBitInput.kt index 0f91712..a7f8c93 100644 --- a/lynglib/src/commonMain/kotlin/net/sergeych/lynon/MemoryBitInput.kt +++ b/lynglib/src/commonMain/kotlin/net/sergeych/lynon/MemoryBitInput.kt @@ -1,6 +1,8 @@ package net.sergeych.lynon class MemoryBitInput(val packedBits: UByteArray): BitInput() { + constructor(bout: MemoryBitOutput): this(bout.toUByteArray()) + private var index = 0 override fun getByte(): Int { diff --git a/lynglib/src/commonMain/kotlin/net/sergeych/lynon/bit_tools.kt b/lynglib/src/commonMain/kotlin/net/sergeych/lynon/bit_tools.kt index bbc5068..32eefc0 100644 --- a/lynglib/src/commonMain/kotlin/net/sergeych/lynon/bit_tools.kt +++ b/lynglib/src/commonMain/kotlin/net/sergeych/lynon/bit_tools.kt @@ -30,4 +30,6 @@ fun sizeInBits(value: ULong): Int { rest = rest shr 1 } return size -} \ No newline at end of file +} + +fun sizeInBits(value: Int): Int = sizeInBits(value.toULong()) \ No newline at end of file diff --git a/lynglib/src/commonTest/kotlin/ScriptTest.kt b/lynglib/src/commonTest/kotlin/ScriptTest.kt index 0e9ccf8..c8e1bc0 100644 --- a/lynglib/src/commonTest/kotlin/ScriptTest.kt +++ b/lynglib/src/commonTest/kotlin/ScriptTest.kt @@ -3,6 +3,7 @@ import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.toList import kotlinx.coroutines.test.runTest import net.sergeych.lyng.* +import net.sergeych.lyng.obj.* import net.sergeych.lyng.pacman.InlineSourcesImportProvider import kotlin.test.* diff --git a/lynglib/src/jvmTest/kotlin/BookTest.kt b/lynglib/src/jvmTest/kotlin/BookTest.kt index 23fd2ec..46a52f7 100644 --- a/lynglib/src/jvmTest/kotlin/BookTest.kt +++ b/lynglib/src/jvmTest/kotlin/BookTest.kt @@ -4,8 +4,8 @@ import kotlinx.coroutines.flow.flow import kotlinx.coroutines.flow.flowOn import kotlinx.coroutines.runBlocking import kotlinx.coroutines.test.runTest -import net.sergeych.lyng.ObjVoid import net.sergeych.lyng.Scope +import net.sergeych.lyng.obj.ObjVoid import java.nio.file.Files import java.nio.file.Files.readAllLines import java.nio.file.Paths diff --git a/lynglib/src/jvmTest/kotlin/LynonTests.kt b/lynglib/src/jvmTest/kotlin/LynonTests.kt index f8be460..d29b7c3 100644 --- a/lynglib/src/jvmTest/kotlin/LynonTests.kt +++ b/lynglib/src/jvmTest/kotlin/LynonTests.kt @@ -1,8 +1,8 @@ -import junit.framework.TestCase.assertEquals -import net.sergeych.bintools.toDump -import net.sergeych.lynon.MemoryBitInput -import net.sergeych.lynon.MemoryBitOutput -import net.sergeych.lynon.sizeInTetrades +import junit.framework.TestCase.* +import kotlinx.coroutines.test.runTest +import net.sergeych.lyng.Scope +import net.sergeych.lyng.obj.* +import net.sergeych.lynon.* import kotlin.test.Test class LynonTests { @@ -19,14 +19,23 @@ class LynonTests { assertEquals(3, sizeInTetrades(257u)) } + @Test + fun testSizeInBits() { + assertEquals(1, sizeInBits(0u)) + assertEquals(1, sizeInBits(1u)) + assertEquals(2, sizeInBits(2u)) + assertEquals(2, sizeInBits(3u)) + assertEquals(4, sizeInBits(15u)) + } + @Test fun testBitStreams() { val bout = MemoryBitOutput() bout.putBits(2, 3) bout.putBits(1, 7) - bout.putBits( 197, 8) - bout.putBits( 3, 4) + bout.putBits(197, 8) + bout.putBits(3, 4) bout.close() val bin = MemoryBitInput(bout.toUByteArray()) @@ -41,11 +50,28 @@ class LynonTests { val bout = MemoryBitOutput() bout.packUnsigned(1471792UL) bout.close() - println(bout.toUByteArray().toDump()) val bin = MemoryBitInput(bout.toUByteArray()) assertEquals(1471792UL, bin.unpackUnsigned()) } + @Test + fun testUnsignedPackLongInteger() { + val bout = MemoryBitOutput() + bout.packUnsigned(ULong.MAX_VALUE) + bout.close() + val bin = MemoryBitInput(bout.toUByteArray()) + assertEquals(ULong.MAX_VALUE, bin.unpackUnsigned()) + } + + @Test + fun testUnsignedPackLongSmallInteger() { + val bout = MemoryBitOutput() + bout.packUnsigned(7UL) + bout.close() + val bin = MemoryBitInput(bout.toUByteArray()) + assertEquals(7UL, bin.unpackUnsigned()) + } + @Test fun testSignedPackInteger() { val bout = MemoryBitOutput() @@ -53,10 +79,114 @@ class LynonTests { bout.packSigned(1471792L) // bout.packSigned(147179L) bout.close() - println(bout.toUByteArray().toDump()) val bin = MemoryBitInput(bout.toUByteArray()) assertEquals(-1471792L, bin.unpackSigned()) assertEquals(1471792L, bin.unpackSigned()) } + @Test + fun testCache1() = runTest { + val bout = MemoryBitOutput() + val encoder = LynonEncoder(bout) + val s = "Hello, World!".toObj() + val scope = Scope() + encoder.packObject(scope, s) // 1 + encoder.packObject(scope, s) + encoder.packObject(scope, s) + encoder.packObject(scope, s) + encoder.packObject(scope, s) + encoder.packObject(scope, s) + encoder.packObject(scope, s) + encoder.packObject(scope, s) // 8 + + val decoder = LynonDecoder(MemoryBitInput(bout)) + val s1 = decoder.unpackObject(scope, ObjString.type) // 1 + assertEquals(s, s1) + assertNotSame(s, s1) + val s2 = decoder.unpackObject(scope, ObjString.type) + assertEquals(s, s2) + assertSame(s1, s2) + assertSame(s1, decoder.unpackObject(scope, ObjString.type)) + assertSame(s1, decoder.unpackObject(scope, ObjString.type)) + assertSame(s1, decoder.unpackObject(scope, ObjString.type)) + assertSame(s1, decoder.unpackObject(scope, ObjString.type)) + assertSame(s1, decoder.unpackObject(scope, ObjString.type)) + assertSame(s1, decoder.unpackObject(scope, ObjString.type)) // 8 + } + + @Test + fun testCache2() = runTest { + val variants = (100..500).map { "Sample $it".toObj() }.shuffled() + var source = variants.shuffled() + for (i in 0..300) source += variants.shuffled() + val encoder = LynonPacker() + val scope = Scope() + for (s in source) { + encoder.packObject(scope, s) + } + val decoder = LynonUnpacker(encoder.toUByteArray()) + val restored = mutableListOf() + for (i in source.indices) { + restored.add(decoder.unpackObject(scope, ObjString.type)) + } + assertEquals(restored, source) + } + + @Test + fun testUnpackBoolean() = runTest { + val scope = Scope() + val decoder = LynonUnpacker(LynonPacker().apply { + packObject(scope, ObjBool(true)) + packObject(scope, ObjBool(false)) + packObject(scope, ObjBool(true)) + packObject(scope, ObjBool(true)) + }.toUByteArray()) + assertEquals(ObjTrue, decoder.unpackObject(scope, ObjBool.type)) + assertEquals(ObjFalse, decoder.unpackObject(scope, ObjBool.type)) + assertEquals(ObjTrue, decoder.unpackObject(scope, ObjBool.type)) + assertEquals(ObjTrue, decoder.unpackObject(scope, ObjBool.type)) + } + + @Test + fun testUnpackReal() = runTest { + val scope = Scope() + val decoder = LynonUnpacker(LynonPacker().apply { + packObject(scope, ObjReal(-Math.PI)) + packObject(scope, ObjReal(Math.PI)) + packObject(scope, ObjReal(-Math.PI)) + packObject(scope, ObjReal(Math.PI)) + packObject(scope, ObjReal(Double.NaN)) + packObject(scope, ObjReal(Double.NEGATIVE_INFINITY)) + packObject(scope, ObjReal(Double.POSITIVE_INFINITY)) + packObject(scope, ObjReal(Double.MIN_VALUE)) + packObject(scope, ObjReal(Double.MAX_VALUE)) + }.toUByteArray()) + assertEquals(ObjReal(-Math.PI), decoder.unpackObject(scope, ObjReal.type)) + assertEquals(ObjReal(Math.PI), decoder.unpackObject(scope, ObjReal.type)) + assertEquals(ObjReal(-Math.PI), decoder.unpackObject(scope, ObjReal.type)) + assertEquals(ObjReal(Math.PI), decoder.unpackObject(scope, ObjReal.type)) + assert((decoder.unpackObject(scope, ObjReal.type)).toDouble().isNaN()) + assertEquals(ObjReal(Double.NEGATIVE_INFINITY), decoder.unpackObject(scope, ObjReal.type)) + assertEquals(ObjReal(Double.POSITIVE_INFINITY), decoder.unpackObject(scope, ObjReal.type)) + assertEquals(ObjReal(Double.MIN_VALUE), decoder.unpackObject(scope, ObjReal.type)) + assertEquals(ObjReal(Double.MAX_VALUE), decoder.unpackObject(scope, ObjReal.type)) + } + @Test + fun testUnpackInt() = runTest { + val scope = Scope() + val decoder = LynonUnpacker(LynonPacker().apply { + packObject(scope, ObjInt(0)) + packObject(scope, ObjInt(-1)) + packObject(scope, ObjInt(23)) + packObject(scope, ObjInt(Long.MIN_VALUE)) + packObject(scope, ObjInt(Long.MAX_VALUE)) + packObject(scope, ObjInt(Long.MAX_VALUE)) + }.toUByteArray()) + assertEquals(ObjInt(0), decoder.unpackObject(scope, ObjInt.type)) + assertEquals(ObjInt(-1), decoder.unpackObject(scope, ObjInt.type)) + assertEquals(ObjInt(23), decoder.unpackObject(scope, ObjInt.type)) + assertEquals(ObjInt(Long.MIN_VALUE), decoder.unpackObject(scope, ObjInt.type)) + assertEquals(ObjInt(Long.MAX_VALUE), decoder.unpackObject(scope, ObjInt.type)) + assertEquals(ObjInt(Long.MAX_VALUE), decoder.unpackObject(scope, ObjInt.type)) + } } \ No newline at end of file