From c54d947f1c3d134c749bbfc9db95c35a1891872a Mon Sep 17 00:00:00 2001 From: sergeych Date: Sat, 14 Mar 2026 20:04:44 +0300 Subject: [PATCH] indexer fix --- .../kotlin/net/sergeych/lyng/obj/Obj.kt | 24 +++++++++++++++++++ lynglib/src/commonTest/kotlin/TypesTest.kt | 19 ++++++++++++++- 2 files changed, 42 insertions(+), 1 deletion(-) 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 4b83204..2c4c4e5 100644 --- a/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/Obj.kt +++ b/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/Obj.kt @@ -646,6 +646,9 @@ open class Obj { } open suspend fun getAt(scope: Scope, index: Obj): Obj { + if (hasNonRootIndexerMember("getAt")) { + return invokeInstanceMethod(scope, "getAt", Arguments(index)) + } if (index is ObjString) { return readField(scope, index.value).value } @@ -655,6 +658,16 @@ open class Obj { suspend fun getAt(scope: Scope, index: Int): Obj = getAt(scope, ObjInt(index.toLong())) open suspend fun putAt(scope: Scope, index: Obj, newValue: Obj) { + when { + hasNonRootIndexerMember("putAt") -> { + invokeInstanceMethod(scope, "putAt", Arguments(index, newValue)) + return + } + hasNonRootIndexerMember("setAt") -> { + invokeInstanceMethod(scope, "setAt", Arguments(index, newValue)) + return + } + } if (index is ObjString) { writeField(scope, index.value, newValue) return @@ -662,6 +675,17 @@ open class Obj { scope.raiseNotImplemented("indexing") } + private fun hasNonRootIndexerMember(name: String): Boolean { + for (cls in objClass.mro) { + if (cls.className == "Obj") break + val rec = cls.members[name] ?: cls.classScope?.objects?.get(name) + if (rec != null && !rec.isAbstract && rec.type != ObjRecord.Type.Delegated) { + return true + } + } + return false + } + open suspend fun callOn(scope: Scope): Obj { scope.raiseNotImplemented() } diff --git a/lynglib/src/commonTest/kotlin/TypesTest.kt b/lynglib/src/commonTest/kotlin/TypesTest.kt index c685f5f..b244ef5 100644 --- a/lynglib/src/commonTest/kotlin/TypesTest.kt +++ b/lynglib/src/commonTest/kotlin/TypesTest.kt @@ -20,7 +20,6 @@ import net.sergeych.lyng.Script import net.sergeych.lyng.ScriptError import net.sergeych.lyng.eval import kotlin.test.Test -import kotlin.test.assertEquals import kotlin.test.assertFailsWith import kotlin.test.assertTrue @@ -536,6 +535,24 @@ class TypesTest { """.trimIndent()) } + @Test fun testIndexer() = runTest { + eval(""" + class Greeter { + override fun getAt(name) = "Hello, %s!"(name) + } + assertEquals("Hello, Bob!",Greeter()["Bob"]) + val g = Greeter() + assertEquals("Hello, Bob!",g["Bob"]) + + // it should work with objects too: + object Polite { + override fun getAt(name) = "How do you do, %s?"(name) + } + + assertEquals("How do you do, Bob?",Polite["Bob"]) + + """.trimIndent()) + } // @Test fun nonTrivialOperatorsTest() = runTest { // val s = Script.newScope() // s.eval("""