added "dynamic" fields (get/set/call fields by name using dynamic standard function

This commit is contained in:
sergeych committed 2025-08-12 00:15:45 +03:00
1 parent e916d9805a
commit 6d8eed7b8c
5 files changed
+170 -13

No files matched your search

@@ -170,6 +170,11 @@ class Script(
}
result ?: raiseError(ObjAssertionFailedException(this,"Expected exception but nothing was thrown"))
}
addFn("dynamic") {
ObjDynamic.create(this, requireOnlyArg())
}
addFn("require") {
val condition = requiredArg<ObjBool>(0)
if( !condition.value ) {
@@ -0,0 +1,65 @@
package net.sergeych.lyng.obj
import net.sergeych.lyng.Arguments
import net.sergeych.lyng.Scope
import net.sergeych.lyng.Statement
class ObjDynamicContext(val delegate: ObjDynamic) : Obj() {
override val objClass: ObjClass = type
companion object {
val type = ObjClass("DelegateContext").apply {
addFn("get") {
val d = thisAs<ObjDynamicContext>().delegate
if (d.readCallback != null)
raiseIllegalState("get already defined")
d.readCallback = requireOnlyArg()
ObjVoid
}
addFn("set") {
val d = thisAs<ObjDynamicContext>().delegate
if (d.writeCallback != null)
raiseIllegalState("set already defined")
d.writeCallback = requireOnlyArg()
ObjVoid
}
}
}
}
class ObjDynamic : Obj() {
internal var readCallback: Statement? = null
internal var writeCallback: Statement? = null
override suspend fun readField(scope: Scope, name: String): ObjRecord {
return readCallback?.execute(scope.copy(Arguments(ObjString(name))))?.let {
if (writeCallback != null)
it.asMutable
else
it.asReadonly
}
?: super.readField(scope, name)
}
override suspend fun writeField(scope: Scope, name: String, newValue: Obj) {
writeCallback?.execute(scope.copy(Arguments(ObjString(name), newValue)))
?: super.writeField(scope, name, newValue)
}
companion object {
suspend fun create(scope: Scope, builder: Statement): ObjDynamic {
val delegate = ObjDynamic()
val context = ObjDynamicContext(delegate)
builder.execute(scope.copy(newThisObj = context))
return delegate
}
val type = object : ObjClass("Delegate") {}
}
}
+40 -11
View File
@@ -44,20 +44,49 @@ class OOTest {
""".trimIndent())
}
// @Test
fun testDynamic() = runTest {
@Test
fun testDynamicGet() = runTest {
eval("""
println("0")
class DynamicTest : Dynamic {
fun getDynamic(name) {
if (name == "foo") "bar" else null
val accessor = dynamic {
get { name ->
if( name == "foo" ) "bar" else null
}
}
println("1")
val d = DynamicTest()
println(d)
println("2")
println("-- " + accessor.foo)
assertEquals("bar", accessor.foo)
assertEquals(null, accessor.bar)
""".trimIndent())
}
@Test
fun testDelegateSet() = runTest {
eval("""
var setValueForBar = null
val accessor = dynamic {
get { name ->
when(name) {
"foo" -> "bar"
"bar" -> setValueForBar
else -> null
}
}
set { name, value ->
if( name == "bar" )
setValueForBar = value
else throw IllegalAssignmentException("Can't assign "+name)
}
}
assertEquals("bar", accessor.foo)
assertEquals(null, accessor.bar)
accessor.bar = "buzz"
assertEquals("buzz", accessor.bar)
assertThrows {
accessor.bad = "!23"
}
""".trimIndent())
}
}