Add a handler for providing evaluation context for scripts
use it on refinement. also some refactoring on context class and around
This commit is contained in:
@@ -36,7 +36,7 @@ open class ScriptCompilationConfiguration(baseConfigurations: Iterable<ScriptCom
|
||||
object Default : ScriptCompilationConfiguration()
|
||||
|
||||
override fun toString(): String {
|
||||
return "ScriptCompilationConfiguration($providedProperties)"
|
||||
return "ScriptCompilationConfiguration($properties)"
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -106,11 +106,43 @@ interface ScriptEvaluationContextDataKeys
|
||||
* The container for script evaluation context data
|
||||
* Used for transferring data to the evaluation refinement callbacks
|
||||
*/
|
||||
class ScriptEvaluationContextData(properties: Map<PropertiesCollection.Key<*>, Any>) : PropertiesCollection(properties) {
|
||||
class ScriptEvaluationContextData(baseConfigurations: Iterable<ScriptEvaluationContextData>, body: Builder.() -> Unit = {}) :
|
||||
PropertiesCollection(Builder(baseConfigurations).apply(body).data) {
|
||||
|
||||
constructor(body: Builder.() -> Unit = {}) : this(emptyList(), body)
|
||||
constructor(
|
||||
vararg baseConfigurations: ScriptEvaluationContextData, body: Builder.() -> Unit = {}
|
||||
) : this(baseConfigurations.asIterable(), body)
|
||||
|
||||
class Builder internal constructor(baseConfigurations: Iterable<ScriptEvaluationContextData>) :
|
||||
ScriptEvaluationContextDataKeys,
|
||||
PropertiesCollection.Builder(baseConfigurations)
|
||||
|
||||
companion object : ScriptEvaluationContextDataKeys
|
||||
}
|
||||
|
||||
/**
|
||||
* optimized alternative to the constructor with multiple base configurations
|
||||
*/
|
||||
fun merge(vararg contexts: ScriptEvaluationContextData?): ScriptEvaluationContextData? {
|
||||
val nonEmpty = ArrayList<ScriptEvaluationContextData>()
|
||||
for (data in contexts) {
|
||||
if (data != null && !data.isEmpty()) {
|
||||
nonEmpty.add(data)
|
||||
}
|
||||
}
|
||||
return when {
|
||||
nonEmpty.isEmpty() -> null
|
||||
nonEmpty.size == 1 -> nonEmpty.first()
|
||||
else -> ScriptEvaluationContextData(nonEmpty.asIterable())
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Command line arguments of the current process, could be provided by an evaluation host
|
||||
*/
|
||||
val ScriptEvaluationContextDataKeys.commandLineArgs by PropertiesCollection.key<List<String>>()
|
||||
|
||||
/**
|
||||
* The facade to the script data for evaluation configuration refinement callbacks
|
||||
*/
|
||||
|
||||
@@ -10,6 +10,7 @@ package kotlin.script.experimental.api
|
||||
import java.io.Serializable
|
||||
import kotlin.reflect.KClass
|
||||
import kotlin.script.experimental.host.ScriptingHostConfiguration
|
||||
import kotlin.script.experimental.host.getEvaluationContext
|
||||
import kotlin.script.experimental.util.PropertiesCollection
|
||||
|
||||
interface ScriptEvaluationConfigurationKeys
|
||||
@@ -121,10 +122,14 @@ data class RefineEvaluationConfigurationData(
|
||||
fun ScriptEvaluationConfiguration.refineBeforeEvaluation(
|
||||
script: CompiledScript<*>,
|
||||
contextData: ScriptEvaluationContextData? = null
|
||||
): ResultWithDiagnostics<ScriptEvaluationConfiguration> =
|
||||
simpleRefineImpl(ScriptEvaluationConfiguration.refineConfigurationBeforeEvaluate) { config, refineData ->
|
||||
refineData.handler.invoke(ScriptEvaluationConfigurationRefinementContext(script, config, contextData))
|
||||
): ResultWithDiagnostics<ScriptEvaluationConfiguration> {
|
||||
val hostConfiguration = get(ScriptEvaluationConfiguration.hostConfiguration)
|
||||
val baseContextData = hostConfiguration?.get(ScriptingHostConfiguration.getEvaluationContext)?.invoke(hostConfiguration)
|
||||
val actualContextData = merge(baseContextData, contextData)
|
||||
return simpleRefineImpl(ScriptEvaluationConfiguration.refineConfigurationBeforeEvaluate) { config, refineData ->
|
||||
refineData.handler.invoke(ScriptEvaluationConfigurationRefinementContext(script, config, actualContextData))
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The script evaluation result value
|
||||
|
||||
@@ -8,6 +8,7 @@ package kotlin.script.experimental.host
|
||||
import kotlin.reflect.KClass
|
||||
import kotlin.script.experimental.api.KotlinType
|
||||
import kotlin.script.experimental.api.ScriptDependency
|
||||
import kotlin.script.experimental.api.ScriptEvaluationContextData
|
||||
import kotlin.script.experimental.util.PropertiesCollection
|
||||
|
||||
interface ScriptingHostConfigurationKeys
|
||||
@@ -52,6 +53,11 @@ val ScriptingHostConfigurationKeys.configurationDependencies by PropertiesCollec
|
||||
*/
|
||||
val ScriptingHostConfigurationKeys.getScriptingClass by PropertiesCollection.key<GetScriptingClass>(isTransient = true)
|
||||
|
||||
/**
|
||||
* Evaluation context getter, allows to provide data to the evaluation configuration refinement functions
|
||||
*/
|
||||
val ScriptingHostConfigurationKeys.getEvaluationContext by PropertiesCollection.key<GetEvaluationContext>(isTransient = true)
|
||||
|
||||
/**
|
||||
* The interface to the generic "class loader" for the types used in the script configurations
|
||||
*/
|
||||
@@ -59,6 +65,18 @@ interface GetScriptingClass {
|
||||
operator fun invoke(classType: KotlinType, contextClass: KClass<*>, hostConfiguration: ScriptingHostConfiguration): KClass<*>
|
||||
}
|
||||
|
||||
/**
|
||||
* A helper to enable passing lambda directly to the getEvaluationContext "keyword"
|
||||
*/
|
||||
fun ScriptingHostConfiguration.Builder.getEvaluationContext(handler: GetEvaluationContext) {
|
||||
ScriptingHostConfiguration.getEvaluationContext.put(handler)
|
||||
}
|
||||
|
||||
/**
|
||||
* The interface to an evaluation context getter
|
||||
*/
|
||||
typealias GetEvaluationContext = (hostConfiguration: ScriptingHostConfiguration) -> ScriptEvaluationContextData
|
||||
|
||||
// helper method
|
||||
fun ScriptingHostConfiguration.getScriptingClass(type: KotlinType, contextClass: KClass<*>): KClass<*> {
|
||||
val getClass = get(ScriptingHostConfiguration.getScriptingClass)
|
||||
|
||||
+3
-1
@@ -13,7 +13,7 @@ import kotlin.reflect.KProperty
|
||||
import kotlin.reflect.KType
|
||||
import kotlin.script.experimental.api.KotlinType
|
||||
|
||||
open class PropertiesCollection(private var properties: Map<Key<*>, Any?> = emptyMap()) : Serializable {
|
||||
open class PropertiesCollection(protected var properties: Map<Key<*>, Any?> = emptyMap()) : Serializable {
|
||||
|
||||
open class Key<T>(
|
||||
val name: String,
|
||||
@@ -64,6 +64,8 @@ open class PropertiesCollection(private var properties: Map<Key<*>, Any?> = empt
|
||||
|
||||
val notTransientData: Map<Key<*>, Any?> get() = properties.filterKeys { it !is TransientKey<*>}
|
||||
|
||||
fun isEmpty(): Boolean = properties.isEmpty()
|
||||
|
||||
override fun equals(other: Any?): Boolean =
|
||||
(other as? PropertiesCollection)?.let { it.properties == properties } == true
|
||||
|
||||
|
||||
Reference in New Issue
Block a user