From 57db77a29597bcb00e65e76d667e46c68334535a Mon Sep 17 00:00:00 2001 From: Ilya Chernikov Date: Wed, 25 Apr 2018 11:28:33 +0200 Subject: [PATCH] Refactor script infrastructure for easier usage and testability: - add script annotation for specifying default configuration for a script - add support for this annotation in the default configurator - rename configurator accordingly - add default implementation of the refineConfiguration method - make property bag class open --- .../annotations/scriptAnnotations.kt | 5 +++ .../experimental/api/scriptConfiguration.kt | 3 +- .../script/experimental/basic/basicScript.kt | 36 +++++++++++-------- .../definitions/definitionFromAnnotation.kt | 4 +-- .../script/experimental/util/propertyBag.kt | 2 +- 5 files changed, 32 insertions(+), 18 deletions(-) diff --git a/libraries/scripting/common/src/kotlin/script/experimental/annotations/scriptAnnotations.kt b/libraries/scripting/common/src/kotlin/script/experimental/annotations/scriptAnnotations.kt index a87b03ccbdd..3f6d81f2c0e 100644 --- a/libraries/scripting/common/src/kotlin/script/experimental/annotations/scriptAnnotations.kt +++ b/libraries/scripting/common/src/kotlin/script/experimental/annotations/scriptAnnotations.kt @@ -42,3 +42,8 @@ annotation class KotlinScriptEvaluator( val evaluator: KClass> ) +@Target(AnnotationTarget.CLASS) +@Retention(AnnotationRetention.RUNTIME) +annotation class KotlinScriptDefaultCompilationConfiguration( + val compilationConfiguration: KClass> // object or class filled in 0-ary constructor +) 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 47c90b4a46a..f2e1c63ad08 100644 --- a/libraries/scripting/common/src/kotlin/script/experimental/api/scriptConfiguration.kt +++ b/libraries/scripting/common/src/kotlin/script/experimental/api/scriptConfiguration.kt @@ -25,6 +25,7 @@ interface ScriptCompilationConfigurator { scriptSource: ScriptSource, configuration: ScriptCompileConfiguration, processedScriptData: ProcessedScriptData = ProcessedScriptData() - ): ResultWithDiagnostics + ): ResultWithDiagnostics = + defaultConfiguration.asSuccess() } 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 6f0f8674086..d0ab36468a4 100644 --- a/libraries/scripting/common/src/kotlin/script/experimental/basic/basicScript.kt +++ b/libraries/scripting/common/src/kotlin/script/experimental/basic/basicScript.kt @@ -5,19 +5,33 @@ package kotlin.script.experimental.basic +import kotlin.reflect.full.primaryConstructor +import kotlin.script.experimental.annotations.KotlinScriptDefaultCompilationConfiguration import kotlin.script.experimental.api.* +import kotlin.script.experimental.util.TypedKey -class PassThroughCompilationConfigurator(val environment: ScriptingEnvironment) : ScriptCompilationConfigurator { +private const val ILLEGAL_CONFIG_ANN_ARG = + "Illegal argument to KotlinScriptDefaultCompilationConfiguration annotation: expecting List-derived object or default-constructed class of configuration parameters" - override val defaultConfiguration = ScriptCompileConfiguration(environment) +open class AnnotationsBasedCompilationConfigurator(val environment: ScriptingEnvironment) : ScriptCompilationConfigurator { - override suspend fun refineConfiguration( - script: ScriptSource, - configuration: ScriptCompileConfiguration, - processedScriptData: ProcessedScriptData - ): ResultWithDiagnostics = - configuration.asSuccess() + override val defaultConfiguration = run { + val base = environment[ScriptingEnvironmentProperties.baseClass] + val cfg = base.annotations.filterIsInstance(KotlinScriptDefaultCompilationConfiguration::class.java).flatMap { + val params = try { + it.compilationConfiguration.objectInstance ?: it.compilationConfiguration.primaryConstructor!!.callBy(emptyMap()) + } catch (e: Throwable) { + throw IllegalArgumentException(ILLEGAL_CONFIG_ANN_ARG, e) + } + params.forEach { + if (it !is Pair<*, *> || it.first !is TypedKey<*>) + throw IllegalArgumentException("$ILLEGAL_CONFIG_ANN_ARG: invalid parameter $it") + } + params as List, Any?>> + } + ScriptCompileConfiguration(environment, cfg) + } } class DummyEvaluator(val environment: ScriptingEnvironment) : ScriptEvaluator { @@ -28,9 +42,3 @@ class DummyEvaluator(val environment: ScriptingEnvironment) : ResultWithDiagnostics.Failure("not implemented".asErrorDiagnostics()) } -// TODO: from org.jetbrains.kotlin.utils.addToStdlib, take it from the stdlib when available -private inline fun Iterable<*>.firstIsInstanceOrNull(): T? { - for (element in this) if (element is T) return element - return null -} - 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 8f16c0cf3f9..33225de11e7 100644 --- a/libraries/scripting/common/src/kotlin/script/experimental/definitions/definitionFromAnnotation.kt +++ b/libraries/scripting/common/src/kotlin/script/experimental/definitions/definitionFromAnnotation.kt @@ -13,8 +13,8 @@ import kotlin.script.experimental.annotations.KotlinScriptCompilationConfigurato import kotlin.script.experimental.annotations.KotlinScriptEvaluator import kotlin.script.experimental.annotations.KotlinScriptFileExtension import kotlin.script.experimental.api.* +import kotlin.script.experimental.basic.AnnotationsBasedCompilationConfigurator import kotlin.script.experimental.basic.DummyEvaluator -import kotlin.script.experimental.basic.PassThroughCompilationConfigurator import kotlin.script.experimental.util.TypedKey private const val ERROR_MSG_PREFIX = "Unable to construct script definition: " @@ -42,7 +42,7 @@ open class ScriptDefinitionFromAnnotatedBaseClass(val environment: ScriptingEnvi override val compilationConfigurator = baseClass.findAnnotation()?.compilationConfigurator?.instantiateScriptHandler() ?: explicitDefinition?.compilationConfigurator - ?: PassThroughCompilationConfigurator::class.instantiateScriptHandler() + ?: AnnotationsBasedCompilationConfigurator::class.instantiateScriptHandler() override val evaluator = baseClass.findAnnotation()?.evaluator?.instantiateScriptHandler() 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 1f55fd50a39..141d77154d8 100644 --- a/libraries/scripting/common/src/kotlin/script/experimental/util/propertyBag.kt +++ b/libraries/scripting/common/src/kotlin/script/experimental/util/propertyBag.kt @@ -17,7 +17,7 @@ class TypedKeyDelegate { fun typedKey() = TypedKeyDelegate() -class ChainedPropertyBag private constructor(private val parent: ChainedPropertyBag?, private val data: Map, Any?>) { +open class ChainedPropertyBag private constructor(private val parent: ChainedPropertyBag?, private val data: Map, Any?>) { constructor(parent: ChainedPropertyBag? = null, pairs: Iterable, Any?>>) : this(parent, HashMap, Any?>().also { it.putAll(pairs) })