diff --git a/libraries/scripting/common/src/kotlin/script/experimental/util/propertiesCollection.kt b/libraries/scripting/common/src/kotlin/script/experimental/util/propertiesCollection.kt index 72c0f7943ed..045d862feb2 100644 --- a/libraries/scripting/common/src/kotlin/script/experimental/util/propertiesCollection.kt +++ b/libraries/scripting/common/src/kotlin/script/experimental/util/propertiesCollection.kt @@ -11,7 +11,7 @@ import kotlin.reflect.KProperty import kotlin.reflect.KType import kotlin.script.experimental.api.KotlinType -open class PropertiesCollection(private val properties: Map, Any> = emptyMap()) : Serializable { +open class PropertiesCollection(private val properties: Map, Any?> = emptyMap()) : Serializable { class Key(val name: String, @Transient val defaultValue: T? = null) : Serializable { @@ -36,13 +36,17 @@ open class PropertiesCollection(private val properties: Map, Any> = empty @Suppress("UNCHECKED_CAST") operator fun get(key: PropertiesCollection.Key): T? = - properties[key]?.let { it as T } ?: key.defaultValue + if (key.defaultValue == null) properties[key] as T? + else properties.getOrDefault(key, key.defaultValue) as T? @Suppress("UNCHECKED_CAST") fun getNoDefault(key: PropertiesCollection.Key): T? = properties[key]?.let { it as T } - fun entries(): Set, Any>> = properties.entries + fun containsKey(key: PropertiesCollection.Key): Boolean = + properties.containsKey(key) + + fun entries(): Set, Any?>> = properties.entries companion object { fun key(defaultValue: T? = null) = PropertyKeyDelegate(defaultValue) @@ -56,13 +60,13 @@ open class PropertiesCollection(private val properties: Map, Any> = empty open class Builder(baseProperties: Iterable = emptyList()) { - val data: MutableMap, Any> = LinkedHashMap, Any>().apply { + val data: MutableMap, Any?> = LinkedHashMap, Any?>().apply { baseProperties.forEach { putAll(it.properties) } } // generic for all properties - operator fun PropertiesCollection.Key.invoke(v: T) { + operator fun PropertiesCollection.Key.invoke(v: T) { data[this] = v } @@ -137,10 +141,14 @@ open class PropertiesCollection(private val properties: Map, Any> = empty // direct manipulation - public - for usage in inline dsl methods and for extending dsl - operator fun set(key: PropertiesCollection.Key, value: T) { + operator fun set(key: PropertiesCollection.Key, value: T) { data[key] = value } + fun reset(key: PropertiesCollection.Key) { + data.remove(key) + } + @Suppress("UNCHECKED_CAST") operator fun get(key: PropertiesCollection.Key): T? = data[key]?.let { it as T } diff --git a/libraries/scripting/jvm-host/src/kotlin/script/experimental/jvmhost/impl/CompiledScriptClassLoader.kt b/libraries/scripting/jvm-host/src/kotlin/script/experimental/jvmhost/impl/CompiledScriptClassLoader.kt index 6e153348188..5536523e712 100644 --- a/libraries/scripting/jvm-host/src/kotlin/script/experimental/jvmhost/impl/CompiledScriptClassLoader.kt +++ b/libraries/scripting/jvm-host/src/kotlin/script/experimental/jvmhost/impl/CompiledScriptClassLoader.kt @@ -11,7 +11,7 @@ import java.io.InputStream import java.net.URL import java.util.* -internal class CompiledScriptClassLoader(parent: ClassLoader, private val entries: Map) : ClassLoader(parent) { +internal class CompiledScriptClassLoader(parent: ClassLoader?, private val entries: Map) : ClassLoader(parent) { override fun findClass(name: String): Class<*>? { val classPathName = name.replace('.', '/') + ".class" diff --git a/libraries/scripting/jvm-host/src/kotlin/script/experimental/jvmhost/impl/KJvmCompiledScript.kt b/libraries/scripting/jvm-host/src/kotlin/script/experimental/jvmhost/impl/KJvmCompiledScript.kt index d0041f3fbe4..ea88aecf9db 100644 --- a/libraries/scripting/jvm-host/src/kotlin/script/experimental/jvmhost/impl/KJvmCompiledScript.kt +++ b/libraries/scripting/jvm-host/src/kotlin/script/experimental/jvmhost/impl/KJvmCompiledScript.kt @@ -13,9 +13,7 @@ import java.net.URLClassLoader import kotlin.reflect.KClass import kotlin.script.experimental.api.* import kotlin.script.experimental.jvm.JvmDependency -import kotlin.script.experimental.jvmhost.JvmScriptEvaluationConfiguration -import kotlin.script.experimental.jvmhost.actualClassLoader -import kotlin.script.experimental.jvmhost.baseClassLoader +import kotlin.script.experimental.jvmhost.* class KJvmCompiledModule( generationState: GenerationState @@ -54,12 +52,15 @@ class KJvmCompiledScript( get() = _otherScripts override suspend fun getClass(scriptEvaluationConfiguration: ScriptEvaluationConfiguration?): ResultWithDiagnostics> = try { - val classLoader = scriptEvaluationConfiguration?.get(JvmScriptEvaluationConfiguration.actualClassLoader) + // ensuring proper defaults are used + val actualEvaluationConfiguration = scriptEvaluationConfiguration ?: ScriptEvaluationConfiguration() + val classLoader = actualEvaluationConfiguration[ScriptEvaluationConfiguration.jvm.actualClassLoader] ?: run { if (compiledModule == null) - return ResultWithDiagnostics.Failure("Unable to load class $scriptClassFQName: no compiled module is provided".asErrorDiagnostics(path = sourceLocationId)) - val baseClassLoader = scriptEvaluationConfiguration?.get(JvmScriptEvaluationConfiguration.baseClassLoader) - ?: Thread.currentThread().contextClassLoader + return ResultWithDiagnostics.Failure( + "Unable to load class $scriptClassFQName: no compiled module is provided".asErrorDiagnostics(path = sourceLocationId) + ) + val baseClassLoader = actualEvaluationConfiguration[ScriptEvaluationConfiguration.jvm.baseClassLoader] val dependencies = compilationConfiguration[ScriptCompilationConfiguration.dependencies] ?.flatMap { (it as? JvmDependency)?.classpath?.map { it.toURI().toURL() } ?: emptyList() } // TODO: previous dependencies and classloaders should be taken into account here diff --git a/libraries/scripting/jvm-host/src/kotlin/script/experimental/jvmhost/jvmScriptEvaluation.kt b/libraries/scripting/jvm-host/src/kotlin/script/experimental/jvmhost/jvmScriptEvaluation.kt index f2e68c30263..e47858972ea 100644 --- a/libraries/scripting/jvm-host/src/kotlin/script/experimental/jvmhost/jvmScriptEvaluation.kt +++ b/libraries/scripting/jvm-host/src/kotlin/script/experimental/jvmhost/jvmScriptEvaluation.kt @@ -10,16 +10,18 @@ package kotlin.script.experimental.jvmhost import kotlin.script.experimental.api.* import kotlin.script.experimental.util.PropertiesCollection -open class JvmScriptEvaluationConfiguration : PropertiesCollection.Builder() { +interface JvmScriptEvaluationConfigurationKeys - companion object : JvmScriptEvaluationConfiguration() +open class JvmScriptEvaluationConfigurationBuilder : PropertiesCollection.Builder(), JvmScriptEvaluationConfigurationKeys { + + companion object : JvmScriptEvaluationConfigurationBuilder() } -val JvmScriptEvaluationConfiguration.baseClassLoader by PropertiesCollection.key(Thread.currentThread().contextClassLoader) +val JvmScriptEvaluationConfigurationKeys.baseClassLoader by PropertiesCollection.key(Thread.currentThread().contextClassLoader) -val JvmScriptEvaluationConfiguration.actualClassLoader by PropertiesCollection.key() +val JvmScriptEvaluationConfigurationKeys.actualClassLoader by PropertiesCollection.key() -val ScriptEvaluationConfiguration.jvm get() = JvmScriptEvaluationConfiguration() +val ScriptEvaluationConfigurationKeys.jvm get() = JvmScriptEvaluationConfigurationBuilder() open class BasicJvmScriptEvaluator : ScriptEvaluator { @@ -28,27 +30,23 @@ open class BasicJvmScriptEvaluator : ScriptEvaluator { scriptEvaluationConfiguration: ScriptEvaluationConfiguration? ): ResultWithDiagnostics = try { - compiledScript.getClass(scriptEvaluationConfiguration).onSuccess { scriptClass -> + val actualEvaluationConfiguration = scriptEvaluationConfiguration ?: ScriptEvaluationConfiguration() + compiledScript.getClass(actualEvaluationConfiguration).onSuccess { scriptClass -> // in the future, when (if) we'll stop to compile everything into constructor // run as SAM // return res // for other scripts we need evaluation configuration with actualClassloader set, // so they are loaded in the same classloader as the "main" script - val updatedEvalConfiguration = when { - scriptEvaluationConfiguration == null -> ScriptEvaluationConfiguration { - // TODO: find out why dsl syntax doesn't work here - set(JvmScriptEvaluationConfiguration.actualClassLoader, scriptClass.java.classLoader) - } - scriptEvaluationConfiguration.getNoDefault(JvmScriptEvaluationConfiguration.actualClassLoader) == null -> - ScriptEvaluationConfiguration(scriptEvaluationConfiguration) { - // TODO: find out why dsl syntax doesn't work here - set(JvmScriptEvaluationConfiguration.actualClassLoader, scriptClass.java.classLoader) + val updatedEvalConfiguration = + if (actualEvaluationConfiguration.containsKey(ScriptEvaluationConfiguration.jvm.actualClassLoader)) + actualEvaluationConfiguration + else + ScriptEvaluationConfiguration(actualEvaluationConfiguration) { + ScriptEvaluationConfiguration.jvm.actualClassLoader(scriptClass.java.classLoader) } - else -> scriptEvaluationConfiguration - } - val sharedScripts = scriptEvaluationConfiguration?.get(ScriptEvaluationConfiguration.scriptsInstancesSharingMap) + val sharedScripts = actualEvaluationConfiguration[ScriptEvaluationConfiguration.scriptsInstancesSharingMap] val instanceFromShared = sharedScripts?.get(scriptClass) @@ -61,10 +59,10 @@ open class BasicJvmScriptEvaluator : ScriptEvaluator { updatedEvalConfiguration[ScriptEvaluationConfiguration.constructorArgs]?.let { args.addAll(it) } - scriptEvaluationConfiguration?.get(ScriptEvaluationConfiguration.providedProperties)?.forEach { + actualEvaluationConfiguration[ScriptEvaluationConfiguration.providedProperties]?.forEach { args.add(it.value) } - scriptEvaluationConfiguration?.get(ScriptEvaluationConfiguration.implicitReceivers)?.let { + actualEvaluationConfiguration[ScriptEvaluationConfiguration.implicitReceivers]?.let { args.addAll(it) }