ObjInstance / ObjClass optimization no more list of accessible fields!

This commit is contained in:
Sergey Chernov 2025-06-10 23:51:01 +04:00
parent 88b355c40d
commit d482401b15
14 changed files with 81 additions and 84 deletions

View File

@ -158,7 +158,7 @@ For example, for our class Point:
assert( Point(1,2) < Point(2,2) ) assert( Point(1,2) < Point(2,2) )
assert( Point(1,2) < Point(1,3) ) assert( Point(1,2) < Point(1,3) )
Point(1,1+1) Point(1,1+1)
>>> Point(1, 2) >>> Point(x=1,y=2)
# Theory # Theory

View File

@ -39,22 +39,5 @@ We can just put the code into the module code:
## class initialization ## class initialization
class foo { already done using `ObjInstance` class and instance-bound context with local
context stored in ObjInstance and class constructor statement in ObjClass.
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
}
}

View File

@ -5,7 +5,7 @@ import org.jetbrains.kotlin.gradle.ExperimentalWasmDsl
import org.jetbrains.kotlin.gradle.dsl.JvmTarget import org.jetbrains.kotlin.gradle.dsl.JvmTarget
group = "net.sergeych" group = "net.sergeych"
version = "0.2.1-SNAPSHOT" version = "0.3.0-SNAPSHOT"
buildscript { buildscript {
repositories { repositories {

View File

@ -0,0 +1,8 @@
package net.sergeych.lyng
enum class AccessType(val isMutable: Boolean) {
Val(false), Var(true),
@Suppress("unused")
Initialization(false)
}

View File

@ -23,8 +23,8 @@ data class ArgsDeclaration(val params: List<Item>, val endTokenType: Token.Type)
suspend fun assignToContext( suspend fun assignToContext(
context: Context, context: Context,
fromArgs: Arguments = context.args, fromArgs: Arguments = context.args,
defaultAccessType: Compiler.AccessType = Compiler.AccessType.Var, defaultAccessType: AccessType = AccessType.Var,
defaultVisibility: Compiler.Visibility = Compiler.Visibility.Public defaultVisibility: Visibility = Visibility.Public
) { ) {
fun assign(a: Item, value: Obj) { fun assign(a: Item, value: Obj) {
context.addItem(a.name, (a.accessType ?: defaultAccessType).isMutable, value, 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__. * So it is a [Statement] that must be executed on __caller context__.
*/ */
val defaultValue: Statement? = null, val defaultValue: Statement? = null,
val accessType: Compiler.AccessType? = null, val accessType: AccessType? = null,
val visibility: Compiler.Visibility? = null, val visibility: Visibility? = null,
) )
} }

View File

@ -19,11 +19,12 @@ class Compiler(
private fun parseScript(start: Pos, cc: CompilerContext): Script { private fun parseScript(start: Pos, cc: CompilerContext): Script {
val statements = mutableListOf<Statement>() val statements = mutableListOf<Statement>()
// val returnScope = cc.startReturnScope()
while (parseStatement(cc, braceMeansLambda = true)?.also { while (parseStatement(cc, braceMeansLambda = true)?.also {
statements += it statements += it
} != null) {/**/ } != null) {/**/
} }
return Script(start, statements) return Script(start, statements)//returnScope.needCatch)
} }
private fun parseStatement(cc: CompilerContext, braceMeansLambda: Boolean = false): Statement? { 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) * Parse argument declaration, used in lambda (and later in fn too)
* @return declaration or null if there is no valid list of arguments * @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 // fields. Note that 'this' is already set by class
constructorArgsDeclaration?.assignToContext(this) constructorArgsDeclaration?.assignToContext(this)
bodyInit?.execute(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 thisObj
} }

View File

@ -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. * 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) { for( i in -depths .. -1) {
when( atOffset(i)?.type) { when( atOffset(i)?.type) {
Token.Type.PROTECTED -> return Compiler.Visibility.Protected Token.Type.PROTECTED -> return Visibility.Protected
Token.Type.PRIVATE -> return Compiler.Visibility.Private Token.Type.PRIVATE -> return Visibility.Private
else -> {} else -> {}
} }
} }
return default return default
} }
// data class ReturnScope(val needCatch: Boolean = false)
// private val
// fun startReturnScope(): ReturnScope {
// return ReturnScope()
// }
} }

View File

@ -78,7 +78,7 @@ class Context(
name: String, name: String,
isMutable: Boolean, isMutable: Boolean,
value: Obj, value: Obj,
visibility: Compiler.Visibility = Compiler.Visibility.Public visibility: Visibility = Visibility.Public
): ObjRecord { ): ObjRecord {
return ObjRecord(value, isMutable, visibility).also { objects.put(name, it) } return ObjRecord(value, isMutable, visibility).also { objects.put(name, it) }
} }

View File

@ -12,7 +12,7 @@ import net.sergeych.synctools.ProtectedOp
data class ObjRecord( data class ObjRecord(
var value: Obj, var value: Obj,
val isMutable: Boolean, val isMutable: Boolean,
val visibility: Compiler.Visibility = Compiler.Visibility.Public val visibility: Visibility = Visibility.Public
) )
/** /**
@ -342,3 +342,4 @@ class ObjIllegalArgumentError(context: Context, message: String = "illegal argum
class ObjIllegalAssignmentError(context: Context, message: String = "illegal assignment") : 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 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)

View File

@ -7,9 +7,6 @@ class ObjClass(
vararg val parents: ObjClass, vararg val parents: ObjClass,
) : Obj() { ) : Obj() {
internal val publicFields = mutableSetOf<String>()
internal val protectedFields = mutableSetOf<String>()
var instanceConstructor: Statement? = null var instanceConstructor: Statement? = null
val allParentsSet: Set<ObjClass> = parents.flatMap { val allParentsSet: Set<ObjClass> = parents.flatMap {
@ -42,10 +39,10 @@ class ObjClass(
name: String, name: String,
initialValue: Obj, initialValue: Obj,
isMutable: Boolean = false, isMutable: Boolean = false,
visibility: Compiler.Visibility = Compiler.Visibility.Public, visibility: Visibility = Visibility.Public,
pos: Pos = Pos.builtIn 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") throw ScriptError(pos, "$name is already defined in $objClass or one of its supertypes")
members[name] = ObjRecord(initialValue, isMutable, visibility) members[name] = ObjRecord(initialValue, isMutable, visibility)
} }

View File

@ -5,38 +5,48 @@ class ObjInstance(override val objClass: ObjClass) : Obj() {
internal lateinit var instanceContext: Context internal lateinit var instanceContext: Context
override suspend fun readField(context: Context, name: String): ObjRecord { override suspend fun readField(context: Context, name: String): ObjRecord {
return if( name in objClass.publicFields ) instanceContext[name]!! return instanceContext[name]?.let {
else super.readField(context, name) 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) { override suspend fun writeField(context: Context, name: String, newValue: Obj) {
if( name in objClass.publicFields ) { instanceContext[name]?.let { f ->
val f = instanceContext[name]!! if (!f.visibility.isPublic)
if( !f.isMutable ) ObjIllegalAssignmentError(context, "can't reassign val $name").raise() ObjIllegalAssignmentError(context, "can't assign to non-public field $name")
if( f.value.assign(context, newValue) == null) if (!f.isMutable) ObjIllegalAssignmentError(context, "can't reassign val $name").raise()
if (f.value.assign(context, newValue) == null)
f.value = newValue f.value = newValue
} } ?: super.writeField(context, name, newValue)
else super.writeField(context, name, newValue)
} }
override suspend fun invokeInstanceMethod(context: Context, name: String, args: Arguments): Obj { override suspend fun invokeInstanceMethod(context: Context, name: String, args: Arguments): Obj =
if( name in objClass.publicFields ) return instanceContext[name]!!.value.invoke(context, this, args) instanceContext[name]?.let {
return super.invokeInstanceMethod(context, name, args) 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 { override fun toString(): String {
val fields = objClass.publicFields.map { val fields = publicFields.map { "${it.key}=${it.value.value}" }.joinToString(",")
instanceContext[it]?.value?.toString() ?: "??"
}.joinToString(", ")
return "${objClass.className}($fields)" return "${objClass.className}($fields)"
} }
override suspend fun compareTo(context: Context, other: Obj): Int { override suspend fun compareTo(context: Context, other: Obj): Int {
if( other !is ObjInstance ) return -1 if (other !is ObjInstance) return -1
if( other.objClass != objClass ) return -1 if (other.objClass != objClass) return -1
for( f in objClass.publicFields ) { for (f in publicFields) {
val a = instanceContext[f]!!.value val a = f.value.value
val b = other.instanceContext[f]!!.value val b = other.instanceContext[f.key]!!.value
val d = a.compareTo(context, b) val d = a.compareTo(context, b)
if (d != 0) return d if (d != 0) return d
} }

View File

@ -6,6 +6,7 @@ import kotlin.math.*
class Script( class Script(
override val pos: Pos, override val pos: Pos,
private val statements: List<Statement> = emptyList(), private val statements: List<Statement> = emptyList(),
// private val catchReturn: Boolean = false,
) : Statement() { ) : Statement() {
override suspend fun execute(context: Context): Obj { override suspend fun execute(context: Context): Obj {

View File

@ -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 }
}

View File

@ -1513,4 +1513,11 @@ class ScriptTest {
assert( Point(1,2) < Point(1,3) ) assert( Point(1,2) < Point(1,3) )
""".trimIndent()) """.trimIndent())
} }
@Test
fun testAccessShortcuts() {
assertTrue( Visibility.Public.isPublic )
assertFalse( Visibility.Private.isPublic )
assertFalse( Visibility.Protected.isPublic )
}
} }