fix #94 overridden toString() now is called correctly in known cases, default implementation is still generated for ObjInstances and some other classes
This commit is contained in:
parent
b7838b45ec
commit
3acd56f55a
@ -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
|
||||
|
||||
@ -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")
|
||||
|
||||
@ -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 {
|
||||
|
||||
@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -198,7 +198,7 @@ class ObjList(val list: MutableList<Obj> = 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
|
||||
|
||||
@ -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<Obj, Obj> = 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
|
||||
|
||||
@ -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('<')
|
||||
|
||||
@ -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)})")
|
||||
}
|
||||
|
||||
|
||||
@ -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 {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user