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 a9222e2283d..7250062b6ed 100644 --- a/libraries/scripting/common/src/kotlin/script/experimental/api/scriptCompilation.kt +++ b/libraries/scripting/common/src/kotlin/script/experimental/api/scriptCompilation.kt @@ -36,7 +36,7 @@ open class ScriptCompilationConfiguration(baseConfigurations: Iterable, Any>) : PropertiesCollection(properties) { +class ScriptEvaluationContextData(baseConfigurations: Iterable, 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) : + 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() + 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>() + /** * The facade to the script data for evaluation configuration refinement callbacks */ 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 893791c80fb..07e101886bd 100644 --- a/libraries/scripting/common/src/kotlin/script/experimental/api/scriptEvaluation.kt +++ b/libraries/scripting/common/src/kotlin/script/experimental/api/scriptEvaluation.kt @@ -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 = - simpleRefineImpl(ScriptEvaluationConfiguration.refineConfigurationBeforeEvaluate) { config, refineData -> - refineData.handler.invoke(ScriptEvaluationConfigurationRefinementContext(script, config, contextData)) +): ResultWithDiagnostics { + 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 diff --git a/libraries/scripting/common/src/kotlin/script/experimental/host/hostConfiguration.kt b/libraries/scripting/common/src/kotlin/script/experimental/host/hostConfiguration.kt index 47d0554efdc..62bc717952d 100644 --- a/libraries/scripting/common/src/kotlin/script/experimental/host/hostConfiguration.kt +++ b/libraries/scripting/common/src/kotlin/script/experimental/host/hostConfiguration.kt @@ -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(isTransient = true) +/** + * Evaluation context getter, allows to provide data to the evaluation configuration refinement functions + */ +val ScriptingHostConfigurationKeys.getEvaluationContext by PropertiesCollection.key(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) diff --git a/libraries/scripting/common/src/kotlin/script/experimental/util/propertiesCollection.kt b/libraries/scripting/common/src/kotlin/script/experimental/util/propertiesCollection.kt index 076a9c1c9a1..4a475591ad5 100644 --- a/libraries/scripting/common/src/kotlin/script/experimental/util/propertiesCollection.kt +++ b/libraries/scripting/common/src/kotlin/script/experimental/util/propertiesCollection.kt @@ -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, Any?> = emptyMap()) : Serializable { +open class PropertiesCollection(protected var properties: Map, Any?> = emptyMap()) : Serializable { open class Key( val name: String, @@ -64,6 +64,8 @@ open class PropertiesCollection(private var properties: Map, Any?> = empt val notTransientData: Map, 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