indexer fix

This commit is contained in:
Sergey Chernov 2026-03-14 20:04:44 +03:00
parent 8a32ffe655
commit c54d947f1c
2 changed files with 42 additions and 1 deletions

View File

@ -646,6 +646,9 @@ open class Obj {
} }
open suspend fun getAt(scope: Scope, index: Obj): Obj { open suspend fun getAt(scope: Scope, index: Obj): Obj {
if (hasNonRootIndexerMember("getAt")) {
return invokeInstanceMethod(scope, "getAt", Arguments(index))
}
if (index is ObjString) { if (index is ObjString) {
return readField(scope, index.value).value 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())) suspend fun getAt(scope: Scope, index: Int): Obj = getAt(scope, ObjInt(index.toLong()))
open suspend fun putAt(scope: Scope, index: Obj, newValue: Obj) { 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) { if (index is ObjString) {
writeField(scope, index.value, newValue) writeField(scope, index.value, newValue)
return return
@ -662,6 +675,17 @@ open class Obj {
scope.raiseNotImplemented("indexing") 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 { open suspend fun callOn(scope: Scope): Obj {
scope.raiseNotImplemented() scope.raiseNotImplemented()
} }

View File

@ -20,7 +20,6 @@ import net.sergeych.lyng.Script
import net.sergeych.lyng.ScriptError import net.sergeych.lyng.ScriptError
import net.sergeych.lyng.eval import net.sergeych.lyng.eval
import kotlin.test.Test import kotlin.test.Test
import kotlin.test.assertEquals
import kotlin.test.assertFailsWith import kotlin.test.assertFailsWith
import kotlin.test.assertTrue import kotlin.test.assertTrue
@ -536,6 +535,24 @@ class TypesTest {
""".trimIndent()) """.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 { // @Test fun nonTrivialOperatorsTest() = runTest {
// val s = Script.newScope() // val s = Script.newScope()
// s.eval(""" // s.eval("""