diff --git a/compiler/cli/cli-common/cli-common.iml b/compiler/cli/cli-common/cli-common.iml
index 1cf8d3edbb4..7447a45530f 100644
--- a/compiler/cli/cli-common/cli-common.iml
+++ b/compiler/cli/cli-common/cli-common.iml
@@ -11,5 +11,6 @@
+
\ No newline at end of file
diff --git a/compiler/cli/cli-common/src/org/jetbrains/kotlin/cli/common/repl/GenericReplCompiledEvaluator.kt b/compiler/cli/cli-common/src/org/jetbrains/kotlin/cli/common/repl/GenericReplCompiledEvaluator.kt
new file mode 100644
index 00000000000..07740419453
--- /dev/null
+++ b/compiler/cli/cli-common/src/org/jetbrains/kotlin/cli/common/repl/GenericReplCompiledEvaluator.kt
@@ -0,0 +1,84 @@
+/*
+ * Copyright 2010-2016 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.jetbrains.kotlin.cli.common.repl
+
+import org.jetbrains.kotlin.resolve.jvm.JvmClassName
+import java.io.File
+import java.net.URLClassLoader
+import java.util.concurrent.locks.ReentrantReadWriteLock
+import kotlin.concurrent.read
+import kotlin.concurrent.write
+
+open class GenericReplCompiledEvaluator(baseClasspath: Iterable) : ReplCompiledEvaluator {
+
+ private val classpath = baseClasspath.toMutableList()
+
+ 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))
+ private val classLoaderLock = ReentrantReadWriteLock()
+
+ private class ClassWithInstance(val klass: Class<*>, val instance: Any)
+
+ private val compiledLoadedClassesHistory = arrayListOf>()
+
+ override fun eval(codeLine: ReplCodeLine, history: Iterable, compiledClasses: List, hasResult: Boolean): ReplEvalResult {
+
+ checkAndUpdateReplHistoryCollection(compiledLoadedClassesHistory, history)?.let {
+ return@eval ReplEvalResult.HistoryMismatch(it)
+ }
+
+ classLoaderLock.read {
+ compiledClasses.filter { it.path.endsWith(".class") }
+ .forEach {
+ classLoader.addClass(JvmClassName.byInternalName(it.path.replaceFirst("\\.class$".toRegex(), "")), it.bytes)
+ }
+ }
+
+ val scriptClass = classLoaderLock.read { classLoader.loadClass("Line${codeLine.no}") }
+
+ val constructorParams = compiledLoadedClassesHistory.map { it.second.klass }.toTypedArray()
+ val constructorArgs = compiledLoadedClassesHistory.map { it.second.instance }.toTypedArray()
+
+ val scriptInstanceConstructor = scriptClass.getConstructor(*constructorParams)
+ val scriptInstance =
+ try {
+ evalWithIO { scriptInstanceConstructor.newInstance(*constructorArgs) }
+ }
+ catch (e: Throwable) {
+ // ignore everything in the stack trace until this constructor call
+ return ReplEvalResult.Error.Runtime(renderReplStackTrace(e.cause!!, startFromMethodName = "${scriptClass.name}."))
+ }
+
+ compiledLoadedClassesHistory.add(codeLine to 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
+ }
+
+ fun dependenciesAdded(newClasspath: List) {
+ 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"
+ }
+}
\ No newline at end of file
diff --git a/compiler/cli/cli-common/src/org/jetbrains/kotlin/cli/common/repl/Repl.kt b/compiler/cli/cli-common/src/org/jetbrains/kotlin/cli/common/repl/Repl.kt
new file mode 100644
index 00000000000..c6d18ee5e9c
--- /dev/null
+++ b/compiler/cli/cli-common/src/org/jetbrains/kotlin/cli/common/repl/Repl.kt
@@ -0,0 +1,82 @@
+/*
+ * Copyright 2010-2016 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.jetbrains.kotlin.cli.common.repl
+
+import java.io.File
+import java.io.Serializable
+import java.util.*
+
+data class ReplCodeLine(val no: Int, val code: String)
+
+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)
+}
+
+sealed class ReplCheckResult : Serializable {
+ object Ok : ReplCheckResult()
+ object Incomplete : ReplCheckResult()
+ class Error(val message: String) : ReplCheckResult()
+}
+
+sealed class ReplCompileResult : Serializable {
+ class CompiledClasses(val classes: List, val hasResult: Boolean) : ReplCompileResult()
+ object Incomplete : ReplCompileResult()
+ class HistoryMismatch(val lineNo: Int): ReplCompileResult()
+ class Error(val message: String) : ReplCompileResult()
+}
+
+sealed class ReplEvalResult : Serializable {
+ class ValueResult(val value: Any?) : ReplEvalResult()
+ 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)
+ }
+}
+
+interface ReplChecker {
+ fun check(codeLine: ReplCodeLine, history: Iterable): ReplCheckResult
+}
+
+interface ReplCompiler : ReplChecker {
+ fun compile(codeLine: ReplCodeLine, history: Iterable): ReplCompileResult
+
+ // a callback
+ fun dependenciesAdded(classpath: List)
+}
+
+interface ReplCompiledEvaluator {
+
+ fun eval(codeLine: ReplCodeLine, history: Iterable, compiledClasses: List, hasResult: Boolean): ReplEvalResult
+
+ // override to capture output
+ fun evalWithIO(body: () -> T): T = body()
+}
+
+
+interface ReplEvaluator : ReplChecker {
+
+ fun eval(codeLine: ReplCodeLine, history: Iterable): ReplEvalResult
+
+ fun dependenciesAdded(classpath: List)
+
+ // override to capture output
+ fun evalWithIO(body: () -> T): T = body()
+}
\ No newline at end of file
diff --git a/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/repl/ReplClassLoader.java b/compiler/cli/cli-common/src/org/jetbrains/kotlin/cli/common/repl/ReplClassLoader.java
similarity index 95%
rename from compiler/cli/src/org/jetbrains/kotlin/cli/jvm/repl/ReplClassLoader.java
rename to compiler/cli/cli-common/src/org/jetbrains/kotlin/cli/common/repl/ReplClassLoader.java
index c1d689043b1..e730b48cfde 100644
--- a/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/repl/ReplClassLoader.java
+++ b/compiler/cli/cli-common/src/org/jetbrains/kotlin/cli/common/repl/ReplClassLoader.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2010-2015 JetBrains s.r.o.
+ * Copyright 2010-2016 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package org.jetbrains.kotlin.cli.jvm.repl;
+package org.jetbrains.kotlin.cli.common.repl;
import com.google.common.collect.Maps;
import org.jetbrains.annotations.NotNull;
diff --git a/compiler/cli/cli-common/src/org/jetbrains/kotlin/cli/common/repl/replUtil.kt b/compiler/cli/cli-common/src/org/jetbrains/kotlin/cli/common/repl/replUtil.kt
new file mode 100644
index 00000000000..1f8e91ed5c8
--- /dev/null
+++ b/compiler/cli/cli-common/src/org/jetbrains/kotlin/cli/common/repl/replUtil.kt
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2010-2016 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.jetbrains.kotlin.cli.common.repl
+
+import com.google.common.base.Throwables
+
+fun checkAndUpdateReplHistoryCollection(col: MutableList>, baseHistory: Iterable): Int? {
+ val baseHistoryIt = baseHistory.iterator()
+ var idx = 0
+ while (baseHistoryIt.hasNext()) {
+ val curLine = baseHistoryIt.next()
+ if (col[idx].first != curLine) return curLine.no
+ idx += 1
+ }
+ col.dropLast(col.size - idx)
+ return null
+}
+
+fun renderReplStackTrace(cause: Throwable, startFromMethodName: String): String {
+ val newTrace = arrayListOf()
+ var skip = true
+ for ((i, element) in cause.stackTrace.withIndex().reversed()) {
+ if ("${element.className}.${element.methodName}" == startFromMethodName) {
+ skip = false
+ }
+ if (!skip) {
+ newTrace.add(element)
+ }
+ }
+
+ val resultingTrace = newTrace.reversed().dropLast(1)
+
+ @Suppress("PLATFORM_CLASS_MAPPED_TO_KOTLIN", "UsePropertyAccessSyntax")
+ (cause as java.lang.Throwable).setStackTrace(resultingTrace.toTypedArray())
+
+ return Throwables.getStackTraceAsString(cause)
+}
+
diff --git a/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/repl/GenericRepl.kt b/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/repl/GenericRepl.kt
index 4e5f97c65b4..518f574f562 100644
--- a/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/repl/GenericRepl.kt
+++ b/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/repl/GenericRepl.kt
@@ -16,7 +16,6 @@
package org.jetbrains.kotlin.cli.jvm.repl
-import com.google.common.base.Throwables
import com.intellij.openapi.Disposable
import com.intellij.openapi.diagnostic.Logger
import com.intellij.openapi.vfs.CharsetToolkit
@@ -26,6 +25,7 @@ import com.intellij.testFramework.LightVirtualFile
import org.jetbrains.kotlin.cli.common.CLIConfigurationKeys
import org.jetbrains.kotlin.cli.common.messages.AnalyzerWithCompilerReport
import org.jetbrains.kotlin.cli.common.messages.MessageCollector
+import org.jetbrains.kotlin.cli.common.repl.*
import org.jetbrains.kotlin.cli.jvm.compiler.EnvironmentConfigFiles
import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment
import org.jetbrains.kotlin.cli.jvm.config.JvmClasspathRoot
@@ -41,100 +41,97 @@ import org.jetbrains.kotlin.descriptors.ScriptDescriptor
import org.jetbrains.kotlin.idea.KotlinLanguage
import org.jetbrains.kotlin.parsing.KotlinParserDefinition
import org.jetbrains.kotlin.psi.KtFile
-import org.jetbrains.kotlin.resolve.jvm.JvmClassName
import org.jetbrains.kotlin.script.KotlinScriptDefinition
import org.jetbrains.kotlin.script.KotlinScriptExternalDependencies
import org.jetbrains.kotlin.script.ScriptParameter
-import java.net.URLClassLoader
-import java.util.concurrent.locks.ReentrantReadWriteLock
-import kotlin.concurrent.read
-import kotlin.concurrent.write
+import java.io.File
private val logger = Logger.getInstance(GenericRepl::class.java)
-open class GenericRepl(
+open class GenericReplChecker(
disposable: Disposable,
val scriptDefinition: KotlinScriptDefinition,
val compilerConfiguration: CompilerConfiguration,
messageCollector: MessageCollector
-) {
- private val environment = run {
+) : ReplChecker {
+ protected val environment = run {
compilerConfiguration.add(JVMConfigurationKeys.SCRIPT_DEFINITIONS, DelegatingScriptDefWithNoParams(scriptDefinition))
compilerConfiguration.put(CLIConfigurationKeys.MESSAGE_COLLECTOR_KEY, messageCollector)
KotlinCoreEnvironment.createForProduction(disposable, compilerConfiguration, EnvironmentConfigFiles.JVM_CONFIG_FILES)
}
- private val psiFileFactory: PsiFileFactoryImpl = PsiFileFactory.getInstance(environment.project) as PsiFileFactoryImpl
- private val analyzerEngine = CliReplAnalyzerEngine(environment)
+ protected val psiFileFactory: PsiFileFactoryImpl = PsiFileFactory.getInstance(environment.project) as PsiFileFactoryImpl
// "line" - is the unit of evaluation here, could in fact consists of several character lines
- private class LineState(
- val code: String,
+ protected class LineState(
+ val codeLine: ReplCodeLine,
val psiFile: KtFile,
val errorHolder: DiagnosticMessageHolder)
- sealed class EvalResult {
- class ValueResult(val value: Any?): EvalResult()
-
- object UnitResult: EvalResult()
- object Ready: EvalResult()
- object Incomplete : EvalResult()
-
- sealed class Error(val errorText: String): EvalResult() {
- class Runtime(errorText: String): Error(errorText)
- class CompileTime(errorText: String): Error(errorText)
- }
- }
-
- private class DelegatingScriptDefWithNoParams(parent: KotlinScriptDefinition) : KotlinScriptDefinition by parent {
+ protected class DelegatingScriptDefWithNoParams(parent: KotlinScriptDefinition) : KotlinScriptDefinition by parent {
override fun getScriptParameters(scriptDescriptor: ScriptDescriptor): List = emptyList()
}
- private var lineState: LineState? = null
+ protected var lineState: LineState? = null
- private var lastDependencies: KotlinScriptExternalDependencies? = null
-
- val classpath = compilerConfiguration.jvmClasspathRoots.toMutableList()
-
- private var classLoader: ReplClassLoader =
- ReplClassLoader(URLClassLoader(classpath.map { it.toURI().toURL() }.toTypedArray(), Thread.currentThread().contextClassLoader))
- private val classLoaderLock = ReentrantReadWriteLock()
-
- private val earlierLines = arrayListOf()
+ val classpath: MutableList = compilerConfiguration.jvmClasspathRoots.toMutableList()
fun createDiagnosticHolder() = ReplTerminalDiagnosticMessageHolder()
- fun checkComplete(executionNumber: Long, code: String): EvalResult {
+ override fun check(codeLine: ReplCodeLine, history: Iterable): ReplCheckResult {
synchronized(this) {
val virtualFile =
- LightVirtualFile("line$executionNumber${KotlinParserDefinition.STD_SCRIPT_EXT}", KotlinLanguage.INSTANCE, code).apply {
+ LightVirtualFile("line${codeLine.no}${KotlinParserDefinition.STD_SCRIPT_EXT}", KotlinLanguage.INSTANCE, codeLine.code).apply {
charset = CharsetToolkit.UTF8_CHARSET
}
val psiFile: KtFile = psiFileFactory.trySetupPsiForFile(virtualFile, KotlinLanguage.INSTANCE, true, false) as KtFile?
- ?: error("Script file not analyzed at line $executionNumber: $code")
+ ?: error("Script file not analyzed at line ${codeLine.no}: ${codeLine.code}")
val errorHolder = createDiagnosticHolder()
val syntaxErrorReport = AnalyzerWithCompilerReport.Companion.reportSyntaxErrors(psiFile, errorHolder)
if (!syntaxErrorReport.isHasErrors) {
- lineState = LineState(code, psiFile, errorHolder)
+ lineState = LineState(codeLine, psiFile, errorHolder)
}
return when {
- syntaxErrorReport.isHasErrors && syntaxErrorReport.isAllErrorsAtEof -> EvalResult.Incomplete
- syntaxErrorReport.isHasErrors -> EvalResult.Error.CompileTime(errorHolder.renderedDiagnostics)
- else -> EvalResult.Ready
+ syntaxErrorReport.isHasErrors && syntaxErrorReport.isAllErrorsAtEof -> ReplCheckResult.Incomplete
+ syntaxErrorReport.isHasErrors -> ReplCheckResult.Error(errorHolder.renderedDiagnostics)
+ else -> ReplCheckResult.Ok
}
}
}
+}
- fun eval(executionNumber: Long, code: String): EvalResult {
+
+abstract class GenericReplCompiler(
+ disposable: Disposable,
+ scriptDefinition: KotlinScriptDefinition,
+ compilerConfiguration: CompilerConfiguration,
+ messageCollector: MessageCollector
+) : ReplCompiler, GenericReplChecker(disposable, scriptDefinition, compilerConfiguration, messageCollector) {
+ private val analyzerEngine = CliReplAnalyzerEngine(environment)
+
+ private var lastDependencies: KotlinScriptExternalDependencies? = null
+
+ private val descriptorsHistory = arrayListOf>()
+
+ override fun compile(codeLine: ReplCodeLine, history: Iterable): ReplCompileResult {
synchronized(this) {
+
+ checkAndUpdateReplHistoryCollection(descriptorsHistory, history)?.let {
+ return@compile ReplCompileResult.HistoryMismatch(it)
+ }
+
val (psiFile, errorHolder) = run {
- if (lineState == null || lineState!!.code != code) {
- val res = checkComplete(executionNumber, code)
- if (res != EvalResult.Ready) return@eval res
+ if (lineState == null || lineState!!.codeLine != codeLine) {
+ val res = check(codeLine, history)
+ when (res) {
+ ReplCheckResult.Incomplete -> return@compile ReplCompileResult.Incomplete
+ is ReplCheckResult.Error -> return@compile ReplCompileResult.Error(res.message)
+ ReplCheckResult.Ok -> {} // continue
+ }
}
Pair(lineState!!.psiFile, lineState!!.errorHolder)
}
@@ -145,20 +142,17 @@ open class GenericRepl(
val newCp = environment.updateClasspath(it.classpath.map(::JvmClasspathRoot))
if (newCp != null && newCp.isNotEmpty()) {
logger.debug("new dependencies: $newCp")
- classLoaderLock.write {
- classpath.addAll(newCp)
- classLoader = ReplClassLoader(URLClassLoader(newCp.map { it.toURI().toURL() }.toTypedArray(), classLoader))
- }
+ dependenciesAdded(newCp)
}
}
if (lastDependencies != newDependencies) {
lastDependencies = newDependencies
}
- val analysisResult = analyzerEngine.analyzeReplLine(psiFile, executionNumber.toInt())
+ val analysisResult = analyzerEngine.analyzeReplLine(psiFile, codeLine.no)
AnalyzerWithCompilerReport.Companion.reportDiagnostics(analysisResult.diagnostics, errorHolder, false)
val scriptDescriptor = when (analysisResult) {
- is CliReplAnalyzerEngine.ReplLineAnalysisResult.WithErrors -> return EvalResult.Error.CompileTime(errorHolder.renderedDiagnostics)
+ is CliReplAnalyzerEngine.ReplLineAnalysisResult.WithErrors -> return ReplCompileResult.Error(errorHolder.renderedDiagnostics)
is CliReplAnalyzerEngine.ReplLineAnalysisResult.Successful -> analysisResult.scriptDescriptor
else -> error("Unexpected result ${analysisResult.javaClass}")
}
@@ -172,7 +166,7 @@ open class GenericRepl(
compilerConfiguration
)
state.replSpecific.scriptResultFieldName = SCRIPT_RESULT_FIELD_NAME
- state.replSpecific.earlierScriptsForReplInterpreter = earlierLines.map(EarlierLine::getScriptDescriptor)
+ state.replSpecific.earlierScriptsForReplInterpreter = descriptorsHistory.map { it.second }
state.beforeCompile()
KotlinCodegenFacade.generatePackage(
state,
@@ -180,68 +174,44 @@ open class GenericRepl(
setOf(psiFile.script!!.getContainingKtFile()),
org.jetbrains.kotlin.codegen.CompilationErrorHandler.THROW_EXCEPTION)
- for (outputFile in state.factory.asList()) {
- if (outputFile.relativePath.endsWith(".class")) {
- classLoaderLock.read {
- classLoader.addClass(JvmClassName.byInternalName(outputFile.relativePath.replaceFirst("\\.class$".toRegex(), "")),
- outputFile.asByteArray())
- }
- }
- }
+ descriptorsHistory.add(codeLine to scriptDescriptor)
- try {
- val scriptClass = classLoaderLock.read { classLoader.loadClass("Line$executionNumber") }
-
- val constructorParams = earlierLines.map(EarlierLine::getScriptClass).toTypedArray()
- val constructorArgs = earlierLines.map(EarlierLine::getScriptInstance).toTypedArray()
-
- val scriptInstanceConstructor = scriptClass.getConstructor(*constructorParams)
- val scriptInstance =
- try {
- evalWithIO { scriptInstanceConstructor.newInstance(*constructorArgs) }
- }
- catch (e: Throwable) {
- // ignore everything in the stack trace until this constructor call
- return EvalResult.Error.Runtime(renderStackTrace(e.cause!!, startFromMethodName = "${scriptClass.name}."))
- }
-
- val rvField = scriptClass.getDeclaredField(SCRIPT_RESULT_FIELD_NAME).apply { isAccessible = true }
- val rv: Any? = rvField.get(scriptInstance)
-
- earlierLines.add(EarlierLine(code, scriptDescriptor, scriptClass, scriptInstance))
-
- return if (state.replSpecific.hasResult) EvalResult.ValueResult(rv) else EvalResult.UnitResult
- }
- catch (e: Throwable) {
- throw e
- }
+ return ReplCompileResult.CompiledClasses(state.factory.asList().map { CompiledClassData(it.relativePath, it.asByteArray()) }, state.replSpecific.hasResult)
}
}
- // override to capture output
- open fun evalWithIO(body: () -> T): T = body()
-
companion object {
private val SCRIPT_RESULT_FIELD_NAME = "\$\$result"
+ }
+}
- private fun renderStackTrace(cause: Throwable, startFromMethodName: String): String {
- val newTrace = arrayListOf()
- var skip = true
- for ((i, element) in cause.stackTrace.withIndex().reversed()) {
- if ("${element.className}.${element.methodName}" == startFromMethodName) {
- skip = false
- }
- if (!skip) {
- newTrace.add(element)
+
+open class GenericRepl(
+ disposable: Disposable,
+ scriptDefinition: KotlinScriptDefinition,
+ compilerConfiguration: CompilerConfiguration,
+ messageCollector: MessageCollector
+) : ReplEvaluator, GenericReplCompiler(disposable, scriptDefinition, compilerConfiguration, messageCollector) {
+
+ private val compiledEvaluator = GenericReplCompiledEvaluator(classpath)
+
+ override fun eval(codeLine: ReplCodeLine, history: Iterable): 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
}
}
- val resultingTrace = newTrace.reversed().dropLast(1)
-
- @Suppress("PLATFORM_CLASS_MAPPED_TO_KOTLIN", "UsePropertyAccessSyntax")
- (cause as java.lang.Throwable).setStackTrace(resultingTrace.toTypedArray())
-
- return Throwables.getStackTraceAsString(cause)
+ return compiledEvaluator.eval(codeLine, history, compiledClasses, hasResult)
}
}
+
+ override fun dependenciesAdded(classpath: List) {
+ compiledEvaluator.dependenciesAdded(classpath)
+ }
}
diff --git a/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/repl/KotlinJsr232ScriptEngine.kt b/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/repl/KotlinJsr232ScriptEngine.kt
index a5a8ff0c5f2..03edacecae4 100644
--- a/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/repl/KotlinJsr232ScriptEngine.kt
+++ b/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/repl/KotlinJsr232ScriptEngine.kt
@@ -21,6 +21,8 @@ import org.jetbrains.kotlin.cli.common.messages.CompilerMessageLocation
import org.jetbrains.kotlin.cli.common.messages.CompilerMessageSeverity
import org.jetbrains.kotlin.cli.common.messages.MessageCollector
import org.jetbrains.kotlin.cli.common.messages.MessageRenderer
+import org.jetbrains.kotlin.cli.common.repl.ReplCodeLine
+import org.jetbrains.kotlin.cli.common.repl.ReplEvalResult
import org.jetbrains.kotlin.config.CompilerConfiguration
import org.jetbrains.kotlin.script.KotlinScriptDefinition
import java.io.Reader
@@ -72,20 +74,24 @@ class KotlinJsr232ScriptEngine(
private val repl = object : GenericRepl(disposable, scriptDefinition, compilerConfiguration, messageCollector) {}
- private var lineCount = 0L
+ private var lineCount = 0
+
+ private val history = arrayListOf()
override fun eval(script: String, context: ScriptContext?): Any? {
lineCount += 1
// TODO bind to context
- val evalResult = repl.eval(lineCount, script)
+ val codeLine = ReplCodeLine(lineCount, script)
+ val evalResult = repl.eval(codeLine, history)
messageCollector.resetAndThrowOnErrors()
val ret = when (evalResult) {
- is GenericRepl.EvalResult.ValueResult -> evalResult.value
- is GenericRepl.EvalResult.UnitResult -> null
- is GenericRepl.EvalResult.Error -> throw ScriptException(evalResult.errorText)
- is GenericRepl.EvalResult.Incomplete -> throw ScriptException("error: incomplete code")
- else -> throw ScriptException("Unexpected result from eval call: $evalResult")
+ is ReplEvalResult.ValueResult -> evalResult.value
+ is ReplEvalResult.UnitResult -> null
+ is ReplEvalResult.Error -> throw ScriptException(evalResult.message)
+ is ReplEvalResult.Incomplete -> throw ScriptException("error: incomplete code")
+ is ReplEvalResult.HistoryMismatch -> throw ScriptException("Repl history mismatch at line: ${evalResult.lineNo}")
}
+ history.add(codeLine)
// TODO update context
return ret
}
diff --git a/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/repl/ReplInterpreter.kt b/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/repl/ReplInterpreter.kt
index 9cc9361913c..cdd43c8e371 100644
--- a/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/repl/ReplInterpreter.kt
+++ b/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/repl/ReplInterpreter.kt
@@ -23,6 +23,7 @@ import com.intellij.psi.PsiFileFactory
import com.intellij.psi.impl.PsiFileFactoryImpl
import com.intellij.testFramework.LightVirtualFile
import org.jetbrains.kotlin.cli.common.messages.AnalyzerWithCompilerReport
+import org.jetbrains.kotlin.cli.common.repl.ReplClassLoader
import org.jetbrains.kotlin.cli.jvm.compiler.EnvironmentConfigFiles
import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment
import org.jetbrains.kotlin.cli.jvm.config.jvmClasspathRoots