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
@@ -77,8 +77,6 @@ open class GenericReplChecker(
protected var lineState: LineState? = null
val classpath: MutableList<File> = compilerConfiguration.jvmClasspathRoots.toMutableList()
fun createDiagnosticHolder() = ReplTerminalDiagnosticMessageHolder()
override fun check(codeLine: ReplCodeLine, history: Iterable<ReplCodeLine>): ReplCheckResult {
@@ -108,7 +106,7 @@ open class GenericReplChecker(
}
abstract class GenericReplCompiler(
open class GenericReplCompiler(
disposable: Disposable,
scriptDefinition: KotlinScriptDefinition,
compilerConfiguration: CompilerConfiguration,
@@ -132,7 +130,7 @@ abstract class GenericReplCompiler(
val res = check(codeLine, history)
when (res) {
ReplCheckResult.Incomplete -> return@compile ReplCompileResult.Incomplete
is ReplCheckResult.Error -> return@compile ReplCompileResult.Error(res.message)
is ReplCheckResult.Error -> return@compile ReplCompileResult.Error(res.message, res.location)
ReplCheckResult.Ok -> {} // continue
}
}
@@ -140,14 +138,6 @@ abstract class GenericReplCompiler(
}
val newDependencies = scriptDefinition.getDependenciesFor(psiFile, environment.project, lastDependencies)
newDependencies?.let {
logger.debug("found dependencies: ${it.classpath}")
val newCp = environment.updateClasspath(it.classpath.map(::JvmClasspathRoot))
if (newCp != null && newCp.isNotEmpty()) {
logger.debug("new dependencies: $newCp")
dependenciesAdded(newCp)
}
}
if (lastDependencies != newDependencies) {
lastDependencies = newDependencies
}
@@ -179,7 +169,9 @@ abstract class GenericReplCompiler(
descriptorsHistory.add(codeLine to scriptDescriptor)
return ReplCompileResult.CompiledClasses(state.factory.asList().map { CompiledClassData(it.relativePath, it.asByteArray()) }, state.replSpecific.hasResult)
return ReplCompileResult.CompiledClasses(state.factory.asList().map { CompiledClassData(it.relativePath, it.asByteArray()) },
state.replSpecific.hasResult,
newDependencies?.let { environment.updateClasspath(it.classpath.map(::JvmClasspathRoot)) } ?: emptyList())
}
}
@@ -193,28 +185,26 @@ open class GenericRepl(
disposable: Disposable,
scriptDefinition: KotlinScriptDefinition,
compilerConfiguration: CompilerConfiguration,
messageCollector: MessageCollector
messageCollector: MessageCollector,
baseClassloader: ClassLoader?
) : ReplEvaluator, GenericReplCompiler(disposable, scriptDefinition, compilerConfiguration, messageCollector) {
private val compiledEvaluator = GenericReplCompiledEvaluator(classpath)
private val compiledEvaluator = GenericReplCompiledEvaluator(compilerConfiguration.jvmClasspathRoots, baseClassloader)
override fun eval(codeLine: ReplCodeLine, history: Iterable<ReplCodeLine>): ReplEvalResult {
synchronized(this) {
val (compiledClasses, hasResult) = compile(codeLine, history).let {
when (it) {
ReplCompileResult.Incomplete -> return@eval ReplEvalResult.Incomplete
is ReplCompileResult.HistoryMismatch -> return@eval ReplEvalResult.HistoryMismatch(it.lineNo)
is ReplCompileResult.Error -> return@eval ReplEvalResult.Error.CompileTime(it.message)
is ReplCompileResult.CompiledClasses -> it.classes to it.hasResult
}
}
return compiledEvaluator.eval(codeLine, history, compiledClasses, hasResult)
}
}
override fun dependenciesAdded(classpath: List<File>) {
compiledEvaluator.dependenciesAdded(classpath)
override fun eval(codeLine: ReplCodeLine, history: Iterable<ReplCodeLine>): ReplEvalResult = synchronized(this) {
return compileAndEval(this, compiledEvaluator, codeLine, history)
}
}
fun compileAndEval(replCompiler: ReplCompiler, replCompiledEvaluator: ReplCompiledEvaluator, codeLine: ReplCodeLine, history: Iterable<ReplCodeLine>): ReplEvalResult =
replCompiler.compile(codeLine, history).let {
when (it) {
ReplCompileResult.Incomplete -> ReplEvalResult.Incomplete
is ReplCompileResult.HistoryMismatch -> ReplEvalResult.HistoryMismatch(it.lineNo)
is ReplCompileResult.Error -> ReplEvalResult.Error.CompileTime(it.message, it.location)
is ReplCompileResult.CompiledClasses -> replCompiledEvaluator.eval(codeLine, history, it.classes, it.hasResult, it.newClasspath)
}
}
@@ -32,7 +32,8 @@ class KotlinJsr232ScriptEngine(
disposable: Disposable,
private val factory: ScriptEngineFactory,
private val scriptDefinition: KotlinScriptDefinition,
private val compilerConfiguration: CompilerConfiguration
private val compilerConfiguration: CompilerConfiguration,
baseClassLoader: ClassLoader
) : AbstractScriptEngine(), ScriptEngine {
data class MessageCollectorReport(val severity: CompilerMessageSeverity, val message: String, val location: CompilerMessageLocation)
@@ -72,7 +73,7 @@ class KotlinJsr232ScriptEngine(
}
}
private val repl = object : GenericRepl(disposable, scriptDefinition, compilerConfiguration, messageCollector) {}
private val repl = object : GenericRepl(disposable, scriptDefinition, compilerConfiguration, messageCollector, baseClassLoader) {}
private var lineCount = 0
@@ -49,7 +49,8 @@ class KotlinJsr232StandardScriptEngineFactory: ScriptEngineFactory {
// TODO: addJvmClasspathRoots(config.classpath)
put(CommonConfigurationKeys.MODULE_NAME, "kotlin-script")
put(JVMConfigurationKeys.INCLUDE_RUNTIME, true)
})
},
Thread.currentThread().contextClassLoader)
override fun getOutputStatement(toDisplay: String?): String = "print(\"$toDisplay\")"
override fun getMethodCallSyntax(obj: String, m: String, vararg args: String): String = "$obj.$m(${args.joinToString()})"