Implement JSR-223 functionality on top of the "new" REPL

This commit is contained in:
Ilya Chernikov
2019-04-16 21:00:02 +02:00
parent 46915df56f
commit ea068e483c
13 changed files with 592 additions and 33 deletions
@@ -33,19 +33,24 @@ class JvmReplEvaluator(
invokeWrapper: InvokeWrapper?
): ReplEvalResult = state.lock.write {
val evalState = state.asState(JvmReplEvaluatorState::class.java)
val history = evalState.history as ReplStageHistoryWithReplace
val compiledScript = (compileResult.data as? KJvmCompiledScript<*>)
?: return ReplEvalResult.Error.CompileTime("Unable to access compiled script: ${compileResult.data}")
val lastSnippetInstance = evalState.history.peek()?.item
val lastSnippetInstance = history.peek()?.item
val historyBeforeSnippet = history.previousItems(compileResult.lineId)
val currentConfiguration = ScriptEvaluationConfiguration(baseScriptEvaluationConfiguration) {
if (evalState.history.isNotEmpty()) {
previousSnippets.put(evalState.history.map { it.item })
if (historyBeforeSnippet.any()) {
previousSnippets.put(historyBeforeSnippet.toList())
}
if (lastSnippetInstance != null) {
jvm {
baseClassLoader(lastSnippetInstance::class.java.classLoader)
}
}
if (scriptArgs != null) {
constructorArgs(*scriptArgs.scriptArgs)
}
}
val res = runBlocking { scriptEvaluator(compiledScript, currentConfiguration) }
@@ -53,7 +58,7 @@ class JvmReplEvaluator(
when (res) {
is ResultWithDiagnostics.Success -> when (val retVal = res.value.returnValue) {
is ResultValue.Value -> {
evalState.history.push(compileResult.lineId, retVal.scriptInstance)
history.replaceOrPush(compileResult.lineId, retVal.scriptInstance)
// TODO: the latter check is temporary while the result is used to return the instance too
if (retVal.type.isNotBlank())
ReplEvalResult.ValueResult(retVal.name, retVal.value, retVal.type)
@@ -61,12 +66,12 @@ class JvmReplEvaluator(
ReplEvalResult.UnitResult()
}
is ResultValue.UnitValue -> {
evalState.history.push(compileResult.lineId, retVal.scriptInstance)
history.replaceOrPush(compileResult.lineId, retVal.scriptInstance)
ReplEvalResult.UnitResult()
}
else -> throw IllegalStateException("Expecting value with script instance, got $retVal")
}
else -> ReplEvalResult.Error.Runtime(res.reports.joinToString("\n") { it.message })
else -> ReplEvalResult.Error.Runtime(res.reports.joinToString("\n") { it.message + (it.exception?.let { e -> ": $e" } ?: "") })
}
}
}
@@ -75,10 +80,29 @@ open class JvmReplEvaluatorState(
scriptEvaluationConfiguration: ScriptEvaluationConfiguration,
override val lock: ReentrantReadWriteLock = ReentrantReadWriteLock()
) : IReplStageState<Any> {
override val history: IReplStageHistory<Any> = BasicReplStageHistory(lock)
override val history: IReplStageHistory<Any> = ReplStageHistoryWithReplace(lock)
override val currentGeneration: Int get() = (history as BasicReplStageHistory<*>).currentGeneration.get()
val topClassLoader: ClassLoader = scriptEvaluationConfiguration[ScriptEvaluationConfiguration.jvm.baseClassLoader]!!
}
open class ReplStageHistoryWithReplace<T>(lock: ReentrantReadWriteLock = ReentrantReadWriteLock()) : BasicReplStageHistory<T>(lock) {
fun replace(id: ILineId, item: T): Boolean = lock.write {
for (idx in indices) {
if (get(idx).id == id) {
set(idx, ReplHistoryRecord(id, item))
return true
}
}
return false
}
fun replaceOrPush(id: ILineId, item: T) {
if (!replace(id, item)) {
tryResetTo(id)
push(id, item)
}
}
fun previousItems(id: ILineId): Sequence<T> = asSequence().takeWhile { it.id.no < id.no }.map { it.item }
}