From 83282534d73a524c35cab1b229a2a52c9e6164f3 Mon Sep 17 00:00:00 2001 From: Giovanni Ciatto Date: Wed, 1 Jul 2020 10:53:14 +0200 Subject: [PATCH] fix lists serialization and factorise ObjsectsUtils --- .../unibo/tuprolog/serialize/ObjectsUtils.kt | 7 +++++ .../it/unibo/tuprolog/serialize/Parsing.kt | 5 ---- .../serialize/TestTermDeserializer.kt | 30 +++++++++++++++++++ .../tuprolog/serialize/TestTermSerializer.kt | 30 +++++++++++++++++++ .../it/unibo/tuprolog/serialize/TestUtils.kt | 22 ++------------ .../tuprolog/serialize/JsTermDeobjectifier.kt | 2 +- .../tuprolog/serialize/JsTermObjectifier.kt | 17 +++++++---- .../unibo/tuprolog/serialize/ObjectsUtils.kt | 16 ++++++++++ .../it/unibo/tuprolog/serialize/Parsing.kt | 13 -------- .../serialize/JvmTermDeobjectifier.kt | 2 +- .../tuprolog/serialize/JvmTermObjectifier.kt | 15 ++++++---- .../unibo/tuprolog/serialize/ObjectsUtils.kt | 24 +++++++++++++++ .../it/unibo/tuprolog/serialize/Parsing.kt | 22 -------------- .../serialize/JsTheoryDeobjectifier.kt | 2 +- .../tuprolog/serialize/JsTheoryObjectifier.kt | 2 +- 15 files changed, 135 insertions(+), 74 deletions(-) create mode 100644 serialize-core/src/commonMain/kotlin/it/unibo/tuprolog/serialize/ObjectsUtils.kt delete mode 100644 serialize-core/src/commonTest/kotlin/it/unibo/tuprolog/serialize/Parsing.kt create mode 100644 serialize-core/src/jsMain/kotlin/it/unibo/tuprolog/serialize/ObjectsUtils.kt delete mode 100644 serialize-core/src/jsTest/kotlin/it/unibo/tuprolog/serialize/Parsing.kt create mode 100644 serialize-core/src/jvmMain/kotlin/it/unibo/tuprolog/serialize/ObjectsUtils.kt delete mode 100644 serialize-core/src/jvmTest/kotlin/it/unibo/tuprolog/serialize/Parsing.kt diff --git a/serialize-core/src/commonMain/kotlin/it/unibo/tuprolog/serialize/ObjectsUtils.kt b/serialize-core/src/commonMain/kotlin/it/unibo/tuprolog/serialize/ObjectsUtils.kt new file mode 100644 index 000000000..6f234684d --- /dev/null +++ b/serialize-core/src/commonMain/kotlin/it/unibo/tuprolog/serialize/ObjectsUtils.kt @@ -0,0 +1,7 @@ +package it.unibo.tuprolog.serialize + +expect object ObjectsUtils { + fun parseAsObject(string: String, mimeType: MimeType): Any + + fun deeplyEqual(obj1: Any?, obj2: Any?): Boolean +} \ No newline at end of file diff --git a/serialize-core/src/commonTest/kotlin/it/unibo/tuprolog/serialize/Parsing.kt b/serialize-core/src/commonTest/kotlin/it/unibo/tuprolog/serialize/Parsing.kt deleted file mode 100644 index 259f6dc1c..000000000 --- a/serialize-core/src/commonTest/kotlin/it/unibo/tuprolog/serialize/Parsing.kt +++ /dev/null @@ -1,5 +0,0 @@ -package it.unibo.tuprolog.serialize - -expect fun parseAsObject(string: String, mimeType: MimeType): Any - -expect fun deeplyEqual(obj1: Any?, obj2: Any?): Boolean \ No newline at end of file diff --git a/serialize-core/src/commonTest/kotlin/it/unibo/tuprolog/serialize/TestTermDeserializer.kt b/serialize-core/src/commonTest/kotlin/it/unibo/tuprolog/serialize/TestTermDeserializer.kt index b2d83ce91..002c87fc5 100644 --- a/serialize-core/src/commonTest/kotlin/it/unibo/tuprolog/serialize/TestTermDeserializer.kt +++ b/serialize-core/src/commonTest/kotlin/it/unibo/tuprolog/serialize/TestTermDeserializer.kt @@ -4,6 +4,36 @@ import kotlin.test.Test import kotlin.test.assertEquals class TestTermDeserializer { + @Test + fun testTailedListSerializationInJSON() { + val deserializer: TermDeserializer = TermDeserializer.of(MimeType.Json) + assertEquals(MimeType.Json, deserializer.mimeType) + + deserializer.assertTermDeserializationWorks("{\"fun\":\"member\",\"args\":[{\"var\":\"H\"},{\"list\":[{\"var\":\"H\"}],\"tail\":{\"var\":\"_\"}}]}") { + structOf("member", varOf("H"), consOf(varOf("H"), anonymous())) + } + } + + @Test + fun testTailedListSerializationInYAML() { + val deserializer: TermDeserializer = TermDeserializer.of(MimeType.Yaml) + assertEquals(MimeType.Yaml, deserializer.mimeType) + + deserializer.assertTermDeserializationWorks( + """ + |fun: member + |args: + | - var: H + | - list: + | - var: H + | tail: + | var: _ + """.trimMargin() + ) { + structOf("member", varOf("H"), consOf(varOf("H"), anonymous())) + } + } + @Test fun testAtomDeserializationInJSON() { val deserializer: TermDeserializer = TermDeserializer.of(MimeType.Json) diff --git a/serialize-core/src/commonTest/kotlin/it/unibo/tuprolog/serialize/TestTermSerializer.kt b/serialize-core/src/commonTest/kotlin/it/unibo/tuprolog/serialize/TestTermSerializer.kt index 0506039aa..950555f7b 100644 --- a/serialize-core/src/commonTest/kotlin/it/unibo/tuprolog/serialize/TestTermSerializer.kt +++ b/serialize-core/src/commonTest/kotlin/it/unibo/tuprolog/serialize/TestTermSerializer.kt @@ -75,6 +75,16 @@ class TestTermSerializer { } } + @Test + fun testTailedListSerializationInJSON() { + val serializer: TermSerializer = TermSerializer.of(MimeType.Json) + assertEquals(MimeType.Json, serializer.mimeType) + + serializer.assertTermSerializationWorks("{\"fun\":\"member\",\"args\":[{\"var\":\"H\"},{\"list\":[{\"var\":\"H\"}],\"tail\":{\"var\":\"_\"}}]}") { + structOf("member", varOf("H"), consOf(varOf("H"), anonymous())) + } + } + @Test fun testListSerializationInYAML() { val serializer: TermSerializer = TermSerializer.of(MimeType.Yaml) @@ -100,6 +110,26 @@ class TestTermSerializer { } } + @Test + fun testTailedListSerializationInYAML() { + val serializer: TermSerializer = TermSerializer.of(MimeType.Yaml) + assertEquals(MimeType.Yaml, serializer.mimeType) + + serializer.assertTermSerializationWorks( + """ + |fun: member + |args: + | - var: H + | - list: + | - var: H + | tail: + | var: _ + """.trimMargin() + ) { + structOf("member", varOf("H"), consOf(varOf("H"), anonymous())) + } + } + @Test fun testSetSerializationInJSON() { val serializer: TermSerializer = TermSerializer.of(MimeType.Json) diff --git a/serialize-core/src/commonTest/kotlin/it/unibo/tuprolog/serialize/TestUtils.kt b/serialize-core/src/commonTest/kotlin/it/unibo/tuprolog/serialize/TestUtils.kt index ca7aee4be..da8acf691 100644 --- a/serialize-core/src/commonTest/kotlin/it/unibo/tuprolog/serialize/TestUtils.kt +++ b/serialize-core/src/commonTest/kotlin/it/unibo/tuprolog/serialize/TestUtils.kt @@ -1,6 +1,8 @@ package it.unibo.tuprolog.serialize import it.unibo.tuprolog.core.* +import it.unibo.tuprolog.serialize.ObjectsUtils.deeplyEqual +import it.unibo.tuprolog.serialize.ObjectsUtils.parseAsObject /** * Utility assertion method aimed at checking if a serializer correctly works @@ -46,7 +48,7 @@ fun Deserializer.assertDeserializationWorks(expected: T, actual: S |got: | $deserialized | - """.trimMargin()) { termsRepresentationsAreEqual(expected, deserialized) } + """.trimMargin()) { expected.equals(deserialized, false) } } /** @@ -65,22 +67,4 @@ fun Deserializer.assertDeserializationWorks(expected: T, actual: S */ fun Deserializer.assertTermDeserializationWorks(actual: String, expectedGenerator: Scope.() -> Term) { assertDeserializationWorks(Scope.empty().expectedGenerator(), actual) -} - -private fun termsRepresentationsAreEqual(t1: Term, t2: Term): Boolean { - return when { - t1 is Var && t2 is Var -> t1.name == t2.name - t1 is Atom && t2 is Atom -> t1.value == t2.value - t1 is Integer && t2 is Integer -> t1.value.compareTo(t2.value) == 0 - t1 is Real && t2 is Real -> t1.value.compareTo(t2.value) == 0 - t1 is Struct && t2 is Struct -> { - t1.arity == t2.arity && t1.functor == t2.functor && (0 until t1.arity).all { - termsRepresentationsAreEqual( - t1[it], - t2[it] - ) - } - } - else -> false - } } \ No newline at end of file diff --git a/serialize-core/src/jsMain/kotlin/it/unibo/tuprolog/serialize/JsTermDeobjectifier.kt b/serialize-core/src/jsMain/kotlin/it/unibo/tuprolog/serialize/JsTermDeobjectifier.kt index f5f0983d8..7c7f3927b 100644 --- a/serialize-core/src/jsMain/kotlin/it/unibo/tuprolog/serialize/JsTermDeobjectifier.kt +++ b/serialize-core/src/jsMain/kotlin/it/unibo/tuprolog/serialize/JsTermDeobjectifier.kt @@ -74,7 +74,7 @@ internal class JsTermDeobjectifier : TermDeobjectifier { private fun deobjectifyList(value: dynamic): Term { val items = value["list"] as? Array ?: throw DeobjectificationException(value) - val last = value["last"] + val last = value["tail"] return scope.listFrom( items.map { deobjectify(it ?: throw DeobjectificationException(value)) diff --git a/serialize-core/src/jsMain/kotlin/it/unibo/tuprolog/serialize/JsTermObjectifier.kt b/serialize-core/src/jsMain/kotlin/it/unibo/tuprolog/serialize/JsTermObjectifier.kt index fead6be02..ecce00b1b 100644 --- a/serialize-core/src/jsMain/kotlin/it/unibo/tuprolog/serialize/JsTermObjectifier.kt +++ b/serialize-core/src/jsMain/kotlin/it/unibo/tuprolog/serialize/JsTermObjectifier.kt @@ -61,12 +61,19 @@ internal class JsTermObjectifier : TermObjectifier { override fun visitEmptySet(term: EmptySet): Any = visitSet(term) - override fun visitList(term: List): Any = - jsObject("list" to term.toList().map { it.accept(this) }) { - if (!term.isWellFormed) { - this["tail"] = term.unfoldedSequence.last().accept(this@JsTermObjectifier) - } + override fun visitList(term: List): Any { + val listed = term.toList() + return if (term.isWellFormed) { + jsObject( + "list" to listed.map { it.accept(this) }.toTypedArray() + ) + } else { + jsObject( + "list" to listed.subList(0, listed.lastIndex).map { it.accept(this) }.toTypedArray(), + "tail" to listed[listed.lastIndex].accept(this) + ) } + } override fun visitCons(term: Cons): Any = visitList(term) diff --git a/serialize-core/src/jsMain/kotlin/it/unibo/tuprolog/serialize/ObjectsUtils.kt b/serialize-core/src/jsMain/kotlin/it/unibo/tuprolog/serialize/ObjectsUtils.kt new file mode 100644 index 000000000..5d7260009 --- /dev/null +++ b/serialize-core/src/jsMain/kotlin/it/unibo/tuprolog/serialize/ObjectsUtils.kt @@ -0,0 +1,16 @@ +package it.unibo.tuprolog.serialize + +actual object ObjectsUtils { + + actual fun parseAsObject(string: String, mimeType: MimeType): Any { + return when (mimeType) { + is MimeType.Xml -> throw NotImplementedError() + is MimeType.Yaml -> YAML.parse(string) + is MimeType.Json -> JSON.parse(string) + } as Any + } + + actual fun deeplyEqual(obj1: Any?, obj2: Any?): Boolean { + return JSON.stringify(obj1) == JSON.stringify(obj2) + } +} \ No newline at end of file diff --git a/serialize-core/src/jsTest/kotlin/it/unibo/tuprolog/serialize/Parsing.kt b/serialize-core/src/jsTest/kotlin/it/unibo/tuprolog/serialize/Parsing.kt deleted file mode 100644 index b721b790c..000000000 --- a/serialize-core/src/jsTest/kotlin/it/unibo/tuprolog/serialize/Parsing.kt +++ /dev/null @@ -1,13 +0,0 @@ -package it.unibo.tuprolog.serialize - -actual fun parseAsObject(string: String, mimeType: MimeType): Any { - return when (mimeType) { - is MimeType.Xml -> throw NotImplementedError() - is MimeType.Yaml -> YAML.parse(string) - is MimeType.Json -> JSON.parse(string) - } as Any -} - -actual fun deeplyEqual(obj1: Any?, obj2: Any?): Boolean { - return JSON.stringify(obj1) == JSON.stringify(obj2) -} \ No newline at end of file diff --git a/serialize-core/src/jvmMain/kotlin/it/unibo/tuprolog/serialize/JvmTermDeobjectifier.kt b/serialize-core/src/jvmMain/kotlin/it/unibo/tuprolog/serialize/JvmTermDeobjectifier.kt index c56f9bbf1..a7a5615a9 100644 --- a/serialize-core/src/jvmMain/kotlin/it/unibo/tuprolog/serialize/JvmTermDeobjectifier.kt +++ b/serialize-core/src/jvmMain/kotlin/it/unibo/tuprolog/serialize/JvmTermDeobjectifier.kt @@ -70,7 +70,7 @@ internal class JvmTermDeobjectifier : TermDeobjectifier { private fun deobjectifyList(value: Map<*, *>): Term { val items = value["list"] as? List<*> ?: throw DeobjectificationException(value) - val last = value["last"] + val last = value["tail"] return scope.listFrom( items.map { deobjectify(it ?: throw DeobjectificationException(value)) diff --git a/serialize-core/src/jvmMain/kotlin/it/unibo/tuprolog/serialize/JvmTermObjectifier.kt b/serialize-core/src/jvmMain/kotlin/it/unibo/tuprolog/serialize/JvmTermObjectifier.kt index f4ce8f2d0..96ebf8c89 100644 --- a/serialize-core/src/jvmMain/kotlin/it/unibo/tuprolog/serialize/JvmTermObjectifier.kt +++ b/serialize-core/src/jvmMain/kotlin/it/unibo/tuprolog/serialize/JvmTermObjectifier.kt @@ -57,16 +57,19 @@ internal class JvmTermObjectifier : TermObjectifier { override fun visitEmptySet(term: EmptySet): Map = visitSet(term) - override fun visitList(term: List): Map = - mapOf( - "list" to term.toList().map { it.accept(this) } - ) + if (term.isWellFormed) { - emptyMap() + override fun visitList(term: List): Map { + val listed = term.toList() + return if (term.isWellFormed) { + mapOf( + "list" to listed.map { it.accept(this) } + ) } else { mapOf( - "tail" to term.unfoldedSequence.last().accept(this) + "list" to listed.subList(0, listed.lastIndex).map { it.accept(this) }, + "tail" to listed[listed.lastIndex].accept(this) ) } + } override fun visitCons(term: Cons): Map = visitList(term) diff --git a/serialize-core/src/jvmMain/kotlin/it/unibo/tuprolog/serialize/ObjectsUtils.kt b/serialize-core/src/jvmMain/kotlin/it/unibo/tuprolog/serialize/ObjectsUtils.kt new file mode 100644 index 000000000..1b78c382b --- /dev/null +++ b/serialize-core/src/jvmMain/kotlin/it/unibo/tuprolog/serialize/ObjectsUtils.kt @@ -0,0 +1,24 @@ +package it.unibo.tuprolog.serialize + +actual object ObjectsUtils { + actual fun parseAsObject(string: String, mimeType: MimeType): Any { + return mimeType.objectMapper.readValue(string, java.lang.Object::class.java) + } + + actual fun deeplyEqual(obj1: Any?, obj2: Any?): Boolean { + return when { + obj1 is Number && obj2 is Number -> obj1.toString() == obj2.toString() + obj1 is List<*> && obj2 is List<*> -> obj1.asSequence().zip(obj2.asSequence()).all { + deeplyEqual(it.first, it.second) + } + obj1 is Map<*,*> && obj2 is Map<*,*> -> { + if (obj1.keys != obj2.keys) { + false + } else { + obj1.keys.all { deeplyEqual(obj1[it], obj2[it]) } + } + } + else -> obj1 == obj2 + } + } +} \ No newline at end of file diff --git a/serialize-core/src/jvmTest/kotlin/it/unibo/tuprolog/serialize/Parsing.kt b/serialize-core/src/jvmTest/kotlin/it/unibo/tuprolog/serialize/Parsing.kt deleted file mode 100644 index f09d8a458..000000000 --- a/serialize-core/src/jvmTest/kotlin/it/unibo/tuprolog/serialize/Parsing.kt +++ /dev/null @@ -1,22 +0,0 @@ -package it.unibo.tuprolog.serialize - -actual fun parseAsObject(string: String, mimeType: MimeType): Any { - return mimeType.objectMapper.readValue(string, java.lang.Object::class.java) -} - -actual fun deeplyEqual(obj1: Any?, obj2: Any?): Boolean { - return when { - obj1 is Number && obj2 is Number -> obj1.toString() == obj2.toString() - obj1 is List<*> && obj2 is List<*> -> obj1.asSequence().zip(obj2.asSequence()).all { - deeplyEqual(it.first, it.second) - } - obj1 is Map<*,*> && obj2 is Map<*,*> -> { - if (obj1.keys != obj2.keys) { - false - } else { - obj1.keys.all { deeplyEqual(obj1[it], obj2[it]) } - } - } - else -> obj1 == obj2 - } -} \ No newline at end of file diff --git a/serialize-theory/src/jsMain/kotlin/it/unibo/tuprolog/serialize/JsTheoryDeobjectifier.kt b/serialize-theory/src/jsMain/kotlin/it/unibo/tuprolog/serialize/JsTheoryDeobjectifier.kt index b36dd7d46..2b8d94804 100644 --- a/serialize-theory/src/jsMain/kotlin/it/unibo/tuprolog/serialize/JsTheoryDeobjectifier.kt +++ b/serialize-theory/src/jsMain/kotlin/it/unibo/tuprolog/serialize/JsTheoryDeobjectifier.kt @@ -6,7 +6,7 @@ import it.unibo.tuprolog.theory.Theory internal class JsTheoryDeobjectifier : TheoryDeobjectifier { override fun deobjectify(`object`: Any): Theory { return Theory.of( - JsTermDeobjectifier().deobjectifyMany(`object`) + TermDeobjectifier.default.deobjectifyMany(`object`) .asSequence() .map { it as Clause } ) diff --git a/serialize-theory/src/jsMain/kotlin/it/unibo/tuprolog/serialize/JsTheoryObjectifier.kt b/serialize-theory/src/jsMain/kotlin/it/unibo/tuprolog/serialize/JsTheoryObjectifier.kt index 4958a97a4..032951c93 100644 --- a/serialize-theory/src/jsMain/kotlin/it/unibo/tuprolog/serialize/JsTheoryObjectifier.kt +++ b/serialize-theory/src/jsMain/kotlin/it/unibo/tuprolog/serialize/JsTheoryObjectifier.kt @@ -3,7 +3,7 @@ package it.unibo.tuprolog.serialize import it.unibo.tuprolog.theory.Theory internal class JsTheoryObjectifier : TheoryObjectifier { - private val objectifier = JsTermObjectifier() + private val objectifier = TermObjectifier.default override fun objectify(value: Theory): Any { return value.map { objectifier.objectify(it) }.toTypedArray()