From 53a6a88924b0a3f15ab7e858c9da12f3294c7d48 Mon Sep 17 00:00:00 2001 From: sergeych Date: Wed, 6 Aug 2025 22:48:32 +0300 Subject: [PATCH] fix #42 class static fields and methods --- .../kotlin/net/sergeych/lyng/Compiler.kt | 41 ++++++++++++++----- lynglib/src/commonTest/kotlin/OOTest.kt | 13 +++++- 2 files changed, 42 insertions(+), 12 deletions(-) diff --git a/lynglib/src/commonMain/kotlin/net/sergeych/lyng/Compiler.kt b/lynglib/src/commonMain/kotlin/net/sergeych/lyng/Compiler.kt index 7937b92..e234062 100644 --- a/lynglib/src/commonMain/kotlin/net/sergeych/lyng/Compiler.kt +++ b/lynglib/src/commonMain/kotlin/net/sergeych/lyng/Compiler.kt @@ -19,10 +19,11 @@ class Compiler( private val initStack = mutableListOf>() - val currentInitScope: MutableList get() = - initStack.lastOrNull() ?: cc.syntaxError("no initialization scope exists here") + val currentInitScope: MutableList + get() = + initStack.lastOrNull() ?: cc.syntaxError("no initialization scope exists here") - private fun pushInitScope(): MutableList = mutableListOf().also { initStack.add(it)} + private fun pushInitScope(): MutableList = mutableListOf().also { initStack.add(it) } private fun popInitScope(): MutableList = initStack.removeLast() @@ -832,6 +833,8 @@ class Compiler( val isExtern = cc.skipId("extern") when { cc.matchQualifiers("fun", "private") -> parseFunctionDeclaration(Visibility.Private, isExtern) + cc.matchQualifiers("fun", "private", "static") -> parseFunctionDeclaration(Visibility.Private, isExtern, isStatic = true) + cc.matchQualifiers("fun", "static") -> parseFunctionDeclaration(Visibility.Public, isExtern, isStatic = true) cc.matchQualifiers("fn", "private") -> parseFunctionDeclaration(Visibility.Private, isExtern) cc.matchQualifiers("fun", "open") -> parseFunctionDeclaration(isOpen = true, isExtern = isExtern) cc.matchQualifiers("fn", "open") -> parseFunctionDeclaration(isOpen = true, isExtern = isExtern) @@ -839,11 +842,21 @@ class Compiler( cc.matchQualifiers("fun") -> parseFunctionDeclaration(isOpen = false, isExtern = isExtern) cc.matchQualifiers("fn") -> parseFunctionDeclaration(isOpen = false, isExtern = isExtern) - cc.matchQualifiers("val", "private", "static") -> parseVarDeclaration(false, Visibility.Private, isStatic = true) + cc.matchQualifiers("val", "private", "static") -> parseVarDeclaration( + false, + Visibility.Private, + isStatic = true + ) + cc.matchQualifiers("val", "static") -> parseVarDeclaration(false, Visibility.Public, isStatic = true) cc.matchQualifiers("val", "private") -> parseVarDeclaration(false, Visibility.Private) cc.matchQualifiers("var", "static") -> parseVarDeclaration(true, Visibility.Public, isStatic = true) - cc.matchQualifiers("var", "static", "private" ) -> parseVarDeclaration(true, Visibility.Private, isStatic = true) + cc.matchQualifiers("var", "static", "private") -> parseVarDeclaration( + true, + Visibility.Private, + isStatic = true + ) + cc.matchQualifiers("var", "private") -> parseVarDeclaration(true, Visibility.Private) cc.matchQualifiers("val", "open") -> parseVarDeclaration(false, Visibility.Private, true) cc.matchQualifiers("var", "open") -> parseVarDeclaration(true, Visibility.Private, true) @@ -1148,12 +1161,12 @@ class Compiler( // the main statement should create custom ObjClass instance with field // accessors, constructor registration, etc. addItem(className, false, newClass) - if( initScope.isNotEmpty()) { + if (initScope.isNotEmpty()) { val classScope = copy(newThisObj = newClass) newClass.classScope = classScope - for( s in initScope ) + for (s in initScope) s.execute(classScope) - .also { println("executed, ${classScope.objects}")} + .also { println("executed, ${classScope.objects}") } } newClass } @@ -1530,7 +1543,8 @@ class Compiler( private suspend fun parseFunctionDeclaration( visibility: Visibility = Visibility.Public, @Suppress("UNUSED_PARAMETER") isOpen: Boolean = false, - isExtern: Boolean = false + isExtern: Boolean = false, + isStatic: Boolean = false, ): Statement { var t = cc.next() val start = t.pos @@ -1583,7 +1597,7 @@ class Compiler( } fnStatements.execute(context) } - return statement(start) { context -> + val fnCreatestatement = statement(start) { context -> // we added fn in the context. now we must save closure // for the function closure = context @@ -1601,6 +1615,11 @@ class Compiler( // saved the proper context in the closure fnBody } + return if (isStatic) { + currentInitScope += fnCreatestatement + NopStatement + } else + fnCreatestatement } private suspend fun parseBlock(skipLeadingBrace: Boolean = false): Statement { @@ -1647,7 +1666,7 @@ class Compiler( val initialExpression = if (setNull) null else parseStatement(true) ?: throw ScriptError(eqToken.pos, "Expected initializer expression") - if( isStatic) { + if (isStatic) { // find objclass instance: this is tricky: this code executes in object initializer, // when creating instance, but we need to execute it in the class initializer which // is missing as for now. Add it to the compiler context? diff --git a/lynglib/src/commonTest/kotlin/OOTest.kt b/lynglib/src/commonTest/kotlin/OOTest.kt index 9ed51a5..5b68b1d 100644 --- a/lynglib/src/commonTest/kotlin/OOTest.kt +++ b/lynglib/src/commonTest/kotlin/OOTest.kt @@ -27,9 +27,20 @@ class OOTest { class Point(x,y) { private static var data = null + + static fun getData() { data } + static fun setData(value) { + data = value + callFrom() + } + static fun callFrom() { + data = data + "!" + } } assertEquals(Point(0,0), Point(0,0) ) - + assertEquals(null, Point.getData() ) + Point.setData("foo") + assertEquals( "foo!", Point.getData() ) """.trimIndent()) } } \ No newline at end of file