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