Implement direct bindings to script properties mapping in the JSR-223 implementation

fix infrastructure and codegen parts
This commit is contained in:
Ilya Chernikov
2019-07-02 12:00:58 +02:00
parent 4940f64265
commit cfceeb1e8c
8 changed files with 252 additions and 12 deletions
@@ -8,12 +8,20 @@ package kotlin.script.experimental.jsr223
import org.jetbrains.kotlin.cli.common.repl.KOTLIN_SCRIPT_ENGINE_BINDINGS_KEY
import org.jetbrains.kotlin.cli.common.repl.KOTLIN_SCRIPT_STATE_BINDINGS_KEY
import javax.script.Bindings
import javax.script.ScriptContext
import javax.script.ScriptEngine
import kotlin.script.experimental.annotations.KotlinScript
import kotlin.script.experimental.api.*
import kotlin.script.experimental.jvmhost.jsr223.getScriptContext
import kotlin.script.experimental.jvmhost.jsr223.importAllBindings
import kotlin.script.experimental.jvmhost.jsr223.jsr223
import kotlin.script.templates.standard.ScriptTemplateWithBindings
@Suppress("unused")
@KotlinScript
@KotlinScript(
compilationConfiguration = KotlinJsr223DefaultScriptCompilationConfiguration::class,
evaluationConfiguration = KotlinJsr223DefaultScriptEvaluationConfiguration::class
)
abstract class KotlinJsr223DefaultScript(val jsr223Bindings: Bindings) : ScriptTemplateWithBindings(jsr223Bindings) {
private val myEngine: ScriptEngine? get() = bindings[KOTLIN_SCRIPT_ENGINE_BINDINGS_KEY]?.let { it as? ScriptEngine }
@@ -47,3 +55,62 @@ abstract class KotlinJsr223DefaultScript(val jsr223Bindings: Bindings) : ScriptT
fun createBindings(): Bindings = withMyEngine { it.createBindings() }
}
object KotlinJsr223DefaultScriptCompilationConfiguration : ScriptCompilationConfiguration(
{
refineConfiguration {
beforeCompiling { context ->
val jsr223context = context.compilationConfiguration[ScriptCompilationConfiguration.jsr223.getScriptContext]?.invoke()
if (jsr223context != null && context.compilationConfiguration[ScriptCompilationConfiguration.jsr223.importAllBindings] == true) {
val updatedProperties =
context.compilationConfiguration[ScriptCompilationConfiguration.providedProperties]?.toMutableMap() ?: hashMapOf()
val allBindings = (jsr223context.getBindings(ScriptContext.GLOBAL_SCOPE).toMutableMap() ?: hashMapOf()).apply {
val engineBindings = jsr223context.getBindings(ScriptContext.ENGINE_SCOPE)
if (engineBindings != null)
putAll(engineBindings)
}
for ((k, v) in allBindings) {
// only adding bindings that are not already defined
if (!updatedProperties.containsKey(k)) {
// TODO: add only valid names
// TODO: find out how it's implemented in other jsr223 engines for typed languages, since this approach prevent certain usage scenarios, e.g. assigning back value of a "sibling" type
updatedProperties[k] = KotlinType(v::class)
}
}
ScriptCompilationConfiguration(context.compilationConfiguration) {
providedProperties(updatedProperties)
}.asSuccess()
} else context.compilationConfiguration.asSuccess()
}
}
jsr223 {
importAllBindings(true)
}
}
)
object KotlinJsr223DefaultScriptEvaluationConfiguration : ScriptEvaluationConfiguration(
{
refineConfigurationBeforeEvaluate { context ->
val jsr223context = context.evaluationConfiguration[ScriptEvaluationConfiguration.jsr223.getScriptContext]?.invoke()
val knownProperties = context.compiledScript.compilationConfiguration[ScriptCompilationConfiguration.providedProperties]
if (jsr223context != null && knownProperties != null && knownProperties.isNotEmpty()) {
val updatedProperties =
context.evaluationConfiguration[ScriptEvaluationConfiguration.providedProperties]?.toMutableMap() ?: hashMapOf()
val engineBindings = jsr223context.getBindings(ScriptContext.ENGINE_SCOPE)
val globalBindings = jsr223context.getBindings(ScriptContext.GLOBAL_SCOPE)
for (prop in knownProperties) {
val v = when {
engineBindings?.containsKey(prop.key) == true -> engineBindings[prop.key]
globalBindings?.containsKey(prop.key) == true -> globalBindings[prop.key]
else -> return@refineConfigurationBeforeEvaluate ResultWithDiagnostics.Failure("Property ${prop.key} is not found in the bindings".asErrorDiagnostics())
}
updatedProperties[prop.key] = v
}
ScriptEvaluationConfiguration(context.evaluationConfiguration) {
providedProperties(updatedProperties)
}.asSuccess()
} else context.evaluationConfiguration.asSuccess()
}
}
)