From 961228ca0b5557acefdaee9c6da7fb68558c4955 Mon Sep 17 00:00:00 2001 From: sergeych Date: Mon, 9 Jun 2025 23:55:06 +0400 Subject: [PATCH] class val and var in body --- .../kotlin/net/sergeych/lyng/Compiler.kt | 18 ++++++++++++++++- .../kotlin/net/sergeych/lyng/Context.kt | 4 +++- .../kotlin/net/sergeych/lyng/Obj.kt | 17 ++++++++++------ .../kotlin/net/sergeych/lyng/ObjClass.kt | 18 +++++++++++++++++ library/src/commonTest/kotlin/ScriptTest.kt | 20 +++++++++++++++++++ 5 files changed, 69 insertions(+), 8 deletions(-) diff --git a/library/src/commonMain/kotlin/net/sergeych/lyng/Compiler.kt b/library/src/commonMain/kotlin/net/sergeych/lyng/Compiler.kt index 34ac778..163987d 100644 --- a/library/src/commonMain/kotlin/net/sergeych/lyng/Compiler.kt +++ b/library/src/commonMain/kotlin/net/sergeych/lyng/Compiler.kt @@ -716,7 +716,9 @@ class Compiler( var extraInit: Statement? = null val bodyInit: Statement? = if (t.type == Token.Type.LBRACE) { // parse body - TODO("parse body") + parseScript(t.pos, cc).also { + cc.skipTokens(Token.Type.RBRACE) + } } else { cc.previous() null @@ -744,6 +746,20 @@ class Compiler( // note that accessors are created in ObjClass instance, not during instance // initialization (not here) } + bodyInit?.execute(this) + // export public + for( (name,record) in objects ) { + when(record.visibility) { + Visibility.Public -> { + thisObj.publicFields += name + thisObj.protectedFields += name + } + Visibility.Protected -> + thisObj.protectedFields += name + else -> { + } + } + } thisObj } diff --git a/library/src/commonMain/kotlin/net/sergeych/lyng/Context.kt b/library/src/commonMain/kotlin/net/sergeych/lyng/Context.kt index e0744f8..efdd2de 100644 --- a/library/src/commonMain/kotlin/net/sergeych/lyng/Context.kt +++ b/library/src/commonMain/kotlin/net/sergeych/lyng/Context.kt @@ -27,6 +27,8 @@ class Context( fun raiseClassCastError(msg: String): Nothing = raiseError(ObjClassCastError(this, msg)) + fun raiseSymbolNotFound(name: String): Nothing = raiseError(ObjSymbolNotDefinedError(this, "symbol is not defined: $name")) + fun raiseError(message: String): Nothing { throw ExecutionError(ObjError(this, message)) } @@ -56,7 +58,7 @@ class Context( inline fun thisAs(): T = (thisObj as? T) ?: raiseClassCastError("Cannot cast ${thisObj.objClass.className} to ${T::class.simpleName}") - private val objects = mutableMapOf() + internal val objects = mutableMapOf() operator fun get(name: String): ObjRecord? = objects[name] diff --git a/library/src/commonMain/kotlin/net/sergeych/lyng/Obj.kt b/library/src/commonMain/kotlin/net/sergeych/lyng/Obj.kt index b65328f..08a3851 100644 --- a/library/src/commonMain/kotlin/net/sergeych/lyng/Obj.kt +++ b/library/src/commonMain/kotlin/net/sergeych/lyng/Obj.kt @@ -179,21 +179,21 @@ open class Obj { suspend fun sync(block: () -> T): T = monitor.withLock { block() } - suspend fun readField(context: Context, name: String): ObjRecord { + suspend open fun readField(context: Context, name: String): ObjRecord { // could be property or class field: - val obj = objClass.getInstanceMemberOrNull(name) - val value = obj?.value + val obj = objClass.getInstanceMemberOrNull(name) ?: context.raiseError("no such field: $name") + val value = obj.value return when (value) { is Statement -> { ObjRecord(value.execute(context.copy(context.pos, newThisObj = this)), obj.isMutable) } // could be writable property naturally - null -> ObjNull.asReadonly +// null -> ObjNull.asReadonly else -> obj } } - fun writeField(context: Context, name: String, newValue: Obj) { + open suspend fun writeField(context: Context, name: String, newValue: Obj) { willMutate(context) val field = objClass.getInstanceMemberOrNull(name) ?: context.raiseError("no such field: $name") if (field.isMutable) field.value = newValue else context.raiseError("can't assign to read-only field: $name") @@ -327,6 +327,10 @@ data class ObjNamespace(val name: String) : Obj() { open class ObjError(val context: Context, val message: String) : Obj() { override val asStr: ObjString by lazy { ObjString("Error: $message") } + + fun raise(): Nothing { + throw ExecutionError(this) + } } class ObjNullPointerError(context: Context) : ObjError(context, "object is null") @@ -335,5 +339,6 @@ class ObjAssertionError(context: Context, message: String) : ObjError(context, m class ObjClassCastError(context: Context, message: String) : ObjError(context, message) class ObjIndexOutOfBoundsError(context: Context, message: String = "index out of bounds") : ObjError(context, message) class ObjIllegalArgumentError(context: Context, message: String = "illegal argument") : ObjError(context, message) - +class ObjIllegalAssignmentError(context: Context, message: String = "illegal assignment") : ObjError(context, message) +class ObjSymbolNotDefinedError(context: Context, message: String = "symbol is not defined") : ObjError(context, message) class ObjIterationFinishedError(context: Context) : ObjError(context, "iteration finished") \ No newline at end of file diff --git a/library/src/commonMain/kotlin/net/sergeych/lyng/ObjClass.kt b/library/src/commonMain/kotlin/net/sergeych/lyng/ObjClass.kt index 11998e3..311c172 100644 --- a/library/src/commonMain/kotlin/net/sergeych/lyng/ObjClass.kt +++ b/library/src/commonMain/kotlin/net/sergeych/lyng/ObjClass.kt @@ -153,5 +153,23 @@ val ObjArray by lazy { class ObjInstance(override val objClass: ObjClass) : Obj() { + internal val publicFields = mutableSetOf() + internal val protectedFields = mutableSetOf() + internal lateinit var instanceContext: Context + + override suspend fun readField(context: Context, name: String): ObjRecord { + return if( name in publicFields ) instanceContext[name]!! + else super.readField(context, name) + } + + override suspend fun writeField(context: Context, name: String, newValue: Obj) { + if( name in publicFields ) { + val f = instanceContext[name]!! + if( !f.isMutable ) ObjIllegalAssignmentError(context, "can't reassign val $name").raise() + if( f.value.assign(context, newValue) == null) + f.value = newValue + } + else super.writeField(context, name, newValue) + } } diff --git a/library/src/commonTest/kotlin/ScriptTest.kt b/library/src/commonTest/kotlin/ScriptTest.kt index 12b1bc1..24ca0d8 100644 --- a/library/src/commonTest/kotlin/ScriptTest.kt +++ b/library/src/commonTest/kotlin/ScriptTest.kt @@ -1415,4 +1415,24 @@ class ScriptTest { assertEquals( 0, p.x ) """.trimIndent()) } + + @Test + fun testStructBodyVal() = runTest { + val c = Context() + c.eval(""" + struct Point(x,y) { + val length = sqrt(x*x+y*y) + var foo = "zero" + } + val p = Point(3,4) + assertEquals(5, p.length) + assertEquals("zero", p.foo) + p.y = 10 + p.foo = "bar" + assert( p.y == 10 ) + assert( p.foo == "bar") + // length is a val, is shoud not change + assert( p.length == 5 ) + """.trimIndent()) + } } \ No newline at end of file