diff --git a/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/Obj.kt b/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/Obj.kt index ab8ec7c..2c158c5 100644 --- a/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/Obj.kt +++ b/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/Obj.kt @@ -142,15 +142,19 @@ open class Obj { * @param calledFromLyng true if called from Lyng's `toString`. Normally this parameter should be ignored, * but it is used to avoid endless recursion in [Obj.toString] base implementation */ - open suspend fun toString(scope: Scope,calledFromLyng: Boolean=false): ObjString { - return if (this is ObjString) this - else if( !calledFromLyng ) { - invokeInstanceMethod(scope, "toString") { - ObjString(this.toString()) + open suspend fun toString(scope: Scope, calledFromLyng: Boolean = false): ObjString { + if (this is ObjString) return this + return if (!calledFromLyng) { + invokeInstanceMethod(scope, "toString", Arguments.EMPTY) { + defaultToString(scope) } as ObjString - } else { ObjString(this.toString()) } + } else { + defaultToString(scope) + } } + open suspend fun defaultToString(scope: Scope): ObjString = ObjString(this.toString()) + /** * Class of the object: definition of member functions (top-level), etc. * Note that using lazy allows to avoid endless recursion here diff --git a/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjException.kt b/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjException.kt index 372bcf5..e65a5a3 100644 --- a/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjException.kt +++ b/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjException.kt @@ -89,7 +89,7 @@ open class ObjException( override val objClass: ObjClass = exceptionClass - override suspend fun toString(scope: Scope, calledFromLyng: Boolean): ObjString { + override suspend fun defaultToString(scope: Scope): ObjString { val at = getStackTrace().list.firstOrNull()?.toString(scope) ?: ObjString("(unknown)") return ObjString("${objClass.className}: $message at $at") diff --git a/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjInstance.kt b/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjInstance.kt index 0fe857a..15dcd24 100644 --- a/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjInstance.kt +++ b/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjInstance.kt @@ -187,16 +187,16 @@ class ObjInstance(override val objClass: ObjClass) : Obj() { !it.key.contains("::") && it.value.visibility.isPublic && it.value.type.serializable } - override suspend fun toString(scope: Scope, calledFromLyng: Boolean): ObjString { + override suspend fun defaultToString(scope: Scope): ObjString { return ObjString(buildString { - append("${objClass.className}(") - var first = true - for ((name, value) in publicFields) { - if (first) first = false else append(",") - append("$name=${value.value.toString(scope)}") - } - append(")") - }) + append("${objClass.className}(") + var first = true + for ((name, value) in publicFields) { + if (first) first = false else append(",") + append("$name=${value.value.toString(scope)}") + } + append(")") + }) } override suspend fun inspect(scope: Scope): String { diff --git a/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjInstanceClass.kt b/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjInstanceClass.kt index 3597766..3f211d4 100644 --- a/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjInstanceClass.kt +++ b/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjInstanceClass.kt @@ -43,7 +43,7 @@ class ObjInstanceClass(val name: String, vararg parents: ObjClass) : ObjClass(na init { addFn("toString", true) { - ObjString(thisObj.toString()) + thisObj.toString(this, true) } } diff --git a/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjList.kt b/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjList.kt index 216cbdd..909d60d 100644 --- a/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjList.kt +++ b/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjList.kt @@ -198,7 +198,7 @@ class ObjList(val list: MutableList = mutableListOf()) : Obj() { return JsonArray(list.map { it.toJson(scope) }) } - override suspend fun toString(scope: Scope, calledFromLyng: Boolean): ObjString { + override suspend fun defaultToString(scope: Scope): ObjString { return ObjString(buildString { append("[") var first = true 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 55db28e..55bbbe7 100644 --- a/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjMap.kt +++ b/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjMap.kt @@ -52,7 +52,7 @@ class ObjMapEntry(val key: Obj, val value: Obj) : Obj() { else -> scope.raiseIndexOutOfBounds() } - override suspend fun toString(scope: Scope, calledFromLyng: Boolean): ObjString { + override suspend fun defaultToString(scope: Scope): ObjString { return ObjString("(${key.toString(scope).value} => ${value.toString(scope).value})") } @@ -124,7 +124,7 @@ class ObjMap(val map: MutableMap = mutableMapOf()) : Obj() { return -1 } - override suspend fun toString(scope: Scope, calledFromLyng: Boolean): ObjString { + override suspend fun defaultToString(scope: Scope): ObjString { val reusult = buildString { append("Map(") var first = true diff --git a/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjRange.kt b/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjRange.kt index 3f782c0..6bc7e59 100644 --- a/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjRange.kt +++ b/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjRange.kt @@ -29,7 +29,7 @@ class ObjRange(val start: Obj?, val end: Obj?, val isEndInclusive: Boolean) : Ob override val objClass: ObjClass = type - override suspend fun toString(scope: Scope,calledFromLyng: Boolean): ObjString { + override suspend fun defaultToString(scope: Scope): ObjString { val result = StringBuilder() result.append("${start?.inspect(scope) ?: '∞'} ..") if (!isEndInclusive) result.append('<') diff --git a/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjRegex.kt b/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjRegex.kt index b9b5033..aed2ef0 100644 --- a/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjRegex.kt +++ b/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjRegex.kt @@ -103,7 +103,7 @@ class ObjRegexMatch(val match: MatchResult) : Obj() { ) } - override suspend fun toString(scope: Scope,calledFromLyng: Boolean): ObjString { + override suspend fun defaultToString(scope: Scope): ObjString { return ObjString("RegexMath(${objRange.toString(scope)},${objGroups.toString(scope)})") } diff --git a/lynglib/src/commonTest/kotlin/ScriptTest.kt b/lynglib/src/commonTest/kotlin/ScriptTest.kt index 9523945..60bd8b1 100644 --- a/lynglib/src/commonTest/kotlin/ScriptTest.kt +++ b/lynglib/src/commonTest/kotlin/ScriptTest.kt @@ -4311,6 +4311,28 @@ class ScriptTest { """.trimIndent()) } + @Test + fun testCustomToStringBug() = runTest { + eval(""" + class A(x,y) + class B(x,y) { + fun toString() { + "B(%d,%d)"(x,y) + } + } + + assertEquals("B(1,2)", B(1,2).toString()) + assertEquals("A(x=1,y=2)", A(1,2).toString()) + + // now tricky part: this _should_ cakk custom toString() + assertEquals(":B(1,2)", ":" + B(1,2).toString()) + // and this must be exactly same: + assertEquals(":B(1,2)", ":" + B(1,2)) + + """.trimIndent()) + + } + // @Test // fun testSplatAssignemnt() = runTest {