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
This commit is contained in:
Ilya Chernikov
2018-04-25 11:28:33 +02:00
parent 516924cda1
commit 57db77a295
5 changed files with 32 additions and 18 deletions
@@ -42,3 +42,8 @@ annotation class KotlinScriptEvaluator(
val evaluator: KClass<out ScriptEvaluator<*>>
)
@Target(AnnotationTarget.CLASS)
@Retention(AnnotationRetention.RUNTIME)
annotation class KotlinScriptDefaultCompilationConfiguration(
val compilationConfiguration: KClass<out List<*>> // object or class filled in 0-ary constructor
)
@@ -25,6 +25,7 @@ interface ScriptCompilationConfigurator {
scriptSource: ScriptSource,
configuration: ScriptCompileConfiguration,
processedScriptData: ProcessedScriptData = ProcessedScriptData()
): ResultWithDiagnostics<ScriptCompileConfiguration>
): ResultWithDiagnostics<ScriptCompileConfiguration> =
defaultConfiguration.asSuccess()
}
@@ -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<ScriptCompileConfiguration> =
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<Pair<TypedKey<*>, Any?>>
}
ScriptCompileConfiguration(environment, cfg)
}
}
class DummyEvaluator<ScriptBase : Any>(val environment: ScriptingEnvironment) : ScriptEvaluator<ScriptBase> {
@@ -28,9 +42,3 @@ class DummyEvaluator<ScriptBase : Any>(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 <reified T : Any> Iterable<*>.firstIsInstanceOrNull(): T? {
for (element in this) if (element is T) return element
return null
}
@@ -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<KotlinScriptCompilationConfigurator>()?.compilationConfigurator?.instantiateScriptHandler()
?: explicitDefinition?.compilationConfigurator
?: PassThroughCompilationConfigurator::class.instantiateScriptHandler()
?: AnnotationsBasedCompilationConfigurator::class.instantiateScriptHandler()
override val evaluator =
baseClass.findAnnotation<KotlinScriptEvaluator>()?.evaluator?.instantiateScriptHandler()
@@ -17,7 +17,7 @@ class TypedKeyDelegate<T> {
fun <T> typedKey() = TypedKeyDelegate<T>()
class ChainedPropertyBag private constructor(private val parent: ChainedPropertyBag?, private val data: Map<TypedKey<*>, Any?>) {
open class ChainedPropertyBag private constructor(private val parent: ChainedPropertyBag?, private val data: Map<TypedKey<*>, Any?>) {
constructor(parent: ChainedPropertyBag? = null, pairs: Iterable<Pair<TypedKey<*>, Any?>>) :
this(parent, HashMap<TypedKey<*>, Any?>().also { it.putAll(pairs) })