optimizing refactoring: no more StoredObj.kt, WithAccess now always deals with Obj and is renamed to ObjRecord
This commit is contained in:
		
							parent
							
								
									33fdb0934a
								
							
						
					
					
						commit
						56e0d2fd63
					
				@ -132,7 +132,7 @@ class Compiler(
 | 
			
		||||
                                operand = Accessor { context ->
 | 
			
		||||
                                    context.pos = next.pos
 | 
			
		||||
                                    val v = left.getter(context).value
 | 
			
		||||
                                    WithAccess(
 | 
			
		||||
                                    ObjRecord(
 | 
			
		||||
                                        v.invokeInstanceMethod(
 | 
			
		||||
                                            context,
 | 
			
		||||
                                            next.value,
 | 
			
		||||
@ -641,7 +641,7 @@ class Compiler(
 | 
			
		||||
                    else -> {
 | 
			
		||||
                        Accessor({
 | 
			
		||||
                            it.pos = t.pos
 | 
			
		||||
                            it.get(t.value)?.asAccess
 | 
			
		||||
                            it.get(t.value)
 | 
			
		||||
                                ?: it.raiseError("symbol not defined: '${t.value}'")
 | 
			
		||||
                        }) { ctx, newValue ->
 | 
			
		||||
                            ctx.get(t.value)?.let { stored ->
 | 
			
		||||
@ -886,7 +886,7 @@ class Compiler(
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private suspend fun loopIntRange(
 | 
			
		||||
        forContext: Context, start: Int, end: Int, loopVar: StoredObj,
 | 
			
		||||
        forContext: Context, start: Int, end: Int, loopVar: ObjRecord,
 | 
			
		||||
        body: Statement, elseStatement: Statement?, label: String?, catchBreak: Boolean
 | 
			
		||||
    ): Obj {
 | 
			
		||||
        var result: Obj = ObjVoid
 | 
			
		||||
@ -914,7 +914,7 @@ class Compiler(
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private suspend fun loopIterable(
 | 
			
		||||
        forContext: Context, sourceObj: Obj, loopVar: StoredObj,
 | 
			
		||||
        forContext: Context, sourceObj: Obj, loopVar: ObjRecord,
 | 
			
		||||
        body: Statement, elseStatement: Statement?, label: String?,
 | 
			
		||||
        catchBreak: Boolean
 | 
			
		||||
    ): Obj {
 | 
			
		||||
 | 
			
		||||
@ -35,47 +35,47 @@ class Context(
 | 
			
		||||
        throw ExecutionError(obj)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    inline fun <reified T: Obj>requiredArg(index: Int): T {
 | 
			
		||||
        if( args.list.size <= index ) raiseError("Expected at least ${index+1} argument, got ${args.list.size}")
 | 
			
		||||
    inline fun <reified T : Obj> requiredArg(index: Int): T {
 | 
			
		||||
        if (args.list.size <= index) raiseError("Expected at least ${index + 1} argument, got ${args.list.size}")
 | 
			
		||||
        return (args.list[index].value as? T)
 | 
			
		||||
            ?: raiseClassCastError("Expected type ${T::class.simpleName}, got ${args.list[index].value::class.simpleName}")
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    inline fun <reified T: Obj>requireOnlyArg(): T {
 | 
			
		||||
        if( args.list.size != 1 ) raiseError("Expected exactly 1 argument, got ${args.list.size}")
 | 
			
		||||
    inline fun <reified T : Obj> requireOnlyArg(): T {
 | 
			
		||||
        if (args.list.size != 1) raiseError("Expected exactly 1 argument, got ${args.list.size}")
 | 
			
		||||
        return requiredArg(0)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Suppress("unused")
 | 
			
		||||
    fun requireExactCount(count: Int) {
 | 
			
		||||
        if( args.list.size != count ) {
 | 
			
		||||
        if (args.list.size != count) {
 | 
			
		||||
            raiseError("Expected exactly $count arguments, got ${args.list.size}")
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    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}")
 | 
			
		||||
 | 
			
		||||
    private val objects = mutableMapOf<String, StoredObj>()
 | 
			
		||||
    private val objects = mutableMapOf<String, ObjRecord>()
 | 
			
		||||
 | 
			
		||||
    operator fun get(name: String): StoredObj? =
 | 
			
		||||
    operator fun get(name: String): ObjRecord? =
 | 
			
		||||
        objects[name]
 | 
			
		||||
            ?: parent?.get(name)
 | 
			
		||||
 | 
			
		||||
    fun copy(pos: Pos, args: Arguments = Arguments.EMPTY,newThisObj: Obj? = null): Context =
 | 
			
		||||
    fun copy(pos: Pos, args: Arguments = Arguments.EMPTY, newThisObj: Obj? = null): Context =
 | 
			
		||||
        Context(this, args, pos, newThisObj ?: thisObj)
 | 
			
		||||
 | 
			
		||||
    fun copy(args: Arguments = Arguments.EMPTY,newThisObj: Obj? = null): Context =
 | 
			
		||||
    fun copy(args: Arguments = Arguments.EMPTY, newThisObj: Obj? = null): Context =
 | 
			
		||||
        Context(this, args, pos, newThisObj ?: thisObj)
 | 
			
		||||
 | 
			
		||||
    fun copy() = Context(this, args, pos, thisObj)
 | 
			
		||||
 | 
			
		||||
    fun addItem(name: String, isMutable: Boolean, value: Obj?): StoredObj {
 | 
			
		||||
        return StoredObj(value, isMutable).also { objects.put(name, it) }
 | 
			
		||||
    fun addItem(name: String, isMutable: Boolean, value: Obj): ObjRecord {
 | 
			
		||||
        return ObjRecord(value, isMutable).also { objects.put(name, it) }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fun getOrCreateNamespace(name: String): ObjClass {
 | 
			
		||||
        val ns = objects.getOrPut(name) { StoredObj(ObjNamespace(name), isMutable = false) }.value
 | 
			
		||||
        val ns = objects.getOrPut(name) { ObjRecord(ObjNamespace(name), isMutable = false) }.value
 | 
			
		||||
        return ns!!.objClass
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@ -86,7 +86,7 @@ class Context(
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    inline fun <reified T: Obj> addFn(vararg names: String, crossinline fn: suspend Context.() -> T) {
 | 
			
		||||
    inline fun <reified T : Obj> addFn(vararg names: String, crossinline fn: suspend Context.() -> T) {
 | 
			
		||||
        val newFn = object : Statement() {
 | 
			
		||||
            override val pos: Pos = Pos.builtIn
 | 
			
		||||
 | 
			
		||||
@ -102,7 +102,7 @@ class Context(
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fun addConst(name: String,value: Obj) = addItem(name, false, value)
 | 
			
		||||
    fun addConst(name: String, value: Obj) = addItem(name, false, value)
 | 
			
		||||
 | 
			
		||||
    suspend fun eval(code: String): Obj =
 | 
			
		||||
        Compiler().compile(code.toSource()).execute(this)
 | 
			
		||||
 | 
			
		||||
@ -6,20 +6,35 @@ import kotlinx.serialization.SerialName
 | 
			
		||||
import kotlinx.serialization.Serializable
 | 
			
		||||
import net.sergeych.synctools.ProtectedOp
 | 
			
		||||
 | 
			
		||||
//typealias InstanceMethod = (Context, Obj) -> Obj
 | 
			
		||||
 | 
			
		||||
data class WithAccess<T>(
 | 
			
		||||
    var value: T,
 | 
			
		||||
/**
 | 
			
		||||
 * Record to store object with access rules, e.g. [isMutable] and access level [visibility].
 | 
			
		||||
 */
 | 
			
		||||
data class ObjRecord(
 | 
			
		||||
    var value: Obj,
 | 
			
		||||
    val isMutable: Boolean,
 | 
			
		||||
    val visibility: Compiler.Visibility = Compiler.Visibility.Public
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * When we need read-write access to an object in some abstract storage, we need Accessor,
 | 
			
		||||
 * as in-site assigning is not always sufficient, in general case we need to replace the object
 | 
			
		||||
 * in the storage.
 | 
			
		||||
 *
 | 
			
		||||
 * Note that assigning new value is more complex than just replacing the object, see how assignment
 | 
			
		||||
 * operator is implemented in [Compiler.allOps].
 | 
			
		||||
 */
 | 
			
		||||
data class Accessor(
 | 
			
		||||
    val getter: suspend (Context) -> WithAccess<Obj>,
 | 
			
		||||
    val getter: suspend (Context) -> ObjRecord,
 | 
			
		||||
    val setterOrNull: (suspend (Context, Obj) -> Unit)?
 | 
			
		||||
) {
 | 
			
		||||
    constructor(getter: suspend (Context) -> WithAccess<Obj>) : this(getter, null)
 | 
			
		||||
    /**
 | 
			
		||||
     * Simplified constructor for immutable stores.
 | 
			
		||||
     */
 | 
			
		||||
    constructor(getter: suspend (Context) -> ObjRecord) : this(getter, null)
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Get the setter or throw.
 | 
			
		||||
     */
 | 
			
		||||
    fun setter(pos: Pos) = setterOrNull ?: throw ScriptError(pos, "can't assign value")
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -164,13 +179,13 @@ open class Obj {
 | 
			
		||||
 | 
			
		||||
    suspend fun <T> sync(block: () -> T): T = monitor.withLock { block() }
 | 
			
		||||
 | 
			
		||||
    suspend fun readField(context: Context, name: String): WithAccess<Obj> {
 | 
			
		||||
    suspend fun readField(context: Context, name: String): ObjRecord {
 | 
			
		||||
        // could be property or class field:
 | 
			
		||||
        val obj = objClass.getInstanceMemberOrNull(name)
 | 
			
		||||
        val value = obj?.value
 | 
			
		||||
        return when (value) {
 | 
			
		||||
            is Statement -> {
 | 
			
		||||
                WithAccess(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
 | 
			
		||||
            null -> ObjNull.asReadonly
 | 
			
		||||
@ -221,8 +236,8 @@ open class Obj {
 | 
			
		||||
        callOn(context.copy(atPos, args = args, newThisObj = thisObj))
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    val asReadonly: WithAccess<Obj> by lazy { WithAccess(this, false) }
 | 
			
		||||
    val asMutable: WithAccess<Obj> by lazy { WithAccess(this, true) }
 | 
			
		||||
    val asReadonly: ObjRecord by lazy { ObjRecord(this, false) }
 | 
			
		||||
    val asMutable: ObjRecord by lazy { ObjRecord(this, true) }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    companion object {
 | 
			
		||||
 | 
			
		||||
@ -16,7 +16,7 @@ class ObjClass(
 | 
			
		||||
    override val objClass: ObjClass by lazy { ObjClassType }
 | 
			
		||||
 | 
			
		||||
    // members: fields most often
 | 
			
		||||
    private val members = mutableMapOf<String, WithAccess<Obj>>()
 | 
			
		||||
    private val members = mutableMapOf<String, ObjRecord>()
 | 
			
		||||
 | 
			
		||||
    override fun toString(): String = className
 | 
			
		||||
 | 
			
		||||
@ -46,7 +46,7 @@ class ObjClass(
 | 
			
		||||
    ) {
 | 
			
		||||
        if (name in members || allParentsSet.any { name in it.members } == true)
 | 
			
		||||
            throw ScriptError(pos, "$name is already defined in $objClass or one of its supertypes")
 | 
			
		||||
        members[name] = WithAccess(initialValue, isMutable)
 | 
			
		||||
        members[name] = ObjRecord(initialValue, isMutable)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fun addFn(name: String, isOpen: Boolean = false, code: suspend Context.() -> Obj) {
 | 
			
		||||
@ -59,13 +59,13 @@ class ObjClass(
 | 
			
		||||
    /**
 | 
			
		||||
     * Get instance member traversing the hierarchy if needed. Its meaning is different for different objects.
 | 
			
		||||
     */
 | 
			
		||||
    fun getInstanceMemberOrNull(name: String): WithAccess<Obj>? {
 | 
			
		||||
    fun getInstanceMemberOrNull(name: String): ObjRecord? {
 | 
			
		||||
        members[name]?.let { return it }
 | 
			
		||||
        allParentsSet.forEach { parent -> parent.getInstanceMemberOrNull(name)?.let { return it } }
 | 
			
		||||
        return null
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fun getInstanceMember(atPos: Pos, name: String): WithAccess<Obj> =
 | 
			
		||||
    fun getInstanceMember(atPos: Pos, name: String): ObjRecord =
 | 
			
		||||
        getInstanceMemberOrNull(name)
 | 
			
		||||
            ?: throw ScriptError(atPos, "symbol doesn't exist: $name")
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -1,11 +0,0 @@
 | 
			
		||||
package net.sergeych.lyng
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Whatever [Obj] stored somewhere
 | 
			
		||||
 */
 | 
			
		||||
data class StoredObj(
 | 
			
		||||
    var value: Obj?,
 | 
			
		||||
    val isMutable: Boolean = false
 | 
			
		||||
) {
 | 
			
		||||
    val asAccess: WithAccess<Obj>? get() = value?.let { WithAccess(it, isMutable) }
 | 
			
		||||
}
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user