Put lines history into all data structures returned by repl, refactor storage and passing of the history for that
This commit is contained in:
+10
-10
@@ -30,12 +30,12 @@ open class GenericReplCompiledEvaluator(baseClasspath: Iterable<File>, baseClass
|
||||
|
||||
private class ClassWithInstance(val klass: Class<*>, val instance: Any)
|
||||
|
||||
private val compiledLoadedClassesHistory = arrayListOf<Pair<ReplCodeLine, ClassWithInstance>>()
|
||||
private val compiledLoadedClassesHistory = ReplHistory<ClassWithInstance>()
|
||||
|
||||
override fun eval(codeLine: ReplCodeLine, history: Iterable<ReplCodeLine>, compiledClasses: List<CompiledClassData>, hasResult: Boolean, newClasspath: List<File>): ReplEvalResult {
|
||||
override fun eval(codeLine: ReplCodeLine, history: List<ReplCodeLine>, compiledClasses: List<CompiledClassData>, hasResult: Boolean, classpathAddendum: List<File>): ReplEvalResult {
|
||||
|
||||
checkAndUpdateReplHistoryCollection(compiledLoadedClassesHistory, history)?.let {
|
||||
return@eval ReplEvalResult.HistoryMismatch(it)
|
||||
return@eval ReplEvalResult.HistoryMismatch(compiledLoadedClassesHistory.lines, it)
|
||||
}
|
||||
|
||||
var mainLineClassName: String? = null
|
||||
@@ -43,9 +43,9 @@ open class GenericReplCompiledEvaluator(baseClasspath: Iterable<File>, baseClass
|
||||
fun classNameFromPath(path: String) = JvmClassName.byInternalName(path.replaceFirst("\\.class$".toRegex(), ""))
|
||||
|
||||
classLoaderLock.read {
|
||||
if (newClasspath.isNotEmpty()) {
|
||||
if (classpathAddendum.isNotEmpty()) {
|
||||
classLoaderLock.write {
|
||||
classLoader = makeReplClassLoader(classLoader, newClasspath)
|
||||
classLoader = makeReplClassLoader(classLoader, classpathAddendum)
|
||||
}
|
||||
}
|
||||
compiledClasses.filter { it.path.endsWith(".class") }
|
||||
@@ -68,10 +68,10 @@ open class GenericReplCompiledEvaluator(baseClasspath: Iterable<File>, baseClass
|
||||
}
|
||||
|
||||
val constructorParams: Array<Class<*>> =
|
||||
(compiledLoadedClassesHistory.map { it.second.klass } +
|
||||
(compiledLoadedClassesHistory.values.map { it.klass } +
|
||||
(scriptArgs?.mapIndexed { i, it -> scriptArgsTypes?.getOrNull(i) ?: it?.javaClass ?: Any::class.java } ?: emptyList())
|
||||
).toTypedArray()
|
||||
val constructorArgs: Array<Any?> = (compiledLoadedClassesHistory.map { it.second.instance } + scriptArgs.orEmpty()).toTypedArray()
|
||||
val constructorArgs: Array<Any?> = (compiledLoadedClassesHistory.values.map { it.instance } + scriptArgs.orEmpty()).toTypedArray()
|
||||
|
||||
val scriptInstanceConstructor = scriptClass.getConstructor(*constructorParams)
|
||||
val scriptInstance =
|
||||
@@ -80,15 +80,15 @@ open class GenericReplCompiledEvaluator(baseClasspath: Iterable<File>, baseClass
|
||||
}
|
||||
catch (e: Throwable) {
|
||||
// ignore everything in the stack trace until this constructor call
|
||||
return ReplEvalResult.Error.Runtime(renderReplStackTrace(e.cause!!, startFromMethodName = "${scriptClass.name}.<init>"))
|
||||
return ReplEvalResult.Error.Runtime(compiledLoadedClassesHistory.lines, renderReplStackTrace(e.cause!!, startFromMethodName = "${scriptClass.name}.<init>"))
|
||||
}
|
||||
|
||||
compiledLoadedClassesHistory.add(codeLine to ClassWithInstance(scriptClass, scriptInstance))
|
||||
compiledLoadedClassesHistory.add(codeLine, ClassWithInstance(scriptClass, scriptInstance))
|
||||
|
||||
val rvField = scriptClass.getDeclaredField(SCRIPT_RESULT_FIELD_NAME).apply { isAccessible = true }
|
||||
val rv: Any? = rvField.get(scriptInstance)
|
||||
|
||||
return if (hasResult) ReplEvalResult.ValueResult(rv) else ReplEvalResult.UnitResult
|
||||
return if (hasResult) ReplEvalResult.ValueResult(compiledLoadedClassesHistory.lines, rv) else ReplEvalResult.UnitResult(compiledLoadedClassesHistory.lines)
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
+29
-2
@@ -19,13 +19,16 @@ package org.jetbrains.kotlin.cli.common.repl
|
||||
import java.io.Reader
|
||||
import javax.script.*
|
||||
|
||||
abstract class KotlinJsr223JvmScriptEngineBase(protected val myFactory: ScriptEngineFactory) : AbstractScriptEngine(), ScriptEngine {
|
||||
//val KOTLIN_SCRIPT_HISTORY_BINDINGS_KEY = "kotlin.script.history"
|
||||
//
|
||||
//val Bindings.kotlinScriptHistory:
|
||||
|
||||
abstract class KotlinJsr223JvmScriptEngineBase(protected val myFactory: ScriptEngineFactory) : AbstractScriptEngine(), ScriptEngine, Compilable, Invocable {
|
||||
protected var lineCount = 0
|
||||
|
||||
protected val history = arrayListOf<ReplCodeLine>()
|
||||
|
||||
abstract fun eval(codeLine: ReplCodeLine, history: Iterable<ReplCodeLine>): ReplEvalResult
|
||||
abstract fun eval(codeLine: ReplCodeLine, history: List<ReplCodeLine>): ReplEvalResult
|
||||
|
||||
override fun eval(script: String, context: ScriptContext?): Any? {
|
||||
|
||||
@@ -49,6 +52,30 @@ abstract class KotlinJsr223JvmScriptEngineBase(protected val myFactory: ScriptEn
|
||||
|
||||
override fun eval(script: Reader, context: ScriptContext?): Any? = eval(script.readText(), context)
|
||||
|
||||
override fun compile(p0: String?): CompiledScript {
|
||||
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
|
||||
}
|
||||
|
||||
override fun compile(p0: Reader?): CompiledScript {
|
||||
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
|
||||
}
|
||||
|
||||
override fun invokeMethod(p0: Any?, p1: String?, vararg p2: Any?): Any {
|
||||
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
|
||||
}
|
||||
|
||||
override fun <T : Any?> getInterface(p0: Class<T>?): T {
|
||||
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
|
||||
}
|
||||
|
||||
override fun <T : Any?> getInterface(p0: Any?, p1: Class<T>?): T {
|
||||
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
|
||||
}
|
||||
|
||||
override fun invokeFunction(p0: String?, vararg p1: Any?): Any {
|
||||
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
|
||||
}
|
||||
|
||||
override fun createBindings(): Bindings = SimpleBindings()
|
||||
|
||||
override fun getFactory(): ScriptEngineFactory = myFactory
|
||||
|
||||
@@ -35,10 +35,14 @@ data class CompiledClassData(val path: String, val bytes: ByteArray) : Serializa
|
||||
}
|
||||
}
|
||||
|
||||
sealed class ReplCheckResult : Serializable {
|
||||
object Ok : ReplCheckResult()
|
||||
object Incomplete : ReplCheckResult()
|
||||
class Error(val message: String, val location: CompilerMessageLocation = CompilerMessageLocation.NO_LOCATION) : ReplCheckResult() {
|
||||
sealed class ReplCheckResult(val updatedHistory: List<ReplCodeLine>) : Serializable {
|
||||
class Ok(updatedHistory: List<ReplCodeLine>) : ReplCheckResult(updatedHistory)
|
||||
class Incomplete(updatedHistory: List<ReplCodeLine>) : ReplCheckResult(updatedHistory)
|
||||
class Error(updatedHistory: List<ReplCodeLine>,
|
||||
val message: String,
|
||||
val location: CompilerMessageLocation = CompilerMessageLocation.NO_LOCATION
|
||||
) : ReplCheckResult(updatedHistory)
|
||||
{
|
||||
override fun toString(): String = "Error(message = \"$message\""
|
||||
}
|
||||
companion object {
|
||||
@@ -46,11 +50,19 @@ sealed class ReplCheckResult : Serializable {
|
||||
}
|
||||
}
|
||||
|
||||
sealed class ReplCompileResult : Serializable {
|
||||
class CompiledClasses(val classes: List<CompiledClassData>, val hasResult: Boolean, val newClasspath: List<File>) : ReplCompileResult()
|
||||
object Incomplete : ReplCompileResult()
|
||||
class HistoryMismatch(val lineNo: Int): ReplCompileResult()
|
||||
class Error(val message: String, val location: CompilerMessageLocation = CompilerMessageLocation.NO_LOCATION) : ReplCompileResult() {
|
||||
sealed class ReplCompileResult(val updatedHistory: List<ReplCodeLine>) : Serializable {
|
||||
class CompiledClasses(updatedHistory: List<ReplCodeLine>,
|
||||
val classes: List<CompiledClassData>,
|
||||
val hasResult: Boolean,
|
||||
val classpathAddendum: List<File>
|
||||
) : ReplCompileResult(updatedHistory)
|
||||
class Incomplete(updatedHistory: List<ReplCodeLine>) : ReplCompileResult(updatedHistory)
|
||||
class HistoryMismatch(updatedHistory: List<ReplCodeLine>, val lineNo: Int): ReplCompileResult(updatedHistory)
|
||||
class Error(updatedHistory: List<ReplCodeLine>,
|
||||
val message: String,
|
||||
val location: CompilerMessageLocation = CompilerMessageLocation.NO_LOCATION
|
||||
) : ReplCompileResult(updatedHistory)
|
||||
{
|
||||
override fun toString(): String = "Error(message = \"$message\""
|
||||
}
|
||||
companion object {
|
||||
@@ -58,16 +70,19 @@ sealed class ReplCompileResult : Serializable {
|
||||
}
|
||||
}
|
||||
|
||||
sealed class ReplEvalResult : Serializable {
|
||||
class ValueResult(val value: Any?) : ReplEvalResult() {
|
||||
sealed class ReplEvalResult(val updatedHistory: List<ReplCodeLine>) : Serializable {
|
||||
class ValueResult(updatedHistory: List<ReplCodeLine>, val value: Any?) : ReplEvalResult(updatedHistory) {
|
||||
override fun toString(): String = "Result: $value"
|
||||
}
|
||||
object UnitResult : ReplEvalResult()
|
||||
object Incomplete : ReplEvalResult()
|
||||
class HistoryMismatch(val lineNo: Int): ReplEvalResult()
|
||||
sealed class Error(val message: String) : ReplEvalResult() {
|
||||
class Runtime(message: String) : Error(message)
|
||||
class CompileTime(message: String, val location: CompilerMessageLocation = CompilerMessageLocation.NO_LOCATION) : Error(message)
|
||||
class UnitResult(updatedHistory: List<ReplCodeLine>) : ReplEvalResult(updatedHistory)
|
||||
class Incomplete(updatedHistory: List<ReplCodeLine>) : ReplEvalResult(updatedHistory)
|
||||
class HistoryMismatch(updatedHistory: List<ReplCodeLine>, val lineNo: Int): ReplEvalResult(updatedHistory)
|
||||
sealed class Error(updatedHistory: List<ReplCodeLine>, val message: String) : ReplEvalResult(updatedHistory) {
|
||||
class Runtime(updatedHistory: List<ReplCodeLine>, message: String) : Error(updatedHistory, message)
|
||||
class CompileTime(updatedHistory: List<ReplCodeLine>,
|
||||
message: String,
|
||||
val location: CompilerMessageLocation = CompilerMessageLocation.NO_LOCATION
|
||||
) : Error(updatedHistory, message)
|
||||
override fun toString(): String = "${this::class.simpleName}Error(message = \"$message\""
|
||||
}
|
||||
companion object {
|
||||
@@ -76,16 +91,16 @@ sealed class ReplEvalResult : Serializable {
|
||||
}
|
||||
|
||||
interface ReplChecker {
|
||||
fun check(codeLine: ReplCodeLine, history: Iterable<ReplCodeLine>): ReplCheckResult
|
||||
fun check(codeLine: ReplCodeLine, history: List<ReplCodeLine>): ReplCheckResult
|
||||
}
|
||||
|
||||
interface ReplCompiler : ReplChecker {
|
||||
fun compile(codeLine: ReplCodeLine, history: Iterable<ReplCodeLine>): ReplCompileResult
|
||||
fun compile(codeLine: ReplCodeLine, history: List<ReplCodeLine>): ReplCompileResult
|
||||
}
|
||||
|
||||
interface ReplCompiledEvaluator {
|
||||
|
||||
fun eval(codeLine: ReplCodeLine, history: Iterable<ReplCodeLine>, compiledClasses: List<CompiledClassData>, hasResult: Boolean, newClasspath: List<File>): ReplEvalResult
|
||||
fun eval(codeLine: ReplCodeLine, history: List<ReplCodeLine>, compiledClasses: List<CompiledClassData>, hasResult: Boolean, classpathAddendum: List<File>): ReplEvalResult
|
||||
|
||||
// override to capture output
|
||||
fun<T> evalWithIO(body: () -> T): T = body()
|
||||
@@ -94,7 +109,7 @@ interface ReplCompiledEvaluator {
|
||||
|
||||
interface ReplEvaluator : ReplChecker {
|
||||
|
||||
fun eval(codeLine: ReplCodeLine, history: Iterable<ReplCodeLine>): ReplEvalResult
|
||||
fun eval(codeLine: ReplCodeLine, history: List<ReplCodeLine>): ReplEvalResult
|
||||
|
||||
// override to capture output
|
||||
fun<T> evalWithIO(body: () -> T): T = body()
|
||||
|
||||
@@ -17,16 +17,42 @@
|
||||
package org.jetbrains.kotlin.cli.common.repl
|
||||
|
||||
import com.google.common.base.Throwables
|
||||
import java.io.Serializable
|
||||
|
||||
fun <T> checkAndUpdateReplHistoryCollection(col: MutableList<Pair<ReplCodeLine, T>>, baseHistory: Iterable<ReplCodeLine>): Int? {
|
||||
val baseHistoryIt = baseHistory.iterator()
|
||||
// TODO: thread safety!!
|
||||
data class ReplHistory<T>(
|
||||
val lines: MutableList<ReplCodeLine> = arrayListOf(),
|
||||
val values: MutableList<T> = arrayListOf()
|
||||
) : Serializable
|
||||
{
|
||||
init { assert(isValid()) }
|
||||
fun isValid() = lines.size == values.size
|
||||
|
||||
fun add(line: ReplCodeLine, value: T) {
|
||||
lines.add(line)
|
||||
values.add(value)
|
||||
}
|
||||
|
||||
fun trimAt(idx: Int) {
|
||||
lines.dropLast(lines.size - idx)
|
||||
values.dropLast(lines.size - idx)
|
||||
}
|
||||
|
||||
companion object {
|
||||
private val serialVersionUID: Long = 8228357578L
|
||||
}
|
||||
}
|
||||
|
||||
fun <T> checkAndUpdateReplHistoryCollection(history: ReplHistory<T>, linesHistory: Iterable<ReplCodeLine>): Int? {
|
||||
assert(history.isValid())
|
||||
val linesHistoryIt = linesHistory.iterator()
|
||||
var idx = 0
|
||||
while (baseHistoryIt.hasNext()) {
|
||||
val curLine = baseHistoryIt.next()
|
||||
if (col[idx].first != curLine) return curLine.no
|
||||
while (linesHistoryIt.hasNext()) {
|
||||
val curLine = linesHistoryIt.next()
|
||||
if (history.lines[idx] != curLine) return curLine.no
|
||||
idx += 1
|
||||
}
|
||||
col.dropLast(col.size - idx)
|
||||
history.trimAt(idx)
|
||||
return null
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user