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
|
var extraInit: Statement? = null
|
||||||
val bodyInit: Statement? = if (t.type == Token.Type.LBRACE) {
|
val bodyInit: Statement? = if (t.type == Token.Type.LBRACE) {
|
||||||
// parse body
|
// parse body
|
||||||
TODO("parse body")
|
parseScript(t.pos, cc).also {
|
||||||
|
cc.skipTokens(Token.Type.RBRACE)
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
cc.previous()
|
cc.previous()
|
||||||
null
|
null
|
||||||
@ -744,6 +746,20 @@ class Compiler(
|
|||||||
// note that accessors are created in ObjClass instance, not during instance
|
// note that accessors are created in ObjClass instance, not during instance
|
||||||
// initialization (not here)
|
// 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
|
thisObj
|
||||||
}
|
}
|
||||||
|
@ -27,6 +27,8 @@ class Context(
|
|||||||
|
|
||||||
fun raiseClassCastError(msg: String): Nothing = raiseError(ObjClassCastError(this, msg))
|
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 {
|
fun raiseError(message: String): Nothing {
|
||||||
throw ExecutionError(ObjError(this, message))
|
throw ExecutionError(ObjError(this, message))
|
||||||
}
|
}
|
||||||
@ -56,7 +58,7 @@ class Context(
|
|||||||
inline fun <reified T : Obj> thisAs(): T = (thisObj as? T)
|
inline fun <reified T : Obj> thisAs(): T = (thisObj as? T)
|
||||||
?: raiseClassCastError("Cannot cast ${thisObj.objClass.className} to ${T::class.simpleName}")
|
?: 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? =
|
operator fun get(name: String): ObjRecord? =
|
||||||
objects[name]
|
objects[name]
|
||||||
|
@ -179,21 +179,21 @@ open class Obj {
|
|||||||
|
|
||||||
suspend fun <T> sync(block: () -> T): T = monitor.withLock { block() }
|
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:
|
// could be property or class field:
|
||||||
val obj = objClass.getInstanceMemberOrNull(name)
|
val obj = objClass.getInstanceMemberOrNull(name) ?: context.raiseError("no such field: $name")
|
||||||
val value = obj?.value
|
val value = obj.value
|
||||||
return when (value) {
|
return when (value) {
|
||||||
is Statement -> {
|
is Statement -> {
|
||||||
ObjRecord(value.execute(context.copy(context.pos, newThisObj = this)), obj.isMutable)
|
ObjRecord(value.execute(context.copy(context.pos, newThisObj = this)), obj.isMutable)
|
||||||
}
|
}
|
||||||
// could be writable property naturally
|
// could be writable property naturally
|
||||||
null -> ObjNull.asReadonly
|
// null -> ObjNull.asReadonly
|
||||||
else -> obj
|
else -> obj
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun writeField(context: Context, name: String, newValue: Obj) {
|
open suspend fun writeField(context: Context, name: String, newValue: Obj) {
|
||||||
willMutate(context)
|
willMutate(context)
|
||||||
val field = objClass.getInstanceMemberOrNull(name) ?: context.raiseError("no such field: $name")
|
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")
|
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() {
|
open class ObjError(val context: Context, val message: String) : Obj() {
|
||||||
override val asStr: ObjString by lazy { ObjString("Error: $message") }
|
override val asStr: ObjString by lazy { ObjString("Error: $message") }
|
||||||
|
|
||||||
|
fun raise(): Nothing {
|
||||||
|
throw ExecutionError(this)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class ObjNullPointerError(context: Context) : ObjError(context, "object is null")
|
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 ObjClassCastError(context: Context, message: String) : ObjError(context, message)
|
||||||
class ObjIndexOutOfBoundsError(context: Context, message: String = "index out of bounds") : 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 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")
|
class ObjIterationFinishedError(context: Context) : ObjError(context, "iteration finished")
|
@ -153,5 +153,23 @@ val ObjArray by lazy {
|
|||||||
|
|
||||||
class ObjInstance(override val objClass: ObjClass) : Obj() {
|
class ObjInstance(override val objClass: ObjClass) : Obj() {
|
||||||
|
|
||||||
|
internal val publicFields = mutableSetOf<String>()
|
||||||
|
internal val protectedFields = mutableSetOf<String>()
|
||||||
|
|
||||||
internal lateinit var instanceContext: Context
|
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 )
|
assertEquals( 0, p.x )
|
||||||
""".trimIndent())
|
""".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