Move invokable parts to JSR223 only, remove unneeded code
This commit is contained in:
+4
-48
@@ -16,20 +16,18 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.cli.common.repl
|
package org.jetbrains.kotlin.cli.common.repl
|
||||||
|
|
||||||
import org.jetbrains.kotlin.utils.tryCreateCallableMapping
|
|
||||||
import org.jetbrains.kotlin.resolve.jvm.JvmClassName
|
import org.jetbrains.kotlin.resolve.jvm.JvmClassName
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import java.net.URLClassLoader
|
import java.net.URLClassLoader
|
||||||
import java.util.concurrent.locks.ReentrantReadWriteLock
|
import java.util.concurrent.locks.ReentrantReadWriteLock
|
||||||
import kotlin.concurrent.read
|
import kotlin.concurrent.read
|
||||||
import kotlin.concurrent.write
|
import kotlin.concurrent.write
|
||||||
import kotlin.reflect.*
|
|
||||||
|
|
||||||
open class GenericReplCompiledEvaluator(baseClasspath: Iterable<File>,
|
open class GenericReplCompiledEvaluator(baseClasspath: Iterable<File>,
|
||||||
baseClassloader: ClassLoader?,
|
baseClassloader: ClassLoader?,
|
||||||
val scriptArgs: Array<Any?>? = null,
|
val scriptArgs: Array<Any?>? = null,
|
||||||
val scriptArgsTypes: Array<Class<*>>? = null
|
val scriptArgsTypes: Array<Class<*>>? = null
|
||||||
) : ReplCompiledEvaluator, ReplScriptInvoker {
|
) : ReplCompiledEvaluator {
|
||||||
|
|
||||||
private var classLoader: org.jetbrains.kotlin.cli.common.repl.ReplClassLoader = makeReplClassLoader(baseClassloader, baseClasspath)
|
private var classLoader: org.jetbrains.kotlin.cli.common.repl.ReplClassLoader = makeReplClassLoader(baseClassloader, baseClasspath)
|
||||||
private val classLoaderLock = ReentrantReadWriteLock()
|
private val classLoaderLock = ReentrantReadWriteLock()
|
||||||
@@ -37,8 +35,6 @@ open class GenericReplCompiledEvaluator(baseClasspath: Iterable<File>,
|
|||||||
// TODO: consider to expose it as a part of (evaluator, invoker) interface
|
// TODO: consider to expose it as a part of (evaluator, invoker) interface
|
||||||
private val evalStateLock = ReentrantReadWriteLock()
|
private val evalStateLock = ReentrantReadWriteLock()
|
||||||
|
|
||||||
private data class ClassWithInstance(val klass: Class<*>, val instance: Any)
|
|
||||||
|
|
||||||
private val compiledLoadedClassesHistory = ReplHistory<ClassWithInstance>()
|
private val compiledLoadedClassesHistory = ReplHistory<ClassWithInstance>()
|
||||||
|
|
||||||
override fun eval(codeLine: ReplCodeLine,
|
override fun eval(codeLine: ReplCodeLine,
|
||||||
@@ -83,7 +79,7 @@ open class GenericReplCompiledEvaluator(baseClasspath: Iterable<File>,
|
|||||||
}
|
}
|
||||||
|
|
||||||
val constructorParams: Array<Class<*>> =
|
val constructorParams: Array<Class<*>> =
|
||||||
(compiledLoadedClassesHistory.values.map { it.klass } +
|
(compiledLoadedClassesHistory.values.map { it.klass.java } +
|
||||||
(scriptArgs?.mapIndexed { i, it -> scriptArgsTypes?.getOrNull(i) ?: it?.javaClass ?: Any::class.java } ?: emptyList())
|
(scriptArgs?.mapIndexed { i, it -> scriptArgsTypes?.getOrNull(i) ?: it?.javaClass ?: Any::class.java } ?: emptyList())
|
||||||
).toTypedArray()
|
).toTypedArray()
|
||||||
val constructorArgs: Array<Any?> = (compiledLoadedClassesHistory.values.map { it.instance } + scriptArgs.orEmpty()).toTypedArray()
|
val constructorArgs: Array<Any?> = (compiledLoadedClassesHistory.values.map { it.instance } + scriptArgs.orEmpty()).toTypedArray()
|
||||||
@@ -98,7 +94,7 @@ open class GenericReplCompiledEvaluator(baseClasspath: Iterable<File>,
|
|||||||
return ReplEvalResult.Error.Runtime(compiledLoadedClassesHistory.lines, renderReplStackTrace(e.cause!!, startFromMethodName = "${scriptClass.name}.<init>"), e as? Exception)
|
return ReplEvalResult.Error.Runtime(compiledLoadedClassesHistory.lines, renderReplStackTrace(e.cause!!, startFromMethodName = "${scriptClass.name}.<init>"), e as? Exception)
|
||||||
}
|
}
|
||||||
|
|
||||||
compiledLoadedClassesHistory.add(codeLine, ClassWithInstance(scriptClass, scriptInstance))
|
compiledLoadedClassesHistory.add(codeLine, ClassWithInstance(scriptClass.kotlin, scriptInstance))
|
||||||
|
|
||||||
val rvField = scriptClass.getDeclaredField(SCRIPT_RESULT_FIELD_NAME).apply { isAccessible = true }
|
val rvField = scriptClass.getDeclaredField(SCRIPT_RESULT_FIELD_NAME).apply { isAccessible = true }
|
||||||
val rv: Any? = rvField.get(scriptInstance)
|
val rv: Any? = rvField.get(scriptInstance)
|
||||||
@@ -106,40 +102,7 @@ open class GenericReplCompiledEvaluator(baseClasspath: Iterable<File>,
|
|||||||
return if (hasResult) ReplEvalResult.ValueResult(compiledLoadedClassesHistory.lines, rv) else ReplEvalResult.UnitResult(compiledLoadedClassesHistory.lines)
|
return if (hasResult) ReplEvalResult.ValueResult(compiledLoadedClassesHistory.lines, rv) else ReplEvalResult.UnitResult(compiledLoadedClassesHistory.lines)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun <T: Any> getInterface(klass: KClass<T>): ReplScriptInvokeResult = evalStateLock.read {
|
override val lastEvaluatedScript: ClassWithInstance? get() = evalStateLock.read { compiledLoadedClassesHistory.values.lastOrNull() }
|
||||||
val (_, instance) = compiledLoadedClassesHistory.values.lastOrNull() ?: return ReplScriptInvokeResult.Error.NoSuchEntity("no script ")
|
|
||||||
return getInterface(instance, klass)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun <T: Any> getInterface(receiver: Any, klass: KClass<T>): ReplScriptInvokeResult = evalStateLock.read {
|
|
||||||
return ReplScriptInvokeResult.ValueResult(klass.safeCast(receiver))
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun invokeMethod(receiver: Any, name: String, vararg args: Any?, invokeWrapper: InvokeWrapper?): ReplScriptInvokeResult = evalStateLock.read {
|
|
||||||
return invokeImpl(receiver.javaClass.kotlin, receiver, name, args, invokeWrapper)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun invokeFunction(name: String, vararg args: Any?, invokeWrapper: InvokeWrapper?): ReplScriptInvokeResult = evalStateLock.read {
|
|
||||||
val (klass, instance) = compiledLoadedClassesHistory.values.lastOrNull() ?: return ReplScriptInvokeResult.Error.NoSuchEntity("no script ")
|
|
||||||
return invokeImpl(klass.kotlin, instance, name, args, invokeWrapper)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun invokeImpl(receiverClass: KClass<*>, receiverInstance: Any, name: String, args: Array<out Any?>, invokeWrapper: InvokeWrapper?): ReplScriptInvokeResult {
|
|
||||||
|
|
||||||
val candidates = receiverClass.memberFunctions.filter { it.name == name } +
|
|
||||||
receiverClass.memberExtensionFunctions.filter { it.name == name }
|
|
||||||
val (fn, mapping) = candidates.findMapping(args.toList()) ?:
|
|
||||||
candidates.findMapping(listOf<Any?>(receiverInstance) + args) ?:
|
|
||||||
return ReplScriptInvokeResult.Error.NoSuchEntity("no suitable function '$name' found")
|
|
||||||
val res = try {
|
|
||||||
invokeWrapper?.invoke { fn.callBy(mapping) } ?: fn.callBy(mapping)
|
|
||||||
}
|
|
||||||
catch (e: Throwable) {
|
|
||||||
// ignore everything in the stack trace until this constructor call
|
|
||||||
return ReplScriptInvokeResult.Error.Runtime(renderReplStackTrace(e.cause!!, startFromMethodName = "${fn.name}"), e as? Exception)
|
|
||||||
}
|
|
||||||
return if (fn.returnType.classifier == Unit::class) ReplScriptInvokeResult.UnitResult else ReplScriptInvokeResult.ValueResult(res)
|
|
||||||
}
|
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
private val SCRIPT_RESULT_FIELD_NAME = "\$\$result"
|
private val SCRIPT_RESULT_FIELD_NAME = "\$\$result"
|
||||||
@@ -149,10 +112,3 @@ open class GenericReplCompiledEvaluator(baseClasspath: Iterable<File>,
|
|||||||
private fun makeReplClassLoader(baseClassloader: ClassLoader?, baseClasspath: Iterable<File>) =
|
private fun makeReplClassLoader(baseClassloader: ClassLoader?, baseClasspath: Iterable<File>) =
|
||||||
ReplClassLoader(URLClassLoader(baseClasspath.map { it.toURI().toURL() }.toTypedArray(), baseClassloader))
|
ReplClassLoader(URLClassLoader(baseClasspath.map { it.toURI().toURL() }.toTypedArray(), baseClassloader))
|
||||||
|
|
||||||
private fun Iterable<KFunction<*>>.findMapping(args: List<Any?>): Pair<KFunction<*>, Map<KParameter, Any?>>? {
|
|
||||||
for (fn in this) {
|
|
||||||
val mapping = tryCreateCallableMapping(fn, args)
|
|
||||||
if (mapping != null) return fn to mapping
|
|
||||||
}
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
|
|||||||
+43
-17
@@ -16,45 +16,71 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.cli.common.repl
|
package org.jetbrains.kotlin.cli.common.repl
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.utils.tryCreateCallableMapping
|
||||||
import javax.script.Invocable
|
import javax.script.Invocable
|
||||||
import javax.script.ScriptException
|
import javax.script.ScriptException
|
||||||
|
import kotlin.reflect.*
|
||||||
|
|
||||||
@Suppress("unused") // used externally (kotlin.script.utils)
|
@Suppress("unused") // used externally (kotlin.script.utils)
|
||||||
interface KotlinJsr223JvmInvocableScriptEngine : Invocable {
|
interface KotlinJsr223JvmInvocableScriptEngine : Invocable {
|
||||||
|
|
||||||
val replScriptInvoker: ReplScriptInvoker
|
val replScriptEvaluator: ReplEvaluatorBase
|
||||||
|
|
||||||
|
fun <T: Any> getInterface(klass: KClass<T>): Any? {
|
||||||
|
val (_, instance) = replScriptEvaluator.lastEvaluatedScript ?: throw IllegalArgumentException("no script ")
|
||||||
|
return getInterface(instance, klass)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun <T: Any> getInterface(receiver: Any, klass: KClass<T>): Any? {
|
||||||
|
return klass.safeCast(receiver)
|
||||||
|
}
|
||||||
|
|
||||||
override fun invokeFunction(name: String?, vararg args: Any?): Any? {
|
override fun invokeFunction(name: String?, vararg args: Any?): Any? {
|
||||||
if (name == null) throw java.lang.NullPointerException("function name cannot be null")
|
if (name == null) throw java.lang.NullPointerException("function name cannot be null")
|
||||||
return processInvokeResult(replScriptInvoker.invokeFunction(name, *args), isMethod = true)
|
val (klass, instance) = replScriptEvaluator.lastEvaluatedScript ?: throw IllegalArgumentException("no script ")
|
||||||
|
return invokeImpl(klass, instance, name, args, invokeWrapper = null)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun invokeMethod(thiz: Any?, name: String?, vararg args: Any?): Any? {
|
override fun invokeMethod(thiz: Any?, name: String?, vararg args: Any?): Any? {
|
||||||
if (name == null) throw java.lang.NullPointerException("method name cannot be null")
|
if (name == null) throw java.lang.NullPointerException("method name cannot be null")
|
||||||
if (thiz == null) throw IllegalArgumentException("cannot invoke method on the null object")
|
if (thiz == null) throw IllegalArgumentException("cannot invoke method on the null object")
|
||||||
return processInvokeResult(replScriptInvoker.invokeMethod(thiz, name, *args), isMethod = true)
|
return invokeImpl(thiz.javaClass.kotlin, thiz, name, args, invokeWrapper = null)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun <T : Any> getInterface(clasz: Class<T>?): T? {
|
override fun <T : Any> getInterface(clasz: Class<T>?): T? {
|
||||||
if (clasz == null) throw IllegalArgumentException("class object cannot be null")
|
val (_, instance) = replScriptEvaluator.lastEvaluatedScript ?: throw IllegalArgumentException("no script ")
|
||||||
if (!clasz.isInterface) throw IllegalArgumentException("expecting interface")
|
return getInterface(instance, clasz)
|
||||||
return processInvokeResult(replScriptInvoker.getInterface(clasz.kotlin), isMethod = false) as? T
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun <T : Any> getInterface(thiz: Any?, clasz: Class<T>?): T? {
|
override fun <T : Any> getInterface(thiz: Any?, clasz: Class<T>?): T? {
|
||||||
if (thiz == null) throw IllegalArgumentException("object cannot be null")
|
if (thiz == null) throw IllegalArgumentException("object cannot be null")
|
||||||
if (clasz == null) throw IllegalArgumentException("class object cannot be null")
|
if (clasz == null) throw IllegalArgumentException("class object cannot be null")
|
||||||
if (!clasz.isInterface) throw IllegalArgumentException("expecting interface")
|
if (!clasz.isInterface) throw IllegalArgumentException("expecting interface")
|
||||||
return processInvokeResult(replScriptInvoker.getInterface(thiz, clasz.kotlin), isMethod = false) as? T
|
return clasz.kotlin.safeCast(thiz)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
private fun processInvokeResult(res: ReplScriptInvokeResult, isMethod: Boolean): Any? =
|
|
||||||
when (res) {
|
private fun invokeImpl(receiverClass: KClass<*>, receiverInstance: Any, name: String, args: Array<out Any?>, invokeWrapper: InvokeWrapper?): Any? {
|
||||||
is ReplScriptInvokeResult.Error.NoSuchEntity -> throw if (isMethod) NoSuchMethodException(res.message) else IllegalArgumentException(res.message)
|
|
||||||
is ReplScriptInvokeResult.Error.CompileTime -> throw IllegalArgumentException(res.message) // should not happen in the current code, so leaving it here despite the contradiction with Invocable's specs
|
val candidates = receiverClass.functions.filter { it.name == name }
|
||||||
is ReplScriptInvokeResult.Error.Runtime -> throw ScriptException(res.message)
|
val (fn, mapping) = candidates.findMapping(listOf<Any?>(receiverInstance) + args) ?:
|
||||||
is ReplScriptInvokeResult.Error -> throw ScriptException(res.message)
|
throw NoSuchMethodException("no suitable function '$name' found")
|
||||||
is ReplScriptInvokeResult.UnitResult -> Unit // TODO: check if it is suitable replacement for java's Void
|
val res = try {
|
||||||
is ReplScriptInvokeResult.ValueResult -> res.value
|
invokeWrapper?.invoke {
|
||||||
}
|
fn.callBy(mapping)
|
||||||
|
} ?: fn.callBy(mapping)
|
||||||
|
}
|
||||||
|
catch (e: Throwable) {
|
||||||
|
// ignore everything in the stack trace until this constructor call
|
||||||
|
throw ScriptException(renderReplStackTrace(e.cause!!, startFromMethodName = fn.name))
|
||||||
|
}
|
||||||
|
return if (fn.returnType.classifier == Unit::class) Unit else res
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun Iterable<KFunction<*>>.findMapping(args: List<Any?>): Pair<KFunction<*>, Map<KParameter, Any?>>? {
|
||||||
|
for (fn in this) {
|
||||||
|
val mapping = tryCreateCallableMapping(fn, args)
|
||||||
|
if (mapping != null) return fn to mapping
|
||||||
|
}
|
||||||
|
return null
|
||||||
}
|
}
|
||||||
@@ -28,6 +28,8 @@ data class ReplCodeLine(val no: Int, val code: String) : Serializable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
data class ClassWithInstance(val klass: KClass<*>, val instance: Any)
|
||||||
|
|
||||||
// TODO: consider storing code hash where source is not needed
|
// TODO: consider storing code hash where source is not needed
|
||||||
|
|
||||||
data class CompiledClassData(val path: String, val bytes: ByteArray) : Serializable {
|
data class CompiledClassData(val path: String, val bytes: ByteArray) : Serializable {
|
||||||
@@ -73,22 +75,6 @@ sealed class ReplCompileResult(val updatedHistory: List<ReplCodeLine>) : Seriali
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
sealed class ReplScriptInvokeResult : Serializable {
|
|
||||||
class ValueResult(val value: Any?) : ReplScriptInvokeResult() {
|
|
||||||
override fun toString(): String = "Result: $value"
|
|
||||||
}
|
|
||||||
object UnitResult : ReplScriptInvokeResult()
|
|
||||||
sealed class Error(val message: String) : ReplScriptInvokeResult() {
|
|
||||||
class Runtime(message: String, val cause: Exception? = null) : Error(message)
|
|
||||||
class NoSuchEntity(message: String) : Error(message)
|
|
||||||
class CompileTime(message: String, val location: CompilerMessageLocation = CompilerMessageLocation.NO_LOCATION) : Error(message)
|
|
||||||
override fun toString(): String = "${this::class.simpleName}Error(message = \"$message\""
|
|
||||||
}
|
|
||||||
companion object {
|
|
||||||
private val serialVersionUID: Long = 8228357578L
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
sealed class ReplEvalResult(val updatedHistory: List<ReplCodeLine>) : Serializable {
|
sealed class ReplEvalResult(val updatedHistory: List<ReplCodeLine>) : Serializable {
|
||||||
class ValueResult(updatedHistory: List<ReplCodeLine>, val value: Any?) : ReplEvalResult(updatedHistory) {
|
class ValueResult(updatedHistory: List<ReplCodeLine>, val value: Any?) : ReplEvalResult(updatedHistory) {
|
||||||
override fun toString(): String = "Result: $value"
|
override fun toString(): String = "Result: $value"
|
||||||
@@ -117,19 +103,11 @@ interface ReplCompiler : ReplChecker {
|
|||||||
fun compile(codeLine: ReplCodeLine, history: List<ReplCodeLine>): ReplCompileResult
|
fun compile(codeLine: ReplCodeLine, history: List<ReplCodeLine>): ReplCompileResult
|
||||||
}
|
}
|
||||||
|
|
||||||
interface ReplScriptInvoker {
|
interface ReplEvaluatorBase {
|
||||||
fun <T: Any> getInterface(clasz: KClass<T>): ReplScriptInvokeResult
|
val lastEvaluatedScript: ClassWithInstance?
|
||||||
fun <T: Any> getInterface(receiver: Any, clasz: KClass<T>): ReplScriptInvokeResult
|
|
||||||
fun invokeMethod(receiver: Any, name: String, vararg args: Any?, invokeWrapper: InvokeWrapper? = null): ReplScriptInvokeResult
|
|
||||||
fun invokeFunction(name: String, vararg args: Any?, invokeWrapper: InvokeWrapper? = null): ReplScriptInvokeResult
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO this is a bit cumbersome, consider some other ways to access an invoker
|
interface ReplCompiledEvaluator : ReplEvaluatorBase {
|
||||||
interface ReplScriptInvokerProxy {
|
|
||||||
val scriptInvoker: ReplScriptInvoker
|
|
||||||
}
|
|
||||||
|
|
||||||
interface ReplCompiledEvaluator {
|
|
||||||
|
|
||||||
fun eval(codeLine: ReplCodeLine,
|
fun eval(codeLine: ReplCodeLine,
|
||||||
history: List<ReplCodeLine>,
|
history: List<ReplCodeLine>,
|
||||||
@@ -141,7 +119,7 @@ interface ReplCompiledEvaluator {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
interface ReplEvaluator : ReplChecker {
|
interface ReplEvaluator : ReplChecker, ReplEvaluatorBase {
|
||||||
|
|
||||||
fun eval(codeLine: ReplCodeLine,
|
fun eval(codeLine: ReplCodeLine,
|
||||||
history: List<ReplCodeLine>,
|
history: List<ReplCodeLine>,
|
||||||
|
|||||||
@@ -22,7 +22,6 @@ import com.intellij.openapi.vfs.CharsetToolkit
|
|||||||
import com.intellij.psi.PsiFileFactory
|
import com.intellij.psi.PsiFileFactory
|
||||||
import com.intellij.psi.impl.PsiFileFactoryImpl
|
import com.intellij.psi.impl.PsiFileFactoryImpl
|
||||||
import com.intellij.testFramework.LightVirtualFile
|
import com.intellij.testFramework.LightVirtualFile
|
||||||
import java.io.File
|
|
||||||
import org.jetbrains.kotlin.cli.common.CLIConfigurationKeys
|
import org.jetbrains.kotlin.cli.common.CLIConfigurationKeys
|
||||||
import org.jetbrains.kotlin.cli.common.messages.AnalyzerWithCompilerReport
|
import org.jetbrains.kotlin.cli.common.messages.AnalyzerWithCompilerReport
|
||||||
import org.jetbrains.kotlin.cli.common.messages.MessageCollector
|
import org.jetbrains.kotlin.cli.common.messages.MessageCollector
|
||||||
@@ -44,6 +43,7 @@ import org.jetbrains.kotlin.parsing.KotlinParserDefinition
|
|||||||
import org.jetbrains.kotlin.psi.KtFile
|
import org.jetbrains.kotlin.psi.KtFile
|
||||||
import org.jetbrains.kotlin.script.KotlinScriptDefinition
|
import org.jetbrains.kotlin.script.KotlinScriptDefinition
|
||||||
import org.jetbrains.kotlin.script.KotlinScriptExternalDependencies
|
import org.jetbrains.kotlin.script.KotlinScriptExternalDependencies
|
||||||
|
import java.io.File
|
||||||
|
|
||||||
private val logger = Logger.getInstance(GenericRepl::class.java)
|
private val logger = Logger.getInstance(GenericRepl::class.java)
|
||||||
|
|
||||||
@@ -184,11 +184,11 @@ open class GenericRepl(
|
|||||||
baseClassloader: ClassLoader?,
|
baseClassloader: ClassLoader?,
|
||||||
scriptArgs: Array<Any?>? = null,
|
scriptArgs: Array<Any?>? = null,
|
||||||
scriptArgsTypes: Array<Class<*>>? = null
|
scriptArgsTypes: Array<Class<*>>? = null
|
||||||
) : ReplEvaluator, ReplScriptInvokerProxy, GenericReplCompiler(disposable, scriptDefinition, compilerConfiguration, messageCollector) {
|
) : ReplEvaluator, GenericReplCompiler(disposable, scriptDefinition, compilerConfiguration, messageCollector) {
|
||||||
|
|
||||||
private val compiledEvaluator = GenericReplCompiledEvaluator(compilerConfiguration.jvmClasspathRoots, baseClassloader, scriptArgs, scriptArgsTypes)
|
private val compiledEvaluator = GenericReplCompiledEvaluator(compilerConfiguration.jvmClasspathRoots, baseClassloader, scriptArgs, scriptArgsTypes)
|
||||||
|
|
||||||
override val scriptInvoker: ReplScriptInvoker get() = compiledEvaluator
|
override val lastEvaluatedScript: ClassWithInstance? get() = compiledEvaluator.lastEvaluatedScript
|
||||||
|
|
||||||
@Synchronized
|
@Synchronized
|
||||||
override fun eval(codeLine: ReplCodeLine, history: List<ReplCodeLine>, invokeWrapper: InvokeWrapper?): ReplEvalResult =
|
override fun eval(codeLine: ReplCodeLine, history: List<ReplCodeLine>, invokeWrapper: InvokeWrapper?): ReplEvalResult =
|
||||||
|
|||||||
+3
@@ -106,6 +106,7 @@ class KotlinRemoteReplCompiler(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: consider removing daemon eval completely - it is not required now and has questionable security. This will simplify daemon interface as well
|
||||||
class KotlinRemoteReplEvaluator(
|
class KotlinRemoteReplEvaluator(
|
||||||
disposable: Disposable,
|
disposable: Disposable,
|
||||||
compileService: CompileService,
|
compileService: CompileService,
|
||||||
@@ -138,6 +139,8 @@ class KotlinRemoteReplEvaluator(
|
|||||||
operationsTracer = operationsTracer
|
operationsTracer = operationsTracer
|
||||||
), ReplEvaluator {
|
), ReplEvaluator {
|
||||||
|
|
||||||
|
override val lastEvaluatedScript: ClassWithInstance? = null // not implemented, no need so far
|
||||||
|
|
||||||
// TODO: invokeWrapper is ignored here, and in the daemon the session wrapper is used instead; So consider to make it per call (avoid performance penalties though)
|
// TODO: invokeWrapper is ignored here, and in the daemon the session wrapper is used instead; So consider to make it per call (avoid performance penalties though)
|
||||||
override fun eval(codeLine: ReplCodeLine, history: List<ReplCodeLine>, invokeWrapper: InvokeWrapper?): ReplEvalResult {
|
override fun eval(codeLine: ReplCodeLine, history: List<ReplCodeLine>, invokeWrapper: InvokeWrapper?): ReplEvalResult {
|
||||||
return compileService.remoteReplLineEval(sessionId, codeLine, history).get()
|
return compileService.remoteReplLineEval(sessionId, codeLine, history).get()
|
||||||
|
|||||||
@@ -324,7 +324,7 @@ class CompileServiceImpl(
|
|||||||
CompileService.CallResult.Error("Sorry, only JVM target platform is supported now")
|
CompileService.CallResult.Error("Sorry, only JVM target platform is supported now")
|
||||||
else {
|
else {
|
||||||
val disposable = Disposer.newDisposable()
|
val disposable = Disposer.newDisposable()
|
||||||
val repl = KotlinJvmReplService(disposable, templateClasspath, templateClassName, scriptArgs, scriptArgsTypes, compilerMessagesOutputStream, evalOutputStream, evalErrorStream, evalInputStream, operationsTracer)
|
val repl = KotlinJvmReplService(disposable, templateClasspath, templateClassName, scriptArgs, scriptArgsTypes, compilerMessagesOutputStream, operationsTracer)
|
||||||
val sessionId = state.sessions.leaseSession(ClientOrSessionProxy(aliveFlagPath, repl, disposable))
|
val sessionId = state.sessions.leaseSession(ClientOrSessionProxy(aliveFlagPath, repl, disposable))
|
||||||
|
|
||||||
CompileService.CallResult.Good(sessionId)
|
CompileService.CallResult.Good(sessionId)
|
||||||
|
|||||||
@@ -26,13 +26,11 @@ import org.jetbrains.kotlin.cli.jvm.repl.compileAndEval
|
|||||||
import org.jetbrains.kotlin.config.CommonConfigurationKeys
|
import org.jetbrains.kotlin.config.CommonConfigurationKeys
|
||||||
import org.jetbrains.kotlin.config.CompilerConfiguration
|
import org.jetbrains.kotlin.config.CompilerConfiguration
|
||||||
import org.jetbrains.kotlin.daemon.common.DummyProfiler
|
import org.jetbrains.kotlin.daemon.common.DummyProfiler
|
||||||
import org.jetbrains.kotlin.daemon.common.RemoteInputStream
|
|
||||||
import org.jetbrains.kotlin.daemon.common.RemoteOperationsTracer
|
import org.jetbrains.kotlin.daemon.common.RemoteOperationsTracer
|
||||||
import org.jetbrains.kotlin.daemon.common.RemoteOutputStream
|
import org.jetbrains.kotlin.daemon.common.RemoteOutputStream
|
||||||
import org.jetbrains.kotlin.script.KotlinScriptDefinition
|
import org.jetbrains.kotlin.script.KotlinScriptDefinition
|
||||||
import org.jetbrains.kotlin.script.KotlinScriptDefinitionFromAnnotatedTemplate
|
import org.jetbrains.kotlin.script.KotlinScriptDefinitionFromAnnotatedTemplate
|
||||||
import org.jetbrains.kotlin.utils.PathUtil
|
import org.jetbrains.kotlin.utils.PathUtil
|
||||||
import java.io.BufferedInputStream
|
|
||||||
import java.io.BufferedOutputStream
|
import java.io.BufferedOutputStream
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import java.io.PrintStream
|
import java.io.PrintStream
|
||||||
@@ -45,9 +43,6 @@ open class KotlinJvmReplService(
|
|||||||
scriptArgs: Array<Any?>?,
|
scriptArgs: Array<Any?>?,
|
||||||
scriptArgsTypes: Array<Class<*>>?,
|
scriptArgsTypes: Array<Class<*>>?,
|
||||||
compilerOutputStreamProxy: RemoteOutputStream,
|
compilerOutputStreamProxy: RemoteOutputStream,
|
||||||
evalOutputStream: RemoteOutputStream?,
|
|
||||||
evalErrorStream: RemoteOutputStream?,
|
|
||||||
evalInputStream: RemoteInputStream?,
|
|
||||||
val operationsTracer: RemoteOperationsTracer?
|
val operationsTracer: RemoteOperationsTracer?
|
||||||
) : ReplCompiler, ReplEvaluator {
|
) : ReplCompiler, ReplEvaluator {
|
||||||
|
|
||||||
@@ -115,32 +110,12 @@ open class KotlinJvmReplService(
|
|||||||
else GenericReplCompiler(disposable, scriptDef, configuration, messageCollector)
|
else GenericReplCompiler(disposable, scriptDef, configuration, messageCollector)
|
||||||
}
|
}
|
||||||
|
|
||||||
private val invokeWrapper : InvokeWrapper? by lazy {
|
|
||||||
if (evalOutputStream == null && evalErrorStream == null && evalInputStream == null) null
|
|
||||||
else object : InvokeWrapper {
|
|
||||||
val out = evalOutputStream?.let { PrintStream(BufferedOutputStream(RemoteOutputStreamClient(it, DummyProfiler()), REMOTE_STREAM_BUFFER_SIZE)) }
|
|
||||||
val err = evalErrorStream?.let { PrintStream(BufferedOutputStream(RemoteOutputStreamClient(it, DummyProfiler()), REMOTE_STREAM_BUFFER_SIZE)) }
|
|
||||||
val `in` = evalInputStream?.let { BufferedInputStream(RemoteInputStreamClient(it, DummyProfiler()), REMOTE_STREAM_BUFFER_SIZE) }
|
|
||||||
override operator fun<T> invoke(body: () -> T): T {
|
|
||||||
val prevOut = swapOrNull(out, { System.out }, { System.setOut(it) })
|
|
||||||
val prevErr = swapOrNull(err, { System.err }, { System.setErr(it) })
|
|
||||||
val prevIn = swapOrNull(`in`, { System.`in` }, { System.setIn(it) })
|
|
||||||
try {
|
|
||||||
return body()
|
|
||||||
}
|
|
||||||
finally {
|
|
||||||
prevIn?.let { System.setIn(prevIn) }
|
|
||||||
prevErr?.let { System.setErr(prevErr) }
|
|
||||||
prevOut?.let { System.setOut(prevOut) }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private val compiledEvaluator : GenericReplCompiledEvaluator by lazy {
|
private val compiledEvaluator : GenericReplCompiledEvaluator by lazy {
|
||||||
GenericReplCompiledEvaluator(configuration.jvmClasspathRoots, null, scriptArgs, scriptArgsTypes)
|
GenericReplCompiledEvaluator(configuration.jvmClasspathRoots, null, scriptArgs, scriptArgsTypes)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override val lastEvaluatedScript: ClassWithInstance? get() = compiledEvaluator.lastEvaluatedScript
|
||||||
|
|
||||||
override fun check(codeLine: ReplCodeLine, history: List<ReplCodeLine>): ReplCheckResult {
|
override fun check(codeLine: ReplCodeLine, history: List<ReplCodeLine>): ReplCheckResult {
|
||||||
operationsTracer?.before("check")
|
operationsTracer?.before("check")
|
||||||
try {
|
try {
|
||||||
@@ -180,10 +155,3 @@ open class KotlinJvmReplService(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private inline fun<T> swapOrNull(value: T?, get: () -> T, set: (T) -> Unit): T? =
|
|
||||||
value?.let {
|
|
||||||
val prevValue = get()
|
|
||||||
set(value)
|
|
||||||
prevValue
|
|
||||||
}
|
|
||||||
+1
-2
@@ -58,9 +58,8 @@ class KotlinJsr223JvmDaemonCompileScriptEngine(
|
|||||||
// TODO: bindings passing works only once on the first eval, subsequent setContext/setBindings call have no effect. Consider making it dynamic, but take history into account
|
// TODO: bindings passing works only once on the first eval, subsequent setContext/setBindings call have no effect. Consider making it dynamic, but take history into account
|
||||||
val localEvaluator by lazy { GenericReplCompiledEvaluator(templateClasspath, Thread.currentThread().contextClassLoader, getScriptArgs(getContext()), scriptArgsTypes) }
|
val localEvaluator by lazy { GenericReplCompiledEvaluator(templateClasspath, Thread.currentThread().contextClassLoader, getScriptArgs(getContext()), scriptArgsTypes) }
|
||||||
|
|
||||||
override val replScriptInvoker: ReplScriptInvoker get() = localEvaluator
|
|
||||||
|
|
||||||
override val replEvaluator: ReplCompiledEvaluator get() = localEvaluator
|
override val replEvaluator: ReplCompiledEvaluator get() = localEvaluator
|
||||||
|
override val replScriptEvaluator: ReplEvaluatorBase get() = localEvaluator
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
+1
-2
@@ -51,9 +51,8 @@ class KotlinJsr223JvmLocalScriptEngine(
|
|||||||
// TODO: bindings passing works only once on the first eval, subsequent setContext/setBindings call have no effect. Consider making it dynamic, but take history into account
|
// TODO: bindings passing works only once on the first eval, subsequent setContext/setBindings call have no effect. Consider making it dynamic, but take history into account
|
||||||
val localEvaluator by lazy { GenericReplCompiledEvaluator(templateClasspath, Thread.currentThread().contextClassLoader, getScriptArgs(getContext()), scriptArgsTypes) }
|
val localEvaluator by lazy { GenericReplCompiledEvaluator(templateClasspath, Thread.currentThread().contextClassLoader, getScriptArgs(getContext()), scriptArgsTypes) }
|
||||||
|
|
||||||
override val replScriptInvoker: ReplScriptInvoker get() = localEvaluator
|
|
||||||
|
|
||||||
override val replEvaluator: ReplCompiledEvaluator get() = localEvaluator
|
override val replEvaluator: ReplCompiledEvaluator get() = localEvaluator
|
||||||
|
override val replScriptEvaluator: ReplEvaluatorBase get() = localEvaluator
|
||||||
|
|
||||||
private fun makeScriptDefinition(templateClasspath: List<File>, templateClassName: String): KotlinScriptDefinition {
|
private fun makeScriptDefinition(templateClasspath: List<File>, templateClassName: String): KotlinScriptDefinition {
|
||||||
val classloader = URLClassLoader(templateClasspath.map { it.toURI().toURL() }.toTypedArray(), this.javaClass.classLoader)
|
val classloader = URLClassLoader(templateClasspath.map { it.toURI().toURL() }.toTypedArray(), this.javaClass.classLoader)
|
||||||
|
|||||||
Reference in New Issue
Block a user