diff --git a/lyng/src/commonMain/kotlin/Common.kt b/lyng/src/commonMain/kotlin/Common.kt index 21a20fb..80bed57 100644 --- a/lyng/src/commonMain/kotlin/Common.kt +++ b/lyng/src/commonMain/kotlin/Common.kt @@ -29,7 +29,6 @@ import com.github.ajalt.clikt.parameters.options.option import kotlinx.coroutines.runBlocking import net.sergeych.lyng.Compiler import net.sergeych.lyng.LyngVersion -import net.sergeych.lyng.Pos import net.sergeych.lyng.Script import net.sergeych.lyng.ScriptError import net.sergeych.lyng.Source @@ -158,7 +157,6 @@ private class Lyng(val launcher: (suspend () -> Unit) -> Unit) : CliktCommand() val version by option("-v", "--version", help = "Print version and exit").flag() val benchmark by option("--benchmark", help = "Run JVM microbenchmarks and exit").flag() - val bytecodeFallbacks by option("--bytecode-fallbacks", help = "Report lambdas that fall back to interpreter").flag() val script by argument(help = "one or more scripts to execute").optional() val execute: String? by option( "-x", "--execute", help = """ @@ -170,7 +168,7 @@ private class Lyng(val launcher: (suspend () -> Unit) -> Unit) : CliktCommand() override fun help(context: Context): String = """ - The Lyng script language interpreter, language version is $LyngVersion. + The Lyng script language runtime, language version is $LyngVersion. Please refer form more information to the project site: https://gitea.sergeych.net/SergeychWorks/lyng @@ -201,15 +199,12 @@ private class Lyng(val launcher: (suspend () -> Unit) -> Unit) : CliktCommand() launcher { // there is no script name, it is a first argument instead: processErrors { - val reporter = bytecodeFallbackReporter(bytecodeFallbacks) val script = Compiler.compileWithResolution( Source("", execute!!), baseScope.currentImportProvider, - seedScope = baseScope, - bytecodeFallbackReporter = reporter + seedScope = baseScope ) script.execute(baseScope) - flushBytecodeFallbacks(reporter) } } } @@ -220,7 +215,7 @@ private class Lyng(val launcher: (suspend () -> Unit) -> Unit) : CliktCommand() echoFormattedHelp() } else { baseScope.addConst("ARGV", ObjList(args.map { ObjString(it) }.toMutableList())) - launcher { executeFile(script!!, bytecodeFallbacks) } + launcher { executeFile(script!!) } } } } @@ -228,14 +223,14 @@ private class Lyng(val launcher: (suspend () -> Unit) -> Unit) : CliktCommand() } } -fun executeFileWithArgs(fileName: String, args: List, reportBytecodeFallbacks: Boolean = false) { +fun executeFileWithArgs(fileName: String, args: List) { runBlocking { baseScopeDefer.await().addConst("ARGV", ObjList(args.map { ObjString(it) }.toMutableList())) - executeFile(fileName, reportBytecodeFallbacks) + executeFile(fileName) } } -suspend fun executeFile(fileName: String, reportBytecodeFallbacks: Boolean = false) { +suspend fun executeFile(fileName: String) { var text = FileSystem.SYSTEM.source(fileName.toPath()).use { fileSource -> fileSource.buffer().use { bs -> bs.readUtf8() @@ -248,15 +243,12 @@ suspend fun executeFile(fileName: String, reportBytecodeFallbacks: Boolean = fal } processErrors { val scope = baseScopeDefer.await() - val reporter = bytecodeFallbackReporter(reportBytecodeFallbacks) val script = Compiler.compileWithResolution( Source(fileName, text), scope.currentImportProvider, - seedScope = scope, - bytecodeFallbackReporter = reporter + seedScope = scope ) script.execute(scope) - flushBytecodeFallbacks(reporter) } } @@ -268,22 +260,3 @@ suspend fun processErrors(block: suspend () -> Unit) { println("\nError executing the script:\n$e\n") } } - -private fun bytecodeFallbackReporter(enabled: Boolean): ((Pos, String) -> Unit)? { - if (!enabled) return null - val reports = ArrayList() - val reporter: (Pos, String) -> Unit = { pos, msg -> - reports.add("$pos: $msg") - } - return object : (Pos, String) -> Unit by reporter { - override fun invoke(pos: Pos, msg: String) = reporter(pos, msg) - override fun toString(): String = reports.joinToString("\n") - } -} - -private fun flushBytecodeFallbacks(reporter: ((Pos, String) -> Unit)?) { - val text = reporter?.toString().orEmpty() - if (text.isBlank()) return - println("Bytecode lambda fallbacks:") - println(text) -} diff --git a/lyngio/src/commonMain/kotlin/net/sergeych/lyng/io/process/LyngProcessModule.kt b/lyngio/src/commonMain/kotlin/net/sergeych/lyng/io/process/LyngProcessModule.kt index f731c90..a832fbc 100644 --- a/lyngio/src/commonMain/kotlin/net/sergeych/lyng/io/process/LyngProcessModule.kt +++ b/lyngio/src/commonMain/kotlin/net/sergeych/lyng/io/process/LyngProcessModule.kt @@ -23,7 +23,6 @@ import net.sergeych.lyng.Scope import net.sergeych.lyng.miniast.* import net.sergeych.lyng.obj.* import net.sergeych.lyng.pacman.ImportManager -import net.sergeych.lyng.statement import net.sergeych.lyngio.process.* import net.sergeych.lyngio.process.security.ProcessAccessDeniedException import net.sergeych.lyngio.process.security.ProcessAccessPolicy @@ -216,7 +215,7 @@ private suspend inline fun Scope.processGuard(crossinline block: suspend () -> O } private fun Flow.toLyngFlow(flowScope: Scope): ObjFlow { - val producer = statement { + val producer = ObjNativeCallable { val builder = (this as? net.sergeych.lyng.BytecodeClosureScope)?.callScope?.thisObj as? ObjFlowBuilder ?: this.thisObj as? ObjFlowBuilder diff --git a/lynglib/src/commonMain/kotlin/net/sergeych/lyng/Compiler.kt b/lynglib/src/commonMain/kotlin/net/sergeych/lyng/Compiler.kt index 61391c0..0086174 100644 --- a/lynglib/src/commonMain/kotlin/net/sergeych/lyng/Compiler.kt +++ b/lynglib/src/commonMain/kotlin/net/sergeych/lyng/Compiler.kt @@ -112,6 +112,9 @@ class Compiler( if (!added) { currentShadowedLocalNames?.add(name) } + if (added) { + scopeSeedNames.remove(name) + } if (added && localDeclCountStack.isNotEmpty()) { localDeclCountStack[localDeclCountStack.lastIndex] = currentLocalDeclCount + 1 } @@ -136,6 +139,9 @@ class Compiler( if (plan.slots.containsKey(name)) return plan.slots[name] = SlotEntry(plan.nextIndex, isMutable, isDelegated) plan.nextIndex += 1 + if (!seedingSlotPlan && plan == moduleSlotPlan()) { + moduleDeclaredNames.add(name) + } } private fun declareSlotNameAt( @@ -155,6 +161,7 @@ class Compiler( private fun moduleSlotPlan(): SlotPlan? = slotPlanStack.firstOrNull() private val slotTypeByScopeId: MutableMap> = mutableMapOf() private val nameObjClass: MutableMap = mutableMapOf() + private val scopeSeedNames: MutableSet = mutableSetOf() private val slotTypeDeclByScopeId: MutableMap> = mutableMapOf() private val nameTypeDecl: MutableMap = mutableMapOf() private data class TypeAliasDecl( @@ -177,69 +184,81 @@ class Compiler( private val encodedPayloadTypeByName: MutableMap = mutableMapOf() private val objectDeclNames: MutableSet = mutableSetOf() private val externCallableNames: MutableSet = mutableSetOf() + private val moduleDeclaredNames: MutableSet = mutableSetOf() + private var seedingSlotPlan: Boolean = false private fun seedSlotPlanFromScope(scope: Scope, includeParents: Boolean = false) { val plan = moduleSlotPlan() ?: return - var current: Scope? = scope - while (current != null) { - for ((name, record) in current.objects) { - if (!record.visibility.isPublic) continue - if (plan.slots.containsKey(name)) continue - declareSlotNameIn(plan, name, record.isMutable, record.type == ObjRecord.Type.Delegated) - val instance = record.value as? ObjInstance - if (instance != null && nameObjClass[name] == null) { - nameObjClass[name] = instance.objClass - } - } - for ((cls, map) in current.extensions) { - for ((name, record) in map) { + seedingSlotPlan = true + try { + var current: Scope? = scope + while (current != null) { + for ((name, record) in current.objects) { if (!record.visibility.isPublic) continue - when (record.type) { - ObjRecord.Type.Property -> { - val getterName = extensionPropertyGetterName(cls.className, name) - if (!plan.slots.containsKey(getterName)) { - declareSlotNameIn( - plan, - getterName, - isMutable = false, - isDelegated = false - ) - } - val prop = record.value as? ObjProperty - if (prop?.setter != null) { - val setterName = extensionPropertySetterName(cls.className, name) - if (!plan.slots.containsKey(setterName)) { + if (plan.slots.containsKey(name)) continue + declareSlotNameIn(plan, name, record.isMutable, record.type == ObjRecord.Type.Delegated) + scopeSeedNames.add(name) + val instance = record.value as? ObjInstance + if (instance != null && nameObjClass[name] == null) { + nameObjClass[name] = instance.objClass + } + } + for ((cls, map) in current.extensions) { + for ((name, record) in map) { + if (!record.visibility.isPublic) continue + when (record.type) { + ObjRecord.Type.Property -> { + val getterName = extensionPropertyGetterName(cls.className, name) + if (!plan.slots.containsKey(getterName)) { declareSlotNameIn( plan, - setterName, + getterName, isMutable = false, isDelegated = false ) + scopeSeedNames.add(getterName) + } + val prop = record.value as? ObjProperty + if (prop?.setter != null) { + val setterName = extensionPropertySetterName(cls.className, name) + if (!plan.slots.containsKey(setterName)) { + declareSlotNameIn( + plan, + setterName, + isMutable = false, + isDelegated = false + ) + scopeSeedNames.add(setterName) + } } } - } - else -> { - val callableName = extensionCallableName(cls.className, name) - if (!plan.slots.containsKey(callableName)) { - declareSlotNameIn( - plan, - callableName, - isMutable = false, - isDelegated = false - ) + else -> { + val callableName = extensionCallableName(cls.className, name) + if (!plan.slots.containsKey(callableName)) { + declareSlotNameIn( + plan, + callableName, + isMutable = false, + isDelegated = false + ) + scopeSeedNames.add(callableName) + } } } } } + for ((name, slotIndex) in current.slotNameToIndexSnapshot()) { + val record = current.getSlotRecord(slotIndex) + if (!record.visibility.isPublic) continue + if (plan.slots.containsKey(name)) continue + declareSlotNameIn(plan, name, record.isMutable, record.type == ObjRecord.Type.Delegated) + scopeSeedNames.add(name) + } + if (!includeParents) return + current = current.parent } - for ((name, slotIndex) in current.slotNameToIndexSnapshot()) { - val record = current.getSlotRecord(slotIndex) - if (!record.visibility.isPublic) continue - if (plan.slots.containsKey(name)) continue - declareSlotNameIn(plan, name, record.isMutable, record.type == ObjRecord.Type.Delegated) - } - if (!includeParents) return - current = current.parent + } finally { + seedingSlotPlan = false } } @@ -254,6 +273,7 @@ class Compiler( record.isMutable, record.type == ObjRecord.Type.Delegated ) + scopeSeedNames.add(name) } } @@ -322,6 +342,7 @@ class Compiler( val nameToken = nextNonWs() if (nameToken.type == Token.Type.ID) { declareSlotNameIn(plan, nameToken.value, isMutable = false, isDelegated = false) + scopeSeedNames.add(nameToken.value) } } "enum" -> { @@ -329,6 +350,7 @@ class Compiler( val nameToken = if (next.type == Token.Type.ID && next.value == "class") nextNonWs() else next if (nameToken.type == Token.Type.ID) { declareSlotNameIn(plan, nameToken.value, isMutable = false, isDelegated = false) + scopeSeedNames.add(nameToken.value) } } } @@ -1557,6 +1579,7 @@ class Compiler( "