Add remote repl support to the daemon, refactor repl classes accordingly, simple tests

This commit is contained in:
Ilya Chernikov
2016-09-16 17:38:00 +02:00
parent 042fc4fadc
commit 86ece30330
12 changed files with 648 additions and 111 deletions
@@ -23,25 +23,28 @@ import java.util.concurrent.locks.ReentrantReadWriteLock
import kotlin.concurrent.read
import kotlin.concurrent.write
open class GenericReplCompiledEvaluator(baseClasspath: Iterable<File>) : ReplCompiledEvaluator {
private val classpath = baseClasspath.toMutableList()
open class GenericReplCompiledEvaluator(baseClasspath: Iterable<File>, baseClassloader: ClassLoader?) : ReplCompiledEvaluator {
private var classLoader: org.jetbrains.kotlin.cli.common.repl.ReplClassLoader =
org.jetbrains.kotlin.cli.common.repl.ReplClassLoader(URLClassLoader(classpath.map { it.toURI().toURL() }.toTypedArray(), Thread.currentThread().contextClassLoader))
org.jetbrains.kotlin.cli.common.repl.ReplClassLoader(URLClassLoader(baseClasspath.map { it.toURI().toURL() }.toTypedArray(), baseClassloader))
private val classLoaderLock = ReentrantReadWriteLock()
private class ClassWithInstance(val klass: Class<*>, val instance: Any)
private val compiledLoadedClassesHistory = arrayListOf<Pair<ReplCodeLine, ClassWithInstance>>()
override fun eval(codeLine: ReplCodeLine, history: Iterable<ReplCodeLine>, compiledClasses: List<CompiledClassData>, hasResult: Boolean): ReplEvalResult {
override fun eval(codeLine: ReplCodeLine, history: Iterable<ReplCodeLine>, compiledClasses: List<CompiledClassData>, hasResult: Boolean, newClasspath: List<File>): ReplEvalResult {
checkAndUpdateReplHistoryCollection(compiledLoadedClassesHistory, history)?.let {
return@eval ReplEvalResult.HistoryMismatch(it)
}
classLoaderLock.read {
if (newClasspath.isNotEmpty()) {
classLoaderLock.write {
classLoader = org.jetbrains.kotlin.cli.common.repl.ReplClassLoader(URLClassLoader(newClasspath.map { it.toURI().toURL() }.toTypedArray(), classLoader))
}
}
compiledClasses.filter { it.path.endsWith(".class") }
.forEach {
classLoader.addClass(JvmClassName.byInternalName(it.path.replaceFirst("\\.class$".toRegex(), "")), it.bytes)
@@ -71,13 +74,6 @@ open class GenericReplCompiledEvaluator(baseClasspath: Iterable<File>) : ReplCom
return if (hasResult) ReplEvalResult.ValueResult(rv) else ReplEvalResult.UnitResult
}
fun dependenciesAdded(newClasspath: List<File>) {
classLoaderLock.write {
classpath.addAll(newClasspath)
classLoader = org.jetbrains.kotlin.cli.common.repl.ReplClassLoader(URLClassLoader(newClasspath.map { it.toURI().toURL() }.toTypedArray(), classLoader))
}
}
companion object {
private val SCRIPT_RESULT_FIELD_NAME = "\$\$result"
}
@@ -16,38 +16,62 @@
package org.jetbrains.kotlin.cli.common.repl
import org.jetbrains.kotlin.cli.common.messages.CompilerMessageLocation
import java.io.File
import java.io.Serializable
import java.util.*
data class ReplCodeLine(val no: Int, val code: String)
data class ReplCodeLine(val no: Int, val code: String) : Serializable {
companion object {
private val serialVersionUID: Long = 8228357578L // just a random number, should be changed when serialized data is changed
}
}
data class CompiledClassData(val path: String, val bytes: ByteArray) : Serializable {
override fun equals(other: Any?): Boolean = (other as? CompiledClassData)?.let { path == it.path && Arrays.equals(bytes, it.bytes) } ?: false
override fun hashCode(): Int = path.hashCode() + Arrays.hashCode(bytes)
companion object {
private val serialVersionUID: Long = 8228357578L // just a random number, should be changed when serialized data is changed
}
}
sealed class ReplCheckResult : Serializable {
object Ok : ReplCheckResult()
object Incomplete : ReplCheckResult()
class Error(val message: String) : ReplCheckResult()
class Error(val message: String, val location: CompilerMessageLocation = CompilerMessageLocation.NO_LOCATION) : ReplCheckResult() {
override fun toString(): String = "Error(message = \"$message\""
}
companion object {
private val serialVersionUID: Long = 8228357578L // just a random number, should be changed when serialized data is changed
}
}
sealed class ReplCompileResult : Serializable {
class CompiledClasses(val classes: List<CompiledClassData>, val hasResult: Boolean) : ReplCompileResult()
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) : ReplCompileResult()
class Error(val message: String, val location: CompilerMessageLocation = CompilerMessageLocation.NO_LOCATION) : ReplCompileResult() {
override fun toString(): String = "Error(message = \"$message\""
}
companion object {
private val serialVersionUID: Long = 8228357578L // just a random number, should be changed when serialized data is changed
}
}
sealed class ReplEvalResult : Serializable {
class ValueResult(val value: Any?) : ReplEvalResult()
class ValueResult(val value: Any?) : ReplEvalResult() {
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) : Error(message)
class CompileTime(message: String, val location: CompilerMessageLocation = CompilerMessageLocation.NO_LOCATION) : Error(message)
override fun toString(): String = "${this.javaClass.kotlin.simpleName}Error(message = \"$message\""
}
companion object {
private val serialVersionUID: Long = 8228357578L // just a random number, should be changed when serialized data is changed
}
}
@@ -57,14 +81,11 @@ interface ReplChecker {
interface ReplCompiler : ReplChecker {
fun compile(codeLine: ReplCodeLine, history: Iterable<ReplCodeLine>): ReplCompileResult
// a callback
fun dependenciesAdded(classpath: List<File>)
}
interface ReplCompiledEvaluator {
fun eval(codeLine: ReplCodeLine, history: Iterable<ReplCodeLine>, compiledClasses: List<CompiledClassData>, hasResult: Boolean): ReplEvalResult
fun eval(codeLine: ReplCodeLine, history: Iterable<ReplCodeLine>, compiledClasses: List<CompiledClassData>, hasResult: Boolean, newClasspath: List<File>): ReplEvalResult
// override to capture output
fun<T> evalWithIO(body: () -> T): T = body()
@@ -75,8 +96,6 @@ interface ReplEvaluator : ReplChecker {
fun eval(codeLine: ReplCodeLine, history: Iterable<ReplCodeLine>): ReplEvalResult
fun dependenciesAdded(classpath: List<File>)
// override to capture output
fun<T> evalWithIO(body: () -> T): T = body()
}