Extend evaluation API for easier passing of evaluation configuration

refactor helpers accordingly
This commit is contained in:
Ilya Chernikov
2019-04-03 15:09:21 +02:00
parent fa58b41e43
commit 90444502a6
8 changed files with 123 additions and 62 deletions
@@ -39,12 +39,12 @@ abstract class BasicScriptingHost(
*/
open fun eval(
script: SourceCode,
scriptCompilationConfiguration: ScriptCompilationConfiguration,
configuration: ScriptEvaluationConfiguration?
compilationConfiguration: ScriptCompilationConfiguration,
evaluationConfiguration: ScriptEvaluationConfiguration?
): ResultWithDiagnostics<EvaluationResult> =
runInCoroutineContext {
compiler(script, scriptCompilationConfiguration).onSuccess {
evaluator(it, configuration)
compiler(script, compilationConfiguration).onSuccess {
evaluator(it, evaluationConfiguration ?: ScriptEvaluationConfiguration.Default)
}
}
}
@@ -8,6 +8,7 @@ package kotlin.script.experimental.host
import kotlin.reflect.KClass
import kotlin.script.experimental.annotations.KotlinScript
import kotlin.script.experimental.api.*
import kotlin.script.experimental.util.PropertiesCollection
private const val ERROR_MSG_PREFIX = "Unable to construct script definition: "
@@ -20,7 +21,7 @@ private const val SCRIPT_RUNTIME_TEMPLATES_PACKAGE = "kotlin.script.templates.st
private abstract class DummyScriptTemplate
/**
* Creates the compilation configuration from annotated script base class
* Creates compilation configuration from annotated script base class
* @param baseClassType the annotated script base class to construct the configuration from
* @param hostConfiguration scripting host configuration properties
* @param contextClass optional context class to extract classloading strategy from
@@ -33,48 +34,70 @@ fun createCompilationConfigurationFromTemplate(
body: ScriptCompilationConfiguration.Builder.() -> Unit = {}
): ScriptCompilationConfiguration {
val templateClass: KClass<*> = baseClassType.getTemplateClass(hostConfiguration, contextClass)
val mainAnnotation: KotlinScript = templateClass.kotlinScriptAnnotation
return ScriptCompilationConfiguration(scriptConfigInstance(mainAnnotation.compilationConfiguration)) {
propertiesFromTemplate(templateClass, baseClassType, mainAnnotation)
body()
}
}
/**
* Creates evaluation configuration from annotated script base class
* @param baseClassType the annotated script base class to construct the configuration from
* @param hostConfiguration scripting host configuration properties
* @param contextClass optional context class to extract classloading strategy from
* @param body optional configuration function to add more properties to the evaluation configuration
*/
fun createEvaluationConfigurationFromTemplate(
baseClassType: KotlinType,
hostConfiguration: ScriptingHostConfiguration,
contextClass: KClass<*> = ScriptEvaluationConfiguration::class,
body: ScriptEvaluationConfiguration.Builder.() -> Unit = {}
): ScriptEvaluationConfiguration {
val templateClass: KClass<*> = baseClassType.getTemplateClass(hostConfiguration, contextClass)
val mainAnnotation = templateClass.kotlinScriptAnnotation
return ScriptEvaluationConfiguration(scriptConfigInstance(mainAnnotation.evaluationConfiguration), body = body)
}
private fun ScriptCompilationConfiguration.Builder.propertiesFromTemplate(
templateClass: KClass<*>, baseClassType: KotlinType, mainAnnotation: KotlinScript
) {
if (baseClass() == null) {
baseClass(if (templateClass == baseClassType.fromClass) baseClassType else KotlinType(templateClass))
}
if (fileExtension() == null) {
fileExtension(mainAnnotation.fileExtension)
}
if (displayName() == null) {
displayName(mainAnnotation.displayName)
}
}
private val KClass<*>.kotlinScriptAnnotation: KotlinScript
get() = findAnnotation()
?: when (this@kotlinScriptAnnotation.qualifiedName) {
// transitions to the new scripting API: substituting annotations for standard templates from script-runtime
"$SCRIPT_RUNTIME_TEMPLATES_PACKAGE.SimpleScriptTemplate",
"$SCRIPT_RUNTIME_TEMPLATES_PACKAGE.ScriptTemplateWithArgs",
"$SCRIPT_RUNTIME_TEMPLATES_PACKAGE.ScriptTemplateWithBindings" -> DummyScriptTemplate::class.findAnnotation<KotlinScript>()
else -> null
}
?: throw IllegalArgumentException("${ERROR_MSG_PREFIX}Expecting KotlinScript annotation on the ${this}")
private fun KotlinType.getTemplateClass(hostConfiguration: ScriptingHostConfiguration, contextClass: KClass<*>): KClass<*> {
val getScriptingClass = hostConfiguration[ScriptingHostConfiguration.getScriptingClass]
?: throw IllegalArgumentException("${ERROR_MSG_PREFIX}Expecting 'getScriptingClass' parameter in the scripting host configuration")
val baseClass: KClass<*> =
try {
getScriptingClass(baseClassType, contextClass, hostConfiguration)
} catch (e: Throwable) {
throw IllegalArgumentException("${ERROR_MSG_PREFIX}Unable to load base class $baseClassType", e)
}
val loadedBaseClassType = if (baseClass == baseClassType.fromClass) baseClassType else KotlinType(baseClass)
val mainAnnotation = baseClass.findAnnotation<KotlinScript>()
?: run {
// transitions to the new scripting API:
// substituting annotations for standard templates from script-runtime
when (baseClass.qualifiedName) {
"$SCRIPT_RUNTIME_TEMPLATES_PACKAGE.SimpleScriptTemplate",
"$SCRIPT_RUNTIME_TEMPLATES_PACKAGE.ScriptTemplateWithArgs",
"$SCRIPT_RUNTIME_TEMPLATES_PACKAGE.ScriptTemplateWithBindings" -> DummyScriptTemplate::class
else -> null
}?.findAnnotation<KotlinScript>()
}
?: throw IllegalArgumentException("${ERROR_MSG_PREFIX}Expecting KotlinScript annotation on the $baseClass")
fun scriptConfigInstance(kclass: KClass<out ScriptCompilationConfiguration>): ScriptCompilationConfiguration = try {
kclass.objectInstance ?: kclass.createInstance()
return try {
getScriptingClass(this, contextClass, hostConfiguration)
} catch (e: Throwable) {
throw IllegalArgumentException("$ILLEGAL_CONFIG_ANN_ARG: ${e.message}", e)
}
return ScriptCompilationConfiguration(scriptConfigInstance(mainAnnotation.compilationConfiguration)) {
if (baseClass() == null) {
baseClass(loadedBaseClassType)
}
if (fileExtension() == null) {
fileExtension(mainAnnotation.fileExtension)
}
if (displayName() == null) {
displayName(mainAnnotation.displayName)
}
body()
throw IllegalArgumentException("${ERROR_MSG_PREFIX}Unable to load base class ${this}", e)
}
}
@@ -90,3 +113,10 @@ private fun <T : Any> KClass<T>.createInstance(): T {
@Suppress("UNCHECKED_CAST")
return noArgsConstructor.newInstance() as T
}
private fun <T : PropertiesCollection> scriptConfigInstance(kclass: KClass<out T>): T = try {
kclass.objectInstance ?: kclass.createInstance()
} catch (e: Throwable) {
throw IllegalArgumentException("$ILLEGAL_CONFIG_ANN_ARG: ${e.message}", e)
}