Implement JSR 223 script template with eval functions, some fixes

This commit is contained in:
Ilya Chernikov
2017-02-11 23:38:45 +01:00
parent 63aae56b11
commit d3682b7f7d
10 changed files with 96 additions and 14 deletions
@@ -28,6 +28,7 @@ import org.jetbrains.kotlin.daemon.common.*
import java.io.File
import java.io.OutputStream
import java.io.PrintStream
import java.util.concurrent.locks.ReentrantReadWriteLock
import javax.script.ScriptContext
import javax.script.ScriptEngineFactory
import javax.script.ScriptException
@@ -68,6 +69,8 @@ class KotlinJsr223JvmDaemonCompileScriptEngine(
override val state: IReplStageState<*> get() = getCurrentState(getContext())
override fun createState(lock: ReentrantReadWriteLock): IReplStageState<*> = replEvaluator.createState(lock)
override fun overrideScriptArgs(context: ScriptContext): ScriptArgsWithTypes? = getScriptArgs(context, scriptArgsTypes)
private fun connectToCompileService(compilerJar: File): CompileService {
@@ -29,6 +29,7 @@ import org.jetbrains.kotlin.script.KotlinScriptDefinitionFromAnnotatedTemplate
import org.jetbrains.kotlin.utils.PathUtil
import java.io.File
import java.net.URLClassLoader
import java.util.concurrent.locks.ReentrantReadWriteLock
import javax.script.ScriptContext
import javax.script.ScriptEngineFactory
import kotlin.reflect.KClass
@@ -56,6 +57,8 @@ class KotlinJsr223JvmLocalScriptEngine(
override val state: IReplStageState<*> get() = getCurrentState(getContext())
override fun createState(lock: ReentrantReadWriteLock): IReplStageState<*> = replEvaluator.createState(lock)
override fun overrideScriptArgs(context: ScriptContext): ScriptArgsWithTypes? = getScriptArgs(context, scriptArgsTypes)
private fun makeScriptDefinition(templateClasspath: List<File>, templateClassName: String): KotlinScriptDefinition {
@@ -29,6 +29,7 @@ import org.jetbrains.kotlin.script.util.manifestClassPath
import org.jetbrains.kotlin.utils.PathUtil.*
import java.io.File
import java.io.FileNotFoundException
import javax.script.Bindings
import javax.script.ScriptContext
import javax.script.ScriptEngine
import kotlin.script.templates.standard.ScriptTemplateWithArgs
@@ -39,10 +40,10 @@ class KotlinJsr223JvmLocalScriptEngineFactory : KotlinJsr223JvmScriptEngineFacto
KotlinJsr223JvmLocalScriptEngine(
Disposer.newDisposable(),
this,
scriptCompilationClasspathFromContext(),
"kotlin.script.templates.standard.ScriptTemplateWithBindings",
scriptCompilationClasspathFromContext("kotlin-script-util.jar"),
KotlinStandardJsr223ScriptTemplate::class.qualifiedName!!,
{ ctx, types -> ScriptArgsWithTypes(arrayOf(ctx.getBindings(ScriptContext.ENGINE_SCOPE)), types ?: emptyArray()) },
arrayOf(Map::class)
arrayOf(Bindings::class)
)
}
@@ -53,10 +54,10 @@ class KotlinJsr223JvmDaemonLocalEvalScriptEngineFactory : KotlinJsr223JvmScriptE
Disposer.newDisposable(),
this,
kotlinCompilerJar,
scriptCompilationClasspathFromContext(),
"kotlin.script.templates.standard.ScriptTemplateWithBindings",
scriptCompilationClasspathFromContext("kotlin-script-util.jar"),
KotlinStandardJsr223ScriptTemplate::class.qualifiedName!!,
{ ctx, types -> ScriptArgsWithTypes(arrayOf(ctx.getBindings(ScriptContext.ENGINE_SCOPE)), types ?: emptyArray()) },
arrayOf(Map::class)
arrayOf(Bindings::class)
)
}
@@ -77,9 +78,9 @@ private fun contextClasspath(keyName: String, classLoader: ClassLoader): List<Fi
)?.toList()
private fun scriptCompilationClasspathFromContext(classLoader: ClassLoader = Thread.currentThread().contextClassLoader): List<File> =
private fun scriptCompilationClasspathFromContext(keyName: String, classLoader: ClassLoader = Thread.currentThread().contextClassLoader): List<File> =
(System.getProperty("kotlin.script.classpath")?.split(File.pathSeparator)?.map(::File)
?: classpathFromClassloader(classLoader)
?: contextClasspath(keyName, classLoader)
).let {
it?.plus(kotlinScriptStandardJars) ?: kotlinScriptStandardJars
}
@@ -0,0 +1,41 @@
package org.jetbrains.kotlin.script.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 org.jetbrains.kotlin.script.ScriptTemplateDefinition
import javax.script.Bindings
import javax.script.ScriptEngine
@Suppress("unused")
@ScriptTemplateDefinition
abstract class KotlinStandardJsr223ScriptTemplate(val bindings: Bindings) {
private val myEngine: ScriptEngine? get() = bindings[KOTLIN_SCRIPT_ENGINE_BINDINGS_KEY]?.let { it as? ScriptEngine }
private inline fun<T> withMyEngine(body: (ScriptEngine) -> T): T =
myEngine?.let(body) ?: throw IllegalStateException("Script engine for `eval` call is not found")
fun eval(script: String, newBindings: Bindings): Any? =
withMyEngine {
val savedState = newBindings[KOTLIN_SCRIPT_STATE_BINDINGS_KEY]?.takeIf { it === this.bindings[KOTLIN_SCRIPT_STATE_BINDINGS_KEY] }?.apply {
newBindings[KOTLIN_SCRIPT_STATE_BINDINGS_KEY] = null
}
val res = it.eval(script, newBindings)
savedState?.apply {
newBindings[KOTLIN_SCRIPT_STATE_BINDINGS_KEY] = savedState
}
res
}
fun eval(script: String): Any? =
withMyEngine {
val savedState = bindings.remove(KOTLIN_SCRIPT_STATE_BINDINGS_KEY)
val res = it.eval(script, bindings)
savedState?.apply {
bindings[KOTLIN_SCRIPT_STATE_BINDINGS_KEY] = savedState
}
res
}
fun createBindings(): Bindings = withMyEngine { it.createBindings() }
}