class val and var in body
This commit is contained in:
parent
56e0d2fd63
commit
961228ca0b
@ -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
|
||||
}
|
||||
|
@ -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]
|
||||
|
@ -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")
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
@ -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())
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user