diff --git a/docs/OOP.md b/docs/OOP.md index febc801..6708e11 100644 --- a/docs/OOP.md +++ b/docs/OOP.md @@ -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 diff --git a/docs/development/including_modules.md b/docs/development/including_modules.md index f201a0b..f00e16c 100644 --- a/docs/development/including_modules.md +++ b/docs/development/including_modules.md @@ -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. \ No newline at end of file diff --git a/library/build.gradle.kts b/library/build.gradle.kts index 17141d8..b2c4242 100644 --- a/library/build.gradle.kts +++ b/library/build.gradle.kts @@ -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 { diff --git a/library/src/commonMain/kotlin/net/sergeych/lyng/AccessType.kt b/library/src/commonMain/kotlin/net/sergeych/lyng/AccessType.kt new file mode 100644 index 0000000..7af0fd6 --- /dev/null +++ b/library/src/commonMain/kotlin/net/sergeych/lyng/AccessType.kt @@ -0,0 +1,8 @@ +package net.sergeych.lyng + +enum class AccessType(val isMutable: Boolean) { + Val(false), Var(true), + + @Suppress("unused") + Initialization(false) +} \ No newline at end of file diff --git a/library/src/commonMain/kotlin/net/sergeych/lyng/ArgsDeclaration.kt b/library/src/commonMain/kotlin/net/sergeych/lyng/ArgsDeclaration.kt index 1bdea48..124087f 100644 --- a/library/src/commonMain/kotlin/net/sergeych/lyng/ArgsDeclaration.kt +++ b/library/src/commonMain/kotlin/net/sergeych/lyng/ArgsDeclaration.kt @@ -23,8 +23,8 @@ data class ArgsDeclaration(val params: List, 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, 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, ) } \ No newline at end of file diff --git a/library/src/commonMain/kotlin/net/sergeych/lyng/Compiler.kt b/library/src/commonMain/kotlin/net/sergeych/lyng/Compiler.kt index e821a71..4fa7f83 100644 --- a/library/src/commonMain/kotlin/net/sergeych/lyng/Compiler.kt +++ b/library/src/commonMain/kotlin/net/sergeych/lyng/Compiler.kt @@ -19,11 +19,12 @@ class Compiler( private fun parseScript(start: Pos, cc: CompilerContext): Script { val statements = mutableListOf() +// 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 } diff --git a/library/src/commonMain/kotlin/net/sergeych/lyng/CompilerContext.kt b/library/src/commonMain/kotlin/net/sergeych/lyng/CompilerContext.kt index 1ac8b38..acb955e 100644 --- a/library/src/commonMain/kotlin/net/sergeych/lyng/CompilerContext.kt +++ b/library/src/commonMain/kotlin/net/sergeych/lyng/CompilerContext.kt @@ -123,15 +123,23 @@ internal class CompilerContext(val tokens: List) { /** * 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() +// } + } \ No newline at end of file diff --git a/library/src/commonMain/kotlin/net/sergeych/lyng/Context.kt b/library/src/commonMain/kotlin/net/sergeych/lyng/Context.kt index 1880e26..2c6d767 100644 --- a/library/src/commonMain/kotlin/net/sergeych/lyng/Context.kt +++ b/library/src/commonMain/kotlin/net/sergeych/lyng/Context.kt @@ -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) } } diff --git a/library/src/commonMain/kotlin/net/sergeych/lyng/Obj.kt b/library/src/commonMain/kotlin/net/sergeych/lyng/Obj.kt index a32a02b..a245440 100644 --- a/library/src/commonMain/kotlin/net/sergeych/lyng/Obj.kt +++ b/library/src/commonMain/kotlin/net/sergeych/lyng/Obj.kt @@ -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") \ No newline at end of file +class ObjIterationFinishedError(context: Context) : ObjError(context, "iteration finished") +class ObjAccessError(context: Context, message: String = "access not allowed error") : ObjError(context, message) \ No newline at end of file diff --git a/library/src/commonMain/kotlin/net/sergeych/lyng/ObjClass.kt b/library/src/commonMain/kotlin/net/sergeych/lyng/ObjClass.kt index 7ed385b..56ef4d7 100644 --- a/library/src/commonMain/kotlin/net/sergeych/lyng/ObjClass.kt +++ b/library/src/commonMain/kotlin/net/sergeych/lyng/ObjClass.kt @@ -7,9 +7,6 @@ class ObjClass( vararg val parents: ObjClass, ) : Obj() { - internal val publicFields = mutableSetOf() - internal val protectedFields = mutableSetOf() - var instanceConstructor: Statement? = null val allParentsSet: Set = 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) } diff --git a/library/src/commonMain/kotlin/net/sergeych/lyng/ObjInstance.kt b/library/src/commonMain/kotlin/net/sergeych/lyng/ObjInstance.kt index b96d7ab..80d9140 100644 --- a/library/src/commonMain/kotlin/net/sergeych/lyng/ObjInstance.kt +++ b/library/src/commonMain/kotlin/net/sergeych/lyng/ObjInstance.kt @@ -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 + 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 } diff --git a/library/src/commonMain/kotlin/net/sergeych/lyng/Script.kt b/library/src/commonMain/kotlin/net/sergeych/lyng/Script.kt index f5cee42..47ab882 100644 --- a/library/src/commonMain/kotlin/net/sergeych/lyng/Script.kt +++ b/library/src/commonMain/kotlin/net/sergeych/lyng/Script.kt @@ -6,6 +6,7 @@ import kotlin.math.* class Script( override val pos: Pos, private val statements: List = emptyList(), +// private val catchReturn: Boolean = false, ) : Statement() { override suspend fun execute(context: Context): Obj { diff --git a/library/src/commonMain/kotlin/net/sergeych/lyng/Visibility.kt b/library/src/commonMain/kotlin/net/sergeych/lyng/Visibility.kt new file mode 100644 index 0000000..51c553e --- /dev/null +++ b/library/src/commonMain/kotlin/net/sergeych/lyng/Visibility.kt @@ -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 } +} \ No newline at end of file diff --git a/library/src/commonTest/kotlin/ScriptTest.kt b/library/src/commonTest/kotlin/ScriptTest.kt index 9d33a4e..715cc2b 100644 --- a/library/src/commonTest/kotlin/ScriptTest.kt +++ b/library/src/commonTest/kotlin/ScriptTest.kt @@ -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 ) + } } \ No newline at end of file