Compare commits

..

No commits in common. "30b6ef235bedd3b4a4c20aecdf009ab454defbdf" and "230cb0a067fab205f99905b818df23e5dda64124" have entirely different histories.

7 changed files with 20 additions and 103 deletions

View File

@ -7,15 +7,10 @@ import net.sergeych.lyng.pacman.ImportProvider
*/ */
class Compiler( class Compiler(
val cc: CompilerContext, val cc: CompilerContext,
val importManager: ImportProvider, val importManager: ImportProvider = Script.defaultImportManager,
@Suppress("UNUSED_PARAMETER") @Suppress("UNUSED_PARAMETER")
settings: Settings = Settings() settings: Settings = Settings()
) { ) {
init {
println("Compiler initialized: $importManager")
}
var packageName: String? = null var packageName: String? = null
class Settings class Settings
@ -1623,8 +1618,8 @@ class Compiler(
companion object { companion object {
suspend fun compile(source: Source,importManager: ImportProvider): Script { suspend fun compile(source: Source, importProvider: ImportProvider = Script.defaultImportManager): Script {
return Compiler(CompilerContext(parseLyng(source)),importManager).parseScript() return Compiler(CompilerContext(parseLyng(source)),importProvider).parseScript()
} }
private var lastPriority = 0 private var lastPriority = 0
@ -1747,7 +1742,7 @@ class Compiler(
allOps.filter { it.priority == l }.associateBy { it.tokenType } allOps.filter { it.priority == l }.associateBy { it.tokenType }
} }
suspend fun compile(code: String): Script = compile(Source("<eval>", code), Script.defaultImportManager) suspend fun compile(code: String): Script = compile(Source("<eval>", code))
/** /**
* The keywords that stop processing of expression term * The keywords that stop processing of expression term

View File

@ -7,7 +7,7 @@ import net.sergeych.lyng.pacman.ImportProvider
* used in [Compiler]; * used in [Compiler];
*/ */
class ModuleScope( class ModuleScope(
var importProvider: ImportProvider, val importProvider: ImportProvider,
pos: Pos = Pos.builtIn, pos: Pos = Pos.builtIn,
override val packageName: String override val packageName: String
) : Scope(importProvider.rootScope, Arguments.EMPTY, pos) { ) : Scope(importProvider.rootScope, Arguments.EMPTY, pos) {
@ -29,17 +29,9 @@ class ModuleScope(
?.also { symbolsToImport!!.remove(it) } ?.also { symbolsToImport!!.remove(it) }
?: scope.raiseError("internal error: symbol $symbol not found though the module is cached") ?: scope.raiseError("internal error: symbol $symbol not found though the module is cached")
} ?: symbol } ?: symbol
val existing = scope.objects[newName] if (newName in scope.objects)
if (existing != null ) { scope.raiseError("symbol $newName already exists, redefinition on import is not allowed")
if (existing.importedFrom != record.importedFrom) scope.objects[newName] = record
scope.raiseError("symbol ${existing.importedFrom?.packageName}.$newName already exists, redefinition on import is not allowed")
// already imported
}
else {
// when importing records, we keep track of its package (not otherwise needed)
if (record.importedFrom == null) record.importedFrom = this
scope.objects[newName] = record
}
} }
} }
if (!symbolsToImport.isNullOrEmpty()) if (!symbolsToImport.isNullOrEmpty())

View File

@ -15,13 +15,8 @@ import kotlin.contracts.ExperimentalContracts
data class ObjRecord( data class ObjRecord(
var value: Obj, var value: Obj,
val isMutable: Boolean, val isMutable: Boolean,
val visibility: Visibility = Visibility.Public, val visibility: Visibility = Visibility.Public
var importedFrom: Scope? = null )
) {
@Suppress("unused")
fun qualifiedName(name: String): String =
"${importedFrom?.packageName ?: "anonymous"}.$name"
}
/** /**
* When we need read-write access to an object in some abstract storage, we need Accessor, * When we need read-write access to an object in some abstract storage, we need Accessor,

View File

@ -1,16 +1,15 @@
package net.sergeych.lyng package net.sergeych.lyng
import net.sergeych.lyng.pacman.ImportManager import net.sergeych.lyng.pacman.ImportManager
import net.sergeych.lyng.pacman.ImportProvider
/** /**
* Scope is where local variables and methods are stored. Scope is also a parent scope for other scopes. * Scope is where local variables and methods are stored. Scope is also a parent scope for other scopes.
* Each block usually creates a scope. Accessing Lyng closures usually is done via a scope. * Each block usually creates a scope. Accessing Lyng closures usually is done via a scope.
* *
* To create default scope, use default `Scope()` constructor, it will create a scope with a parent * To create default scope, use default `Scope()` constructor, it will create a scope with a parent
* module scope with default [ImportManager], you can access with [currentImportProvider] as needed. * module scope with default [ImportManager], you can access with [importManager] as needed.
* *
* If you want to create [ModuleScope] by hand, try [currentImportProvider] and [ImportManager.newModule], * If you want to create [ModuleScope] by hand, try [importManager] and [ImportManager.newModule],
* or [ImportManager.newModuleAt]. * or [ImportManager.newModuleAt].
* *
* There are special types of scopes: * There are special types of scopes:
@ -30,7 +29,7 @@ open class Scope(
args: Arguments = Arguments.EMPTY, args: Arguments = Arguments.EMPTY,
pos: Pos = Pos.builtIn, pos: Pos = Pos.builtIn,
) )
: this(Script.defaultImportManager.copy().newModuleAt(pos), args, pos) : this(Script.defaultImportManager.newModuleAt(pos), args, pos)
fun raiseNotImplemented(what: String = "operation"): Nothing = raiseError("$what is not implemented") fun raiseNotImplemented(what: String = "operation"): Nothing = raiseError("$what is not implemented")
@ -142,12 +141,12 @@ open class Scope(
fun addConst(name: String, value: Obj) = addItem(name, false, value) fun addConst(name: String, value: Obj) = addItem(name, false, value)
suspend fun eval(code: String): Obj = suspend fun eval(code: String): Obj =
Compiler.compile(code.toSource(), currentImportProvider).execute(this) Compiler.compile(code.toSource()).execute(this)
suspend fun eval(source: Source): Obj = suspend fun eval(source: Source): Obj =
Compiler.compile( Compiler.compile(
source, source,
currentImportProvider (this as? ModuleScope)?.importProvider ?: Script.defaultImportManager
).execute(this) ).execute(this)
fun containsLocal(name: String): Boolean = name in objects fun containsLocal(name: String): Boolean = name in objects
@ -169,19 +168,10 @@ open class Scope(
* @throws IllegalStateException if there is no such manager (if you create some specific scope with no manager, * @throws IllegalStateException if there is no such manager (if you create some specific scope with no manager,
* then you knew what you did) * then you knew what you did)
*/ */
val currentImportProvider: ImportProvider by lazy { val importManager: ImportManager by lazy {
if (this is ModuleScope) if( this is ModuleScope )
importProvider.getActualProvider() (importProvider as? ImportManager)?.let { return@lazy it }
else parent?.importManager ?: throw IllegalStateException("this scope has no manager in the chain")
parent?.currentImportProvider ?: throw IllegalStateException("this scope has no manager in the chain")
} }
val importManager by lazy { (currentImportProvider as? ImportManager)
?: throw IllegalStateException("this scope has no manager in the chain (provided $currentImportProvider") }
companion object {
fun new(): Scope =
Script.defaultImportManager.copy().newModuleAt(Pos.builtIn)
}
} }

View File

@ -19,8 +19,6 @@ class ImportManager(
securityManager: SecurityManager = SecurityManager.allowAll securityManager: SecurityManager = SecurityManager.allowAll
) : ImportProvider(rootScope, securityManager) { ) : ImportProvider(rootScope, securityManager) {
val packageNames: List<String> get() = imports.keys.toList()
private inner class Entry( private inner class Entry(
val packageName: String, val packageName: String,
val builder: suspend (ModuleScope) -> Unit, val builder: suspend (ModuleScope) -> Unit,
@ -45,10 +43,6 @@ class ImportManager(
override suspend fun createModuleScope(pos: Pos, packageName: String): ModuleScope { override suspend fun createModuleScope(pos: Pos, packageName: String): ModuleScope {
return doImport(packageName, pos) return doImport(packageName, pos)
} }
override fun getActualProvider(): ImportProvider {
return this@ImportManager
}
} }
/** /**
@ -101,7 +95,6 @@ class ImportManager(
*/ */
private suspend fun doImport(packageName: String, pos: Pos): ModuleScope { private suspend fun doImport(packageName: String, pos: Pos): ModuleScope {
val entry = imports[packageName] ?: throw ImportException(pos, "package not found: $packageName") val entry = imports[packageName] ?: throw ImportException(pos, "package not found: $packageName")
println("import enrty found: $packageName")
return entry.getScope(pos) return entry.getScope(pos)
} }
@ -132,11 +125,4 @@ class ImportManager(
} }
} }
fun copy(): ImportManager =
op.withLock {
ImportManager(rootScope, securityManager).apply {
imports.putAll(this@ImportManager.imports)
}
}
} }

View File

@ -14,9 +14,6 @@ abstract class ImportProvider(
val rootScope: Scope, val rootScope: Scope,
val securityManager: SecurityManager = SecurityManager.allowAll val securityManager: SecurityManager = SecurityManager.allowAll
) { ) {
open fun getActualProvider() = this
/** /**
* Find an import and create a scope for it. This method must implement caching so repeated * Find an import and create a scope for it. This method must implement caching so repeated
* imports are not repeatedly loaded and parsed and should be cheap. * imports are not repeatedly loaded and parsed and should be cheap.

View File

@ -2443,7 +2443,7 @@ class ScriptTest {
@Test @Test
fun testDefaultImportManager() = runTest { fun testDefaultImportManager() = runTest {
val scope = Scope.new() val scope = Scope()
assertFails { assertFails {
scope.eval(""" scope.eval("""
import foo import foo
@ -2574,42 +2574,4 @@ class ScriptTest {
) )
} }
@Test
fun testDoubleImports() = runTest {
val s = Scope.new()
println(Script.defaultImportManager.packageNames)
println(s.importManager.packageNames)
s.importManager.addTextPackages("""
package foo
import lyng.time
fun foo() {
println("foo: %s"(Instant()))
}
""".trimIndent())
s.importManager.addTextPackages("""
package bar
import lyng.time
fun bar() {
println("bar: %s"(Instant()))
}
""".trimIndent())
println(s.importManager.packageNames)
s.eval("""
import foo
import bar
foo()
bar()
""".trimIndent())
}
} }