class val and var in body

This commit is contained in:
Sergey Chernov 2025-06-09 23:55:06 +04:00
parent 56e0d2fd63
commit 961228ca0b
5 changed files with 69 additions and 8 deletions

View File

@ -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
}

View File

@ -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 <reified T : Obj> thisAs(): T = (thisObj as? T)
?: raiseClassCastError("Cannot cast ${thisObj.objClass.className} to ${T::class.simpleName}")
private val objects = mutableMapOf<String, ObjRecord>()
internal val objects = mutableMapOf<String, ObjRecord>()
operator fun get(name: String): ObjRecord? =
objects[name]

View File

@ -179,21 +179,21 @@ open class Obj {
suspend fun <T> 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")

View File

@ -153,5 +153,23 @@ val ObjArray by lazy {
class ObjInstance(override val objClass: ObjClass) : Obj() {
internal val publicFields = mutableSetOf<String>()
internal val protectedFields = mutableSetOf<String>()
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)
}
}

View File

@ -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())
}
}