From a54675abe75bd6f53b01e183653f88002d339b20 Mon Sep 17 00:00:00 2001 From: Ilya Chernikov Date: Fri, 13 Jul 2018 19:05:37 +0200 Subject: [PATCH] Clean and fix new scripting API --- .../core/script/ScriptDefinitionsManager.kt | 2 +- .../examples/jvm/resolve/maven/host/host.kt | 12 +++---- .../script/examples/jvm/simple/host/host.kt | 12 +++---- .../experimental/api/scriptCompilation.kt | 4 +-- .../experimental/api/scriptConfiguration.kt | 2 +- .../api/scriptConfigurationProperties.kt | 2 +- .../experimental/api/scriptDefinition.kt | 13 +++++-- .../experimental/api/scriptEvaluation.kt | 2 +- .../experimental/api/scriptingEnvironment.kt | 8 ----- .../script/experimental/basic/basicScript.kt | 6 ++-- .../definitions/definitionFromAnnotation.kt | 36 +++++++++---------- .../experimental/host/BasicScriptingHost.kt | 5 +-- .../script/experimental/util/propertyBag.kt | 16 +++++++-- .../jvmhost/impl/KJVMCompilerImpl.kt | 28 ++++++++------- .../jvm/impl/BridgeDependenciesResolver.kt | 15 ++++---- .../experimental/jvm/jvmScriptCompilation.kt | 14 ++++---- .../experimental/jvm/jvmScriptEvaluation.kt | 4 +-- ...KotlinScriptDefinitionAdapterFromNewAPI.kt | 21 ++++++----- ...LazyScriptDefinitionFromDiscoveredClass.kt | 2 +- ...DefinitionsFromClasspathDiscoverySource.kt | 2 +- 20 files changed, 111 insertions(+), 95 deletions(-) diff --git a/idea/idea-core/src/org/jetbrains/kotlin/idea/core/script/ScriptDefinitionsManager.kt b/idea/idea-core/src/org/jetbrains/kotlin/idea/core/script/ScriptDefinitionsManager.kt index dcd6b9ce7b0..cf926707ff0 100644 --- a/idea/idea-core/src/org/jetbrains/kotlin/idea/core/script/ScriptDefinitionsManager.kt +++ b/idea/idea-core/src/org/jetbrains/kotlin/idea/core/script/ScriptDefinitionsManager.kt @@ -210,8 +210,8 @@ fun loadDefinitionsFromTemplates( template.annotations.firstIsInstanceOrNull() != null -> { KotlinScriptDefinitionAdapterFromNewAPI( ScriptDefinitionFromAnnotatedBaseClass( + KotlinType(template), ScriptingEnvironment( - ScriptingEnvironmentProperties.baseClass to KotlinType(template), ScriptingEnvironmentProperties.configurationDependencies to listOf(JvmDependency(classpath)), ScriptingEnvironmentProperties.getScriptingClass to JvmGetScriptingClass() ) diff --git a/libraries/examples/scripting/jvm-maven-deps/host/src/org/jetbrains/kotlin/script/examples/jvm/resolve/maven/host/host.kt b/libraries/examples/scripting/jvm-maven-deps/host/src/org/jetbrains/kotlin/script/examples/jvm/resolve/maven/host/host.kt index f3426a58273..d8d2acf6799 100644 --- a/libraries/examples/scripting/jvm-maven-deps/host/src/org/jetbrains/kotlin/script/examples/jvm/resolve/maven/host/host.kt +++ b/libraries/examples/scripting/jvm-maven-deps/host/src/org/jetbrains/kotlin/script/examples/jvm/resolve/maven/host/host.kt @@ -21,19 +21,17 @@ import kotlin.script.experimental.misc.* fun evalFile(scriptFile: File): ResultWithDiagnostics { val scriptCompiler = JvmScriptCompiler(KJVMCompilerImpl(), DummyCompiledJvmScriptCache()) val scriptDefinition = ScriptDefinitionFromAnnotatedBaseClass( + KotlinType(MyScriptWithMavenDeps::class), ScriptingEnvironment( - ScriptingEnvironmentProperties.baseClass(), ScriptingEnvironmentProperties.getScriptingClass(JvmGetScriptingClass()) ) ) - val host = JvmBasicScriptingHost( - scriptDefinition.compilationConfigurator, - scriptCompiler, - scriptDefinition.evaluator - ) + val host = JvmBasicScriptingHost(scriptCompiler, scriptDefinition.evaluator) - return host.eval(scriptFile.toScriptSource(), ScriptCompileConfiguration(myJvmConfigParams), ScriptEvaluationEnvironment()) + return host.eval( + scriptFile.toScriptSource(), scriptDefinition, ScriptCompileConfiguration(myJvmConfigParams), ScriptEvaluationEnvironment() + ) } fun main(vararg args: String) { diff --git a/libraries/examples/scripting/jvm-simple-script/host/src/org/jetbrains/kotlin/script/examples/jvm/simple/host/host.kt b/libraries/examples/scripting/jvm-simple-script/host/src/org/jetbrains/kotlin/script/examples/jvm/simple/host/host.kt index 31f13fd9018..4f77c7aeffc 100644 --- a/libraries/examples/scripting/jvm-simple-script/host/src/org/jetbrains/kotlin/script/examples/jvm/simple/host/host.kt +++ b/libraries/examples/scripting/jvm-simple-script/host/src/org/jetbrains/kotlin/script/examples/jvm/simple/host/host.kt @@ -25,19 +25,17 @@ val myJvmConfigParams = jvmJavaHomeParams + with(ScriptCompileConfigurationPrope fun evalFile(scriptFile: File): ResultWithDiagnostics { val scriptCompiler = JvmScriptCompiler(KJVMCompilerImpl(), DummyCompiledJvmScriptCache()) val scriptDefinition = ScriptDefinitionFromAnnotatedBaseClass( + KotlinType(MyScript::class), ScriptingEnvironment( - ScriptingEnvironmentProperties.baseClass(), ScriptingEnvironmentProperties.getScriptingClass(JvmGetScriptingClass()) ) ) - val host = JvmBasicScriptingHost( - scriptDefinition.compilationConfigurator, - scriptCompiler, - scriptDefinition.evaluator - ) + val host = JvmBasicScriptingHost(scriptCompiler, scriptDefinition.evaluator) - return host.eval(scriptFile.toScriptSource(), ScriptCompileConfiguration(myJvmConfigParams), ScriptEvaluationEnvironment()) + return host.eval( + scriptFile.toScriptSource(), scriptDefinition, ScriptCompileConfiguration(myJvmConfigParams), ScriptEvaluationEnvironment() + ) } fun main(vararg args: String) { diff --git a/libraries/scripting/common/src/kotlin/script/experimental/api/scriptCompilation.kt b/libraries/scripting/common/src/kotlin/script/experimental/api/scriptCompilation.kt index 42c66258b3c..361638f1e77 100644 --- a/libraries/scripting/common/src/kotlin/script/experimental/api/scriptCompilation.kt +++ b/libraries/scripting/common/src/kotlin/script/experimental/api/scriptCompilation.kt @@ -9,8 +9,8 @@ interface ScriptCompiler { suspend fun compile( script: ScriptSource, - configurator: ScriptCompilationConfigurator? = null, - additionalConfiguration: ScriptCompileConfiguration? = null // overrides parameters from configurator.defaultConfiguration + scriptDefinition: ScriptDefinition, + additionalConfiguration: ScriptCompileConfiguration? = null // overrides properties from definition and configurator.defaultConfiguration ): ResultWithDiagnostics> } diff --git a/libraries/scripting/common/src/kotlin/script/experimental/api/scriptConfiguration.kt b/libraries/scripting/common/src/kotlin/script/experimental/api/scriptConfiguration.kt index 6da768e156e..8d2469020c0 100644 --- a/libraries/scripting/common/src/kotlin/script/experimental/api/scriptConfiguration.kt +++ b/libraries/scripting/common/src/kotlin/script/experimental/api/scriptConfiguration.kt @@ -17,7 +17,7 @@ typealias ProcessedScriptData = ChainedPropertyBag interface ScriptCompilationConfigurator { - // constructor(environment: ScriptingEnvironment) // the constructor is expected from implementations + // constructor(properties: ScriptDefinitionPropertiesBag) // the constructor is expected from implementations val defaultConfiguration: ScriptCompileConfiguration diff --git a/libraries/scripting/common/src/kotlin/script/experimental/api/scriptConfigurationProperties.kt b/libraries/scripting/common/src/kotlin/script/experimental/api/scriptConfigurationProperties.kt index ab91d0a20ae..60f0ea39e17 100644 --- a/libraries/scripting/common/src/kotlin/script/experimental/api/scriptConfigurationProperties.kt +++ b/libraries/scripting/common/src/kotlin/script/experimental/api/scriptConfigurationProperties.kt @@ -13,7 +13,7 @@ object ScriptCompileConfigurationProperties { val sourceFragments by typedKey>() - val baseClass = ScriptingEnvironmentProperties.baseClass + val baseClass = ScriptDefinitionProperties.baseClass val scriptBodyTarget by typedKey() diff --git a/libraries/scripting/common/src/kotlin/script/experimental/api/scriptDefinition.kt b/libraries/scripting/common/src/kotlin/script/experimental/api/scriptDefinition.kt index d2d83a55285..411637310e3 100644 --- a/libraries/scripting/common/src/kotlin/script/experimental/api/scriptDefinition.kt +++ b/libraries/scripting/common/src/kotlin/script/experimental/api/scriptDefinition.kt @@ -7,6 +7,7 @@ package kotlin.script.experimental.api +import kotlin.reflect.KClass import kotlin.script.experimental.util.ChainedPropertyBag import kotlin.script.experimental.util.typedKey @@ -18,7 +19,7 @@ interface ScriptDefinition { val properties: ScriptDefinitionPropertiesBag - val compilationConfigurator: ScriptCompilationConfigurator + val compilationConfigurator: ScriptCompilationConfigurator? val evaluator: ScriptEvaluator<*>? } @@ -28,4 +29,12 @@ object ScriptDefinitionProperties { val name by typedKey() // Name of the script type, by default "Kotlin script" val fileExtension by typedKey() // default: "kts" -} \ No newline at end of file + + val baseClass by typedKey() // script base class +} + +fun ScriptDefinitionPropertiesBag.getScriptBaseClass(contextClass: KClass<*>): KClass<*> = + getScriptingClass(get(ScriptDefinitionProperties.baseClass), contextClass) + +fun ScriptDefinitionPropertiesBag.getScriptBaseClass(context: Any): KClass<*> = + getScriptingClass(get(ScriptDefinitionProperties.baseClass), context::class) diff --git a/libraries/scripting/common/src/kotlin/script/experimental/api/scriptEvaluation.kt b/libraries/scripting/common/src/kotlin/script/experimental/api/scriptEvaluation.kt index d1d9a7495b1..f6989f9c13c 100644 --- a/libraries/scripting/common/src/kotlin/script/experimental/api/scriptEvaluation.kt +++ b/libraries/scripting/common/src/kotlin/script/experimental/api/scriptEvaluation.kt @@ -27,7 +27,7 @@ data class EvaluationResult(val returnValue: Any?, val environment: ScriptEvalua // NOTE: name inconsistency: run vs evaluate interface ScriptEvaluator { - // constructor(environment: ScriptingEnvironment) // the constructor is expected from implementations + // constructor(properties: ScriptDefinitionPropertiesBag) // the constructor is expected from implementations suspend fun eval( compiledScript: CompiledScript, diff --git a/libraries/scripting/common/src/kotlin/script/experimental/api/scriptingEnvironment.kt b/libraries/scripting/common/src/kotlin/script/experimental/api/scriptingEnvironment.kt index ec17b1e7bc9..3df21bda6c6 100644 --- a/libraries/scripting/common/src/kotlin/script/experimental/api/scriptingEnvironment.kt +++ b/libraries/scripting/common/src/kotlin/script/experimental/api/scriptingEnvironment.kt @@ -13,9 +13,6 @@ typealias ScriptingEnvironment = ChainedPropertyBag object ScriptingEnvironmentProperties { - // required by definitions that extract data from script base class annotations - val baseClass by typedKey() - // should contain all dependencies needed for baseClass and compilationConfigurator val configurationDependencies by typedKey>() @@ -40,8 +37,3 @@ fun ScriptingEnvironment.getScriptingClass(type: KotlinType, contextClass: KClas fun ScriptingEnvironment.getScriptingClass(type: KotlinType, context: Any): KClass<*> = getScriptingClass(type, context::class) -fun ScriptingEnvironment.getScriptBaseClass(contextClass: KClass<*>): KClass<*> = - getScriptingClass(get(ScriptingEnvironmentProperties.baseClass), contextClass) - -fun ScriptingEnvironment.getScriptBaseClass(context: Any): KClass<*> = - getScriptingClass(get(ScriptingEnvironmentProperties.baseClass), context::class) diff --git a/libraries/scripting/common/src/kotlin/script/experimental/basic/basicScript.kt b/libraries/scripting/common/src/kotlin/script/experimental/basic/basicScript.kt index 787473c86a9..bcf4660ad77 100644 --- a/libraries/scripting/common/src/kotlin/script/experimental/basic/basicScript.kt +++ b/libraries/scripting/common/src/kotlin/script/experimental/basic/basicScript.kt @@ -13,10 +13,10 @@ import kotlin.script.experimental.util.TypedKey private const val ILLEGAL_CONFIG_ANN_ARG = "Illegal argument to KotlinScriptDefaultCompilationConfiguration annotation: expecting List-derived object or default-constructed class of configuration parameters" -open class AnnotationsBasedCompilationConfigurator(val environment: ScriptingEnvironment) : ScriptCompilationConfigurator { +open class AnnotationsBasedCompilationConfigurator(val properties: ScriptDefinitionPropertiesBag) : ScriptCompilationConfigurator { override val defaultConfiguration by lazy(LazyThreadSafetyMode.PUBLICATION) { - val baseClass = environment.getScriptBaseClass(this) + val baseClass = properties.getScriptBaseClass(this) val cfg = baseClass.annotations.filterIsInstance(KotlinScriptDefaultCompilationConfiguration::class.java).flatMap { ann -> val params = try { ann.compilationConfiguration.objectInstance ?: ann.compilationConfiguration.createInstance() @@ -29,7 +29,7 @@ open class AnnotationsBasedCompilationConfigurator(val environment: ScriptingEnv } params as List, Any?>> } - ScriptCompileConfiguration(environment, cfg) + ScriptCompileConfiguration(properties, cfg) } } diff --git a/libraries/scripting/common/src/kotlin/script/experimental/definitions/definitionFromAnnotation.kt b/libraries/scripting/common/src/kotlin/script/experimental/definitions/definitionFromAnnotation.kt index 0cd44d0b5fe..a25fa6cbdbd 100644 --- a/libraries/scripting/common/src/kotlin/script/experimental/definitions/definitionFromAnnotation.kt +++ b/libraries/scripting/common/src/kotlin/script/experimental/definitions/definitionFromAnnotation.kt @@ -13,52 +13,52 @@ import kotlin.script.experimental.api.* import kotlin.script.experimental.basic.AnnotationsBasedCompilationConfigurator import kotlin.script.experimental.basic.DummyEvaluator import kotlin.script.experimental.util.TypedKey +import kotlin.script.experimental.util.chainPropertyBags private const val ERROR_MSG_PREFIX = "Unable to construct script definition: " -open class ScriptDefinitionFromAnnotatedBaseClass(val environment: ScriptingEnvironment) : ScriptDefinition { +open class ScriptDefinitionFromAnnotatedBaseClass( + protected val baseClassType: KotlinType, + val environment: ScriptingEnvironment +) : ScriptDefinition { private val getScriptingClass = environment.getOrNull(ScriptingEnvironmentProperties.getScriptingClass) - ?: throw IllegalArgumentException("${ERROR_MSG_PREFIX}Expecting 'getScriptingClass' parameter in the scripting environment") + ?: throw IllegalArgumentException("${ERROR_MSG_PREFIX}Expecting 'getScriptingClass' parameter in the scripting environment") - private val baseClass: KClass<*> = run { - val baseClassType = environment.getOrNull(ScriptingEnvironmentProperties.baseClass) - ?: throw IllegalArgumentException("${ERROR_MSG_PREFIX}Expecting 'baseClass' parameter in the scripting environment") + private val baseClass: KClass<*> = try { getScriptingClass(baseClassType, this::class, environment) } catch (e: Throwable) { throw IllegalArgumentException("${ERROR_MSG_PREFIX}Unable to load base class $baseClassType", e) } - } private val mainAnnotation = baseClass.findAnnotation() - ?: throw IllegalArgumentException("${ERROR_MSG_PREFIX}Expecting KotlinScript annotation on the $baseClass") + ?: throw IllegalArgumentException("${ERROR_MSG_PREFIX}Expecting KotlinScript annotation on the $baseClass") private val explicitDefinition: ScriptDefinition? = baseClass.findAnnotation()?.definition.takeIf { it != this::class }?.let { it.instantiateScriptHandler() } override val properties = run { - val baseProperties = explicitDefinition?.properties ?: environment - val toAdd = arrayListOf, Any>>() + val baseProperties = chainPropertyBags(explicitDefinition?.properties, environment) + val propertiesData = arrayListOf, Any>>(ScriptDefinitionProperties.baseClass to baseClassType) baseClass.findAnnotation()?.let { - toAdd += ScriptDefinitionProperties.fileExtension to it.extension + propertiesData += ScriptDefinitionProperties.fileExtension to it.extension } if (baseProperties.getOrNull(ScriptDefinitionProperties.name) == null) { - toAdd += ScriptDefinitionProperties.name to mainAnnotation.name + propertiesData += ScriptDefinitionProperties.name to mainAnnotation.name } - if (toAdd.isEmpty()) baseProperties - else ScriptingEnvironment(baseProperties, toAdd) + ScriptingEnvironment(baseProperties, propertiesData) } override val compilationConfigurator = baseClass.findAnnotation()?.compilationConfigurator?.instantiateScriptHandler() - ?: explicitDefinition?.compilationConfigurator - ?: AnnotationsBasedCompilationConfigurator::class.instantiateScriptHandler() + ?: explicitDefinition?.compilationConfigurator + ?: AnnotationsBasedCompilationConfigurator::class.instantiateScriptHandler() override val evaluator = baseClass.findAnnotation()?.evaluator?.instantiateScriptHandler() - ?: explicitDefinition?.evaluator - ?: DummyEvaluator::class.instantiateScriptHandler() + ?: explicitDefinition?.evaluator + ?: DummyEvaluator::class.instantiateScriptHandler() private fun KClass.instantiateScriptHandler(): T { val klass: KClass = try { @@ -68,7 +68,7 @@ open class ScriptDefinitionFromAnnotatedBaseClass(val environment: ScriptingEnvi } try { // TODO: fix call after deciding on constructor parameters - return klass.objectInstance ?: klass.primaryConstructor!!.call(environment) + return klass.objectInstance ?: klass.primaryConstructor!!.call(properties) } catch (e: Throwable) { throw IllegalArgumentException("${ERROR_MSG_PREFIX}Unable to instantiate handler $this: $e", e) } diff --git a/libraries/scripting/common/src/kotlin/script/experimental/host/BasicScriptingHost.kt b/libraries/scripting/common/src/kotlin/script/experimental/host/BasicScriptingHost.kt index 91da2cd2bf9..97057b063d9 100644 --- a/libraries/scripting/common/src/kotlin/script/experimental/host/BasicScriptingHost.kt +++ b/libraries/scripting/common/src/kotlin/script/experimental/host/BasicScriptingHost.kt @@ -23,19 +23,20 @@ import kotlinx.coroutines.experimental.runBlocking import kotlin.script.experimental.api.* abstract class BasicScriptingHost( - val configurator: ScriptCompilationConfigurator, val compiler: ScriptCompiler, + // TODO: does it belong here or to the definition? val evaluator: ScriptEvaluator ) { open fun runInCoroutineContext(block: suspend CoroutineScope.() -> T): T = runBlocking { block() } open fun eval( script: ScriptSource, + scriptDefinition: ScriptDefinition, compileConfiguration: ScriptCompileConfiguration, environment: ScriptEvaluationEnvironment ): ResultWithDiagnostics = runInCoroutineContext { - val compiled = compiler.compile(script, configurator, compileConfiguration) + val compiled = compiler.compile(script, scriptDefinition, compileConfiguration) when (compiled) { is ResultWithDiagnostics.Failure -> compiled is ResultWithDiagnostics.Success -> { diff --git a/libraries/scripting/common/src/kotlin/script/experimental/util/propertyBag.kt b/libraries/scripting/common/src/kotlin/script/experimental/util/propertyBag.kt index ee803841e59..8eeeead19b8 100644 --- a/libraries/scripting/common/src/kotlin/script/experimental/util/propertyBag.kt +++ b/libraries/scripting/common/src/kotlin/script/experimental/util/propertyBag.kt @@ -27,8 +27,8 @@ open class ChainedPropertyBag private constructor(private val parent: ChainedPro fun cloneWithNewParent(newParent: ChainedPropertyBag?): ChainedPropertyBag = when { newParent == null -> this - parent == null -> ChainedPropertyBag(newParent, data) - else -> ChainedPropertyBag(parent.cloneWithNewParent(newParent), data) + parent == null -> createOptimized(newParent, data) + else -> createOptimized(parent.cloneWithNewParent(newParent), data) } inline operator fun get(key: TypedKey): T = getRaw(key) as T @@ -38,4 +38,16 @@ open class ChainedPropertyBag private constructor(private val parent: ChainedPro inline fun getOrNull(key: TypedKey): T? = getOrNullRaw(key)?.let { it as T } fun getOrNullRaw(key: TypedKey): Any? = data[key] ?: parent?.getOrNullRaw(key) ?: key.defaultValue + + companion object { + fun createOptimized(parent: ChainedPropertyBag?, data: Map, Any?>): ChainedPropertyBag = when { + parent != null && data.isEmpty() -> parent + else -> ChainedPropertyBag(parent, data) + } + } } + +fun chainPropertyBags(propertyBags: Iterable): ChainedPropertyBag = + propertyBags.fold(ChainedPropertyBag()) { res, next -> if (next == null) res else res.cloneWithNewParent(next) } + +fun chainPropertyBags(vararg propertyBags: ChainedPropertyBag?): ChainedPropertyBag = chainPropertyBags(propertyBags.asIterable()) diff --git a/libraries/scripting/jvm-host/src/kotlin/script/experimental/jvmhost/impl/KJVMCompilerImpl.kt b/libraries/scripting/jvm-host/src/kotlin/script/experimental/jvmhost/impl/KJVMCompilerImpl.kt index 3563d9382c8..ac8b1ca5e4f 100644 --- a/libraries/scripting/jvm-host/src/kotlin/script/experimental/jvmhost/impl/KJVMCompilerImpl.kt +++ b/libraries/scripting/jvm-host/src/kotlin/script/experimental/jvmhost/impl/KJVMCompilerImpl.kt @@ -44,6 +44,7 @@ import kotlin.script.experimental.jvm.JvmScriptCompileConfigurationProperties import kotlin.script.experimental.jvm.JvmScriptEvaluationEnvironmentProperties import kotlin.script.experimental.jvm.KJVMCompilerProxy import kotlin.script.experimental.jvm.impl.BridgeDependenciesResolver +import kotlin.script.experimental.util.chainPropertyBags class KJVMCompiledScript( override val configuration: ScriptCompileConfiguration, @@ -63,7 +64,7 @@ class KJVMCompiledScript( val clazz = classLoader.loadClass(scriptClassFQName) (clazz as? ScriptBase)?.asSuccess() - ?: ResultWithDiagnostics.Failure("Compiled class expected to be a subclass of the , but got ${clazz.javaClass.name}".asErrorDiagnostics()) + ?: ResultWithDiagnostics.Failure("Compiled class expected to be a subclass of the , but got ${clazz.javaClass.name}".asErrorDiagnostics()) } catch (e: Throwable) { ResultWithDiagnostics.Failure(ScriptDiagnostic("Unable to instantiate class $scriptClassFQName", exception = e)) } @@ -73,7 +74,7 @@ class KJVMCompilerImpl : KJVMCompilerProxy { override fun compile( script: ScriptSource, - configurator: ScriptCompilationConfigurator?, + scriptDefinition: ScriptDefinition, additionalConfiguration: ScriptCompileConfiguration ): ResultWithDiagnostics> { val messageCollector = ScriptDiagnosticsMessageCollector() @@ -84,8 +85,11 @@ class KJVMCompilerImpl : KJVMCompilerProxy { try { setIdeaIoUseFallback() - val scriptCompileConfiguration = configurator?.defaultConfiguration?.let { additionalConfiguration.cloneWithNewParent(it) } - ?: additionalConfiguration + val scriptCompileConfiguration = chainPropertyBags( + additionalConfiguration, + scriptDefinition.compilationConfigurator?.defaultConfiguration, + scriptDefinition.properties + ) var environment: KotlinCoreEnvironment? = null var updatedScriptCompileConfiguration = scriptCompileConfiguration @@ -104,7 +108,7 @@ class KJVMCompilerImpl : KJVMCompilerProxy { val kotlinCompilerConfiguration = org.jetbrains.kotlin.config.CompilerConfiguration().apply { add( JVMConfigurationKeys.SCRIPT_DEFINITIONS, - BridgeScriptDefinition(scriptCompileConfiguration, configurator, ::updateClasspath) + BridgeScriptDefinition(scriptDefinition, scriptCompileConfiguration, ::updateClasspath) ) put(CLIConfigurationKeys.MESSAGE_COLLECTOR_KEY, messageCollector) put(JVMConfigurationKeys.RETAIN_OUTPUT_IN_MEMORY, true) @@ -157,7 +161,7 @@ class KJVMCompilerImpl : KJVMCompilerProxy { charset = CharsetToolkit.UTF8_CHARSET } val psiFile: KtFile = psiFileFactory.trySetupPsiForFile(virtualFile, KotlinLanguage.INSTANCE, true, false) as KtFile? - ?: return failure("Unable to make PSI file from script".asErrorDiagnostics()) + ?: return failure("Unable to make PSI file from script".asErrorDiagnostics()) val sourceFiles = listOf(psiFile) @@ -237,18 +241,18 @@ class ScriptDiagnosticsMessageCollector : MessageCollector { // A bridge to the current scripting internal class BridgeScriptDefinition( - scriptCompilerConfiguration: ScriptCompileConfiguration, - scriptConfigurator: ScriptCompilationConfigurator?, + scriptDefinition: ScriptDefinition, + calculatedBcriptCompilerConfiguration: ScriptCompileConfiguration, updateClasspath: (List) -> Unit -) : KotlinScriptDefinition(scriptCompilerConfiguration.getScriptBaseClass(BridgeScriptDefinition::class)) { +) : KotlinScriptDefinition(calculatedBcriptCompilerConfiguration.getScriptBaseClass(BridgeScriptDefinition::class)) { override val acceptedAnnotations = run { val cl = this::class.java.classLoader - scriptCompilerConfiguration.getOrNull(ScriptCompileConfigurationProperties.refineConfigurationOnAnnotations) + calculatedBcriptCompilerConfiguration.getOrNull(ScriptCompileConfigurationProperties.refineConfigurationOnAnnotations) ?.map { (cl.loadClass(it.typeName) as Class).kotlin } - ?: emptyList() + ?: emptyList() } override val dependencyResolver: DependenciesResolver = - BridgeDependenciesResolver(scriptConfigurator, scriptCompilerConfiguration, updateClasspath) + BridgeDependenciesResolver(scriptDefinition, calculatedBcriptCompilerConfiguration, updateClasspath) } diff --git a/libraries/scripting/jvm/src/kotlin/script/experimental/jvm/impl/BridgeDependenciesResolver.kt b/libraries/scripting/jvm/src/kotlin/script/experimental/jvm/impl/BridgeDependenciesResolver.kt index 54a9e46c5bf..cd6942fdac6 100644 --- a/libraries/scripting/jvm/src/kotlin/script/experimental/jvm/impl/BridgeDependenciesResolver.kt +++ b/libraries/scripting/jvm/src/kotlin/script/experimental/jvm/impl/BridgeDependenciesResolver.kt @@ -16,13 +16,12 @@ import kotlin.script.experimental.dependencies.ScriptDependencies import kotlin.script.experimental.dependencies.ScriptReport import kotlin.script.experimental.host.toScriptSource import kotlin.script.experimental.jvm.JvmDependency -import kotlin.script.experimental.jvm.defaultConfiguration import kotlin.script.experimental.jvm.mapToLegacyScriptReportPosition import kotlin.script.experimental.jvm.mapToLegacyScriptReportSeverity class BridgeDependenciesResolver( - val scriptConfigurator: ScriptCompilationConfigurator?, - val baseScriptCompilerConfiguration: ScriptCompileConfiguration = scriptConfigurator.defaultConfiguration, + val scriptDefinition: ScriptDefinition, + val calculatedBaseScriptCompilerConfiguration: ScriptCompileConfiguration, val onClasspathUpdated: (List) -> Unit = {} ) : AsyncDependenciesResolver { @@ -38,10 +37,10 @@ class BridgeDependenciesResolver( val processedScriptData = ProcessedScriptData(ProcessedScriptDataProperties.foundAnnotations to scriptContents.annotations) - val refinedConfiguration = scriptConfigurator?.let { + val refinedConfiguration = scriptDefinition.compilationConfigurator?.let { scriptConfigurator -> val res = scriptConfigurator.refineConfiguration( scriptContents.toScriptSource(), - baseScriptCompilerConfiguration, + calculatedBaseScriptCompilerConfiguration, processedScriptData ) when (res) { @@ -52,12 +51,12 @@ class BridgeDependenciesResolver( res.value } } - } ?: baseScriptCompilerConfiguration + } ?: calculatedBaseScriptCompilerConfiguration val newClasspath = refinedConfiguration.getOrNull(ScriptCompileConfigurationProperties.dependencies) ?.flatMap { (it as JvmDependency).classpath } ?: emptyList() - if (refinedConfiguration != baseScriptCompilerConfiguration) { - val oldClasspath = baseScriptCompilerConfiguration.getOrNull(ScriptCompileConfigurationProperties.dependencies) + if (refinedConfiguration != calculatedBaseScriptCompilerConfiguration) { + val oldClasspath = calculatedBaseScriptCompilerConfiguration.getOrNull(ScriptCompileConfigurationProperties.dependencies) ?.flatMap { (it as JvmDependency).classpath } ?: emptyList() if (newClasspath != oldClasspath) { onClasspathUpdated(newClasspath) diff --git a/libraries/scripting/jvm/src/kotlin/script/experimental/jvm/jvmScriptCompilation.kt b/libraries/scripting/jvm/src/kotlin/script/experimental/jvm/jvmScriptCompilation.kt index 910b0ab5002..96e0cfc24b3 100644 --- a/libraries/scripting/jvm/src/kotlin/script/experimental/jvm/jvmScriptCompilation.kt +++ b/libraries/scripting/jvm/src/kotlin/script/experimental/jvm/jvmScriptCompilation.kt @@ -16,18 +16,18 @@ open class JvmScriptCompiler( override suspend fun compile( script: ScriptSource, - configurator: ScriptCompilationConfigurator?, + scriptDefinition: ScriptDefinition, additionalConfiguration: ScriptCompileConfiguration? ): ResultWithDiagnostics> { - val baseConfiguration = additionalConfiguration?.cloneWithNewParent(configurator?.defaultConfiguration) - ?: configurator?.defaultConfiguration + val baseConfiguration = additionalConfiguration?.cloneWithNewParent(scriptDefinition.compilationConfigurator?.defaultConfiguration) + ?: scriptDefinition.compilationConfigurator?.defaultConfiguration ?: ScriptCompileConfiguration() val refinedConfiguration = if (baseConfiguration.getOrNull(ScriptCompileConfigurationProperties.refineBeforeParsing) == true) { - if (configurator == null) { + if (scriptDefinition.compilationConfigurator == null) { return ResultWithDiagnostics.Failure("Non-null configurator expected".asErrorDiagnostics()) } - configurator.refineConfiguration(script, baseConfiguration).let { + scriptDefinition.compilationConfigurator!!.refineConfiguration(script, baseConfiguration).let { when (it) { is ResultWithDiagnostics.Failure -> return it is ResultWithDiagnostics.Success -> it.value @@ -40,7 +40,7 @@ open class JvmScriptCompiler( if (cached != null) return cached.asSuccess() - return compilerProxy.compile(script, configurator, refinedConfiguration).also { + return compilerProxy.compile(script, scriptDefinition, refinedConfiguration).also { if (it is ResultWithDiagnostics.Success) { cache.store(it.value, refinedConfiguration) } @@ -56,7 +56,7 @@ interface CompiledJvmScriptsCache { interface KJVMCompilerProxy { fun compile( script: ScriptSource, - configurator: ScriptCompilationConfigurator?, + scriptDefinition: ScriptDefinition, additionalConfiguration: ScriptCompileConfiguration ): ResultWithDiagnostics> } diff --git a/libraries/scripting/jvm/src/kotlin/script/experimental/jvm/jvmScriptEvaluation.kt b/libraries/scripting/jvm/src/kotlin/script/experimental/jvm/jvmScriptEvaluation.kt index b1bb1db2782..088e0662501 100644 --- a/libraries/scripting/jvm/src/kotlin/script/experimental/jvm/jvmScriptEvaluation.kt +++ b/libraries/scripting/jvm/src/kotlin/script/experimental/jvm/jvmScriptEvaluation.kt @@ -7,16 +7,14 @@ package kotlin.script.experimental.jvm -import kotlin.script.experimental.api.ScriptCompilationConfigurator import kotlin.script.experimental.api.ScriptEvaluator import kotlin.script.experimental.host.BasicScriptingHost import kotlin.script.experimental.util.typedKey open class JvmBasicScriptingHost( - configurationExtractor: ScriptCompilationConfigurator, compiler: JvmScriptCompiler, evaluator: ScriptEvaluator -) : BasicScriptingHost(configurationExtractor, compiler, evaluator) +) : BasicScriptingHost(compiler, evaluator) object JvmScriptEvaluationEnvironmentProperties { val baseClassLoader by typedKey() diff --git a/plugins/scripting/scripting-cli/src/org/jetbrains/kotlin/scripting/compiler/plugin/KotlinScriptDefinitionAdapterFromNewAPI.kt b/plugins/scripting/scripting-cli/src/org/jetbrains/kotlin/scripting/compiler/plugin/KotlinScriptDefinitionAdapterFromNewAPI.kt index 4d03b2b94fe..d91bfae387d 100644 --- a/plugins/scripting/scripting-cli/src/org/jetbrains/kotlin/scripting/compiler/plugin/KotlinScriptDefinitionAdapterFromNewAPI.kt +++ b/plugins/scripting/scripting-cli/src/org/jetbrains/kotlin/scripting/compiler/plugin/KotlinScriptDefinitionAdapterFromNewAPI.kt @@ -18,6 +18,7 @@ import kotlin.script.experimental.api.* import kotlin.script.experimental.dependencies.DependenciesResolver import kotlin.script.experimental.jvm.impl.BridgeDependenciesResolver import kotlin.script.experimental.location.ScriptExpectedLocation +import kotlin.script.experimental.util.chainPropertyBags // temporary trick with passing Any as a template and overwriting it below, TODO: fix after introducing new script definitions hierarchy abstract class KotlinScriptDefinitionAdapterFromNewAPIBase : KotlinScriptDefinition(Any::class) { @@ -26,8 +27,12 @@ abstract class KotlinScriptDefinitionAdapterFromNewAPIBase : KotlinScriptDefinit abstract val scriptFileExtensionWithDot: String + protected val baseCompilationConfiguration by lazy(LazyThreadSafetyMode.PUBLICATION) { + chainPropertyBags(scriptDefinition.compilationConfigurator?.defaultConfiguration, scriptDefinition.properties) + } + open val baseClass: KClass<*> by lazy(LazyThreadSafetyMode.PUBLICATION) { - getScriptingClass(scriptDefinition.compilationConfigurator.defaultConfiguration[ScriptingEnvironmentProperties.baseClass]) + getScriptingClass(baseCompilationConfiguration[ScriptDefinitionProperties.baseClass]) } override val template: KClass<*> get() = baseClass @@ -49,28 +54,28 @@ abstract class KotlinScriptDefinitionAdapterFromNewAPIBase : KotlinScriptDefinit get() = emptyList() override val dependencyResolver: DependenciesResolver by lazy(LazyThreadSafetyMode.PUBLICATION) { - BridgeDependenciesResolver(scriptDefinition.compilationConfigurator) + BridgeDependenciesResolver(scriptDefinition, baseCompilationConfiguration) } override val acceptedAnnotations: List> by lazy(LazyThreadSafetyMode.PUBLICATION) { - scriptDefinition.compilationConfigurator.defaultConfiguration.getOrNull(ScriptCompileConfigurationProperties.refineConfigurationOnAnnotations) + baseCompilationConfiguration.getOrNull(ScriptCompileConfigurationProperties.refineConfigurationOnAnnotations) .orEmpty() .map { getScriptingClass(it) as KClass } } override val implicitReceivers: List by lazy(LazyThreadSafetyMode.PUBLICATION) { - scriptDefinition.compilationConfigurator.defaultConfiguration.getOrNull(ScriptCompileConfigurationProperties.scriptImplicitReceivers) + baseCompilationConfiguration.getOrNull(ScriptCompileConfigurationProperties.scriptImplicitReceivers) .orEmpty() .map { getScriptingClass(it).starProjectedType } } override val environmentVariables: List> by lazy(LazyThreadSafetyMode.PUBLICATION) { - scriptDefinition.compilationConfigurator.defaultConfiguration.getOrNull(ScriptCompileConfigurationProperties.contextVariables) + baseCompilationConfiguration.getOrNull(ScriptCompileConfigurationProperties.contextVariables) ?.map { (k, v) -> k to getScriptingClass(v).starProjectedType }.orEmpty() } override val additionalCompilerArguments: List - get() = scriptDefinition.compilationConfigurator.defaultConfiguration.getOrNull(ScriptCompileConfigurationProperties.compilerOptions) + get() = baseCompilationConfiguration.getOrNull(ScriptCompileConfigurationProperties.compilerOptions) .orEmpty() override val scriptExpectedLocations: List = @@ -80,11 +85,11 @@ abstract class KotlinScriptDefinitionAdapterFromNewAPIBase : KotlinScriptDefinit ) override val targetClassAnnotations: List - get() = scriptDefinition.compilationConfigurator.defaultConfiguration.getOrNull(ScriptCompileConfigurationProperties.generatedClassAnnotations) + get() = baseCompilationConfiguration.getOrNull(ScriptCompileConfigurationProperties.generatedClassAnnotations) .orEmpty() override val targetMethodAnnotations: List - get() = scriptDefinition.compilationConfigurator.defaultConfiguration.getOrNull(ScriptCompileConfigurationProperties.generatedMethodAnnotations) + get() = baseCompilationConfiguration.getOrNull(ScriptCompileConfigurationProperties.generatedMethodAnnotations) .orEmpty() private val scriptingClassGetter by lazy(LazyThreadSafetyMode.PUBLICATION) { diff --git a/plugins/scripting/scripting-cli/src/org/jetbrains/kotlin/scripting/compiler/plugin/LazyScriptDefinitionFromDiscoveredClass.kt b/plugins/scripting/scripting-cli/src/org/jetbrains/kotlin/scripting/compiler/plugin/LazyScriptDefinitionFromDiscoveredClass.kt index 4148cd8c9f2..1f93d614251 100644 --- a/plugins/scripting/scripting-cli/src/org/jetbrains/kotlin/scripting/compiler/plugin/LazyScriptDefinitionFromDiscoveredClass.kt +++ b/plugins/scripting/scripting-cli/src/org/jetbrains/kotlin/scripting/compiler/plugin/LazyScriptDefinitionFromDiscoveredClass.kt @@ -41,8 +41,8 @@ class LazyScriptDefinitionFromDiscoveredClass internal constructor( ) try { ScriptDefinitionFromAnnotatedBaseClass( + KotlinType(className), ScriptingEnvironment( - ScriptingEnvironmentProperties.baseClass to KotlinType(className), ScriptingEnvironmentProperties.configurationDependencies to listOf(JvmDependency(classpath)), ScriptingEnvironmentProperties.getScriptingClass to JvmGetScriptingClass() ) diff --git a/plugins/scripting/scripting-cli/src/org/jetbrains/kotlin/scripting/compiler/plugin/ScriptiDefinitionsFromClasspathDiscoverySource.kt b/plugins/scripting/scripting-cli/src/org/jetbrains/kotlin/scripting/compiler/plugin/ScriptiDefinitionsFromClasspathDiscoverySource.kt index f504cbfc9cd..424da2fc479 100644 --- a/plugins/scripting/scripting-cli/src/org/jetbrains/kotlin/scripting/compiler/plugin/ScriptiDefinitionsFromClasspathDiscoverySource.kt +++ b/plugins/scripting/scripting-cli/src/org/jetbrains/kotlin/scripting/compiler/plugin/ScriptiDefinitionsFromClasspathDiscoverySource.kt @@ -276,8 +276,8 @@ private fun loadScriptDefinition( if (cls.annotations.firstIsInstanceOrNull() != null) { KotlinScriptDefinitionAdapterFromNewAPI( ScriptDefinitionFromAnnotatedBaseClass( + KotlinType(cls.kotlin), ScriptingEnvironment( - ScriptingEnvironmentProperties.baseClass to KotlinType(cls.kotlin), ScriptingEnvironmentProperties.getScriptingClass to JvmGetScriptingClass() ) )