ObjInstance / ObjClass optimization no more list of accessible fields!
This commit is contained in:
		
							parent
							
								
									88b355c40d
								
							
						
					
					
						commit
						d482401b15
					
				@ -158,7 +158,7 @@ For example, for our class Point:
 | 
			
		||||
    assert( Point(1,2) < Point(2,2) )
 | 
			
		||||
    assert( Point(1,2) < Point(1,3) )
 | 
			
		||||
    Point(1,1+1)
 | 
			
		||||
    >>> Point(1, 2)
 | 
			
		||||
    >>> Point(x=1,y=2)
 | 
			
		||||
 | 
			
		||||
# Theory
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -39,22 +39,5 @@ We can just put the code into the module code:
 | 
			
		||||
 | 
			
		||||
## class initialization
 | 
			
		||||
 | 
			
		||||
    class foo {
 | 
			
		||||
        
 | 
			
		||||
        private static var instanceCounter = 0
 | 
			
		||||
        
 | 
			
		||||
        val instanceId = instanceCounter
 | 
			
		||||
        
 | 
			
		||||
        fun close() {
 | 
			
		||||
            instanceCounter--
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // instance initializatino could be as this:
 | 
			
		||||
        if( instanceId > 100 )
 | 
			
		||||
            throw Exception("Too many instances")
 | 
			
		||||
 | 
			
		||||
        static {
 | 
			
		||||
            // static, one-per-class initializer could be posted here
 | 
			
		||||
            instanceCounter = 1
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
already done using `ObjInstance` class and instance-bound context with local
 | 
			
		||||
context stored in ObjInstance and class constructor statement in ObjClass.
 | 
			
		||||
@ -5,7 +5,7 @@ import org.jetbrains.kotlin.gradle.ExperimentalWasmDsl
 | 
			
		||||
import org.jetbrains.kotlin.gradle.dsl.JvmTarget
 | 
			
		||||
 | 
			
		||||
group = "net.sergeych"
 | 
			
		||||
version = "0.2.1-SNAPSHOT"
 | 
			
		||||
version = "0.3.0-SNAPSHOT"
 | 
			
		||||
 | 
			
		||||
buildscript {
 | 
			
		||||
    repositories {
 | 
			
		||||
 | 
			
		||||
@ -0,0 +1,8 @@
 | 
			
		||||
package net.sergeych.lyng
 | 
			
		||||
 | 
			
		||||
enum class AccessType(val isMutable: Boolean) {
 | 
			
		||||
    Val(false), Var(true),
 | 
			
		||||
 | 
			
		||||
    @Suppress("unused")
 | 
			
		||||
    Initialization(false)
 | 
			
		||||
}
 | 
			
		||||
@ -23,8 +23,8 @@ data class ArgsDeclaration(val params: List<Item>, val endTokenType: Token.Type)
 | 
			
		||||
    suspend fun assignToContext(
 | 
			
		||||
        context: Context,
 | 
			
		||||
        fromArgs: Arguments = context.args,
 | 
			
		||||
        defaultAccessType: Compiler.AccessType = Compiler.AccessType.Var,
 | 
			
		||||
        defaultVisibility: Compiler.Visibility = Compiler.Visibility.Public
 | 
			
		||||
        defaultAccessType: AccessType = AccessType.Var,
 | 
			
		||||
        defaultVisibility: Visibility = Visibility.Public
 | 
			
		||||
    ) {
 | 
			
		||||
        fun assign(a: Item, value: Obj) {
 | 
			
		||||
            context.addItem(a.name, (a.accessType ?: defaultAccessType).isMutable, value,
 | 
			
		||||
@ -100,7 +100,7 @@ data class ArgsDeclaration(val params: List<Item>, val endTokenType: Token.Type)
 | 
			
		||||
         * So it is a [Statement] that must be executed on __caller context__.
 | 
			
		||||
         */
 | 
			
		||||
        val defaultValue: Statement? = null,
 | 
			
		||||
        val accessType: Compiler.AccessType? = null,
 | 
			
		||||
        val visibility: Compiler.Visibility? = null,
 | 
			
		||||
        val accessType: AccessType? = null,
 | 
			
		||||
        val visibility: Visibility? = null,
 | 
			
		||||
    )
 | 
			
		||||
}
 | 
			
		||||
@ -19,11 +19,12 @@ class Compiler(
 | 
			
		||||
 | 
			
		||||
    private fun parseScript(start: Pos, cc: CompilerContext): Script {
 | 
			
		||||
        val statements = mutableListOf<Statement>()
 | 
			
		||||
//        val returnScope = cc.startReturnScope()
 | 
			
		||||
        while (parseStatement(cc, braceMeansLambda = true)?.also {
 | 
			
		||||
                statements += it
 | 
			
		||||
            } != null) {/**/
 | 
			
		||||
        }
 | 
			
		||||
        return Script(start, statements)
 | 
			
		||||
        return Script(start, statements)//returnScope.needCatch)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private fun parseStatement(cc: CompilerContext, braceMeansLambda: Boolean = false): Statement? {
 | 
			
		||||
@ -439,17 +440,6 @@ class Compiler(
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    enum class AccessType(val isMutable: Boolean) {
 | 
			
		||||
        Val(false), Var(true),
 | 
			
		||||
 | 
			
		||||
        @Suppress("unused")
 | 
			
		||||
        Initialization(false)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    enum class Visibility {
 | 
			
		||||
        Public, Private, Protected//, Internal
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Parse argument declaration, used in lambda (and later in fn too)
 | 
			
		||||
     * @return declaration or null if there is no valid list of arguments
 | 
			
		||||
@ -765,22 +755,6 @@ class Compiler(
 | 
			
		||||
            // fields. Note that 'this' is already set by class
 | 
			
		||||
            constructorArgsDeclaration?.assignToContext(this)
 | 
			
		||||
            bodyInit?.execute(this)
 | 
			
		||||
            // export public
 | 
			
		||||
            for ((name, record) in objects) {
 | 
			
		||||
                when (record.visibility) {
 | 
			
		||||
                    Visibility.Public -> {
 | 
			
		||||
                        thisObj.objClass.publicFields += name
 | 
			
		||||
                        thisObj.objClass.protectedFields += name
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    Visibility.Protected ->
 | 
			
		||||
                        thisObj.objClass.protectedFields += name
 | 
			
		||||
 | 
			
		||||
                    Visibility.Private -> {
 | 
			
		||||
                        //println("private field: $name")
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            thisObj
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@ -123,15 +123,23 @@ internal class CompilerContext(val tokens: List<Token>) {
 | 
			
		||||
    /**
 | 
			
		||||
     * Scan backwards as deep as specified looking for visibility token. Does not change position.
 | 
			
		||||
     */
 | 
			
		||||
    fun getVisibility(default: Compiler.Visibility = Compiler.Visibility.Public, depths: Int = 2): Compiler.Visibility {
 | 
			
		||||
    fun getVisibility(default: Visibility = Visibility.Public, depths: Int = 2): Visibility {
 | 
			
		||||
        for( i in -depths .. -1) {
 | 
			
		||||
            when( atOffset(i)?.type) {
 | 
			
		||||
                Token.Type.PROTECTED -> return Compiler.Visibility.Protected
 | 
			
		||||
                Token.Type.PRIVATE -> return Compiler.Visibility.Private
 | 
			
		||||
                Token.Type.PROTECTED -> return Visibility.Protected
 | 
			
		||||
                Token.Type.PRIVATE -> return Visibility.Private
 | 
			
		||||
                else -> {}
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        return default
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
//    data class ReturnScope(val needCatch: Boolean = false)
 | 
			
		||||
 | 
			
		||||
//    private val
 | 
			
		||||
 | 
			
		||||
//    fun startReturnScope(): ReturnScope {
 | 
			
		||||
//        return ReturnScope()
 | 
			
		||||
//    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@ -78,7 +78,7 @@ class Context(
 | 
			
		||||
        name: String,
 | 
			
		||||
        isMutable: Boolean,
 | 
			
		||||
        value: Obj,
 | 
			
		||||
        visibility: Compiler.Visibility = Compiler.Visibility.Public
 | 
			
		||||
        visibility: Visibility = Visibility.Public
 | 
			
		||||
    ): ObjRecord {
 | 
			
		||||
        return ObjRecord(value, isMutable, visibility).also { objects.put(name, it) }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@ -12,7 +12,7 @@ import net.sergeych.synctools.ProtectedOp
 | 
			
		||||
data class ObjRecord(
 | 
			
		||||
    var value: Obj,
 | 
			
		||||
    val isMutable: Boolean,
 | 
			
		||||
    val visibility: Compiler.Visibility = Compiler.Visibility.Public
 | 
			
		||||
    val visibility: Visibility = Visibility.Public
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
@ -341,4 +341,5 @@ class ObjIndexOutOfBoundsError(context: Context, message: String = "index out of
 | 
			
		||||
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")
 | 
			
		||||
class ObjAccessError(context: Context, message: String = "access not allowed error") : ObjError(context, message)
 | 
			
		||||
@ -7,9 +7,6 @@ class ObjClass(
 | 
			
		||||
    vararg val parents: ObjClass,
 | 
			
		||||
) : Obj() {
 | 
			
		||||
 | 
			
		||||
    internal val publicFields = mutableSetOf<String>()
 | 
			
		||||
    internal val protectedFields = mutableSetOf<String>()
 | 
			
		||||
 | 
			
		||||
    var instanceConstructor: Statement? = null
 | 
			
		||||
 | 
			
		||||
    val allParentsSet: Set<ObjClass> = parents.flatMap {
 | 
			
		||||
@ -42,10 +39,10 @@ class ObjClass(
 | 
			
		||||
        name: String,
 | 
			
		||||
        initialValue: Obj,
 | 
			
		||||
        isMutable: Boolean = false,
 | 
			
		||||
        visibility: Compiler.Visibility = Compiler.Visibility.Public,
 | 
			
		||||
        visibility: Visibility = Visibility.Public,
 | 
			
		||||
        pos: Pos = Pos.builtIn
 | 
			
		||||
    ) {
 | 
			
		||||
        if (name in members || allParentsSet.any { name in it.members } == true)
 | 
			
		||||
        if (name in members || allParentsSet.any { name in it.members })
 | 
			
		||||
            throw ScriptError(pos, "$name is already defined in $objClass or one of its supertypes")
 | 
			
		||||
        members[name] = ObjRecord(initialValue, isMutable, visibility)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@ -5,38 +5,48 @@ class ObjInstance(override val objClass: ObjClass) : Obj() {
 | 
			
		||||
    internal lateinit var instanceContext: Context
 | 
			
		||||
 | 
			
		||||
    override suspend fun readField(context: Context, name: String): ObjRecord {
 | 
			
		||||
        return if( name in objClass.publicFields ) instanceContext[name]!!
 | 
			
		||||
        else super.readField(context, name)
 | 
			
		||||
        return instanceContext[name]?.let {
 | 
			
		||||
            if (it.visibility.isPublic)
 | 
			
		||||
                it
 | 
			
		||||
            else
 | 
			
		||||
                context.raiseError(ObjAccessError(context, "can't access non-public field $name"))
 | 
			
		||||
        }
 | 
			
		||||
            ?: super.readField(context, name)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override suspend fun writeField(context: Context, name: String, newValue: Obj) {
 | 
			
		||||
        if( name in objClass.publicFields ) {
 | 
			
		||||
            val f = instanceContext[name]!!
 | 
			
		||||
            if( !f.isMutable ) ObjIllegalAssignmentError(context, "can't reassign val $name").raise()
 | 
			
		||||
            if( f.value.assign(context, newValue) == null)
 | 
			
		||||
        instanceContext[name]?.let { f ->
 | 
			
		||||
            if (!f.visibility.isPublic)
 | 
			
		||||
                ObjIllegalAssignmentError(context, "can't assign to non-public field $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)
 | 
			
		||||
        } ?: super.writeField(context, name, newValue)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override suspend fun invokeInstanceMethod(context: Context, name: String, args: Arguments): Obj {
 | 
			
		||||
        if( name in objClass.publicFields ) return instanceContext[name]!!.value.invoke(context, this, args)
 | 
			
		||||
        return super.invokeInstanceMethod(context, name, args)
 | 
			
		||||
    }
 | 
			
		||||
    override suspend fun invokeInstanceMethod(context: Context, name: String, args: Arguments): Obj =
 | 
			
		||||
        instanceContext[name]?.let {
 | 
			
		||||
            if (it.visibility.isPublic)
 | 
			
		||||
                it.value.invoke(context, this, args)
 | 
			
		||||
            else
 | 
			
		||||
                context.raiseError(ObjAccessError(context, "can't invoke non-public method $name"))
 | 
			
		||||
        }
 | 
			
		||||
            ?: super.invokeInstanceMethod(context, name, args)
 | 
			
		||||
 | 
			
		||||
    private val publicFields: Map<String, ObjRecord>
 | 
			
		||||
        get() = instanceContext.objects.filter { it.value.visibility.isPublic }
 | 
			
		||||
 | 
			
		||||
    override fun toString(): String {
 | 
			
		||||
        val fields = objClass.publicFields.map {
 | 
			
		||||
                instanceContext[it]?.value?.toString() ?: "??"
 | 
			
		||||
        }.joinToString(", ")
 | 
			
		||||
        val fields = publicFields.map { "${it.key}=${it.value.value}" }.joinToString(",")
 | 
			
		||||
        return "${objClass.className}($fields)"
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override suspend fun compareTo(context: Context, other: Obj): Int {
 | 
			
		||||
        if( other !is ObjInstance ) return -1
 | 
			
		||||
        if( other.objClass != objClass ) return -1
 | 
			
		||||
        for( f in objClass.publicFields ) {
 | 
			
		||||
            val a = instanceContext[f]!!.value
 | 
			
		||||
            val b = other.instanceContext[f]!!.value
 | 
			
		||||
        if (other !is ObjInstance) return -1
 | 
			
		||||
        if (other.objClass != objClass) return -1
 | 
			
		||||
        for (f in publicFields) {
 | 
			
		||||
            val a = f.value.value
 | 
			
		||||
            val b = other.instanceContext[f.key]!!.value
 | 
			
		||||
            val d = a.compareTo(context, b)
 | 
			
		||||
            if (d != 0) return d
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@ -6,6 +6,7 @@ import kotlin.math.*
 | 
			
		||||
class Script(
 | 
			
		||||
    override val pos: Pos,
 | 
			
		||||
    private val statements: List<Statement> = emptyList(),
 | 
			
		||||
//    private val catchReturn: Boolean = false,
 | 
			
		||||
) : Statement() {
 | 
			
		||||
 | 
			
		||||
    override suspend fun execute(context: Context): Obj {
 | 
			
		||||
 | 
			
		||||
@ -0,0 +1,8 @@
 | 
			
		||||
package net.sergeych.lyng
 | 
			
		||||
 | 
			
		||||
enum class Visibility {
 | 
			
		||||
    Public, Private, Protected;//, Internal
 | 
			
		||||
    val isPublic by lazy { this == Public }
 | 
			
		||||
    @Suppress("unused")
 | 
			
		||||
    val isProtected by lazy { this == Protected }
 | 
			
		||||
}
 | 
			
		||||
@ -1513,4 +1513,11 @@ class ScriptTest {
 | 
			
		||||
            assert( Point(1,2) < Point(1,3) )
 | 
			
		||||
        """.trimIndent())
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    fun testAccessShortcuts() {
 | 
			
		||||
        assertTrue( Visibility.Public.isPublic )
 | 
			
		||||
        assertFalse( Visibility.Private.isPublic )
 | 
			
		||||
        assertFalse( Visibility.Protected.isPublic )
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user