Skip to content

Commit 706fbee

Browse files
committed
Switch to a new REPL API
1 parent 2a78703 commit 706fbee

File tree

4 files changed

+41
-27
lines changed

4 files changed

+41
-27
lines changed

src/main/kotlin/org/jetbrains/kotlin/jupyter/repl.kt

+10-11
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package org.jetbrains.kotlin.jupyter
33
import jupyter.kotlin.*
44
import jupyter.kotlin.KotlinContext
55
import jupyter.kotlin.KotlinReceiver
6+
import kotlinx.coroutines.runBlocking
67
import org.jetbrains.kotlin.config.KotlinCompilerVersion
78
import org.jetbrains.kotlin.jupyter.repl.completion.CompletionResult
89
import org.jetbrains.kotlin.jupyter.repl.completion.KotlinCompleter
@@ -19,9 +20,7 @@ import kotlin.script.dependencies.ScriptContents
1920
import kotlin.script.experimental.api.*
2021
import kotlin.script.experimental.host.withDefaultsFrom
2122
import kotlin.script.experimental.jvm.*
22-
import kotlin.script.experimental.util.hasErrors
23-
import kotlin.script.experimental.util.isIncomplete
24-
import kotlin.script.experimental.util.renderError
23+
import kotlin.script.experimental.util.*
2524

2625
data class EvalResult(val resultValue: Any?)
2726

@@ -264,7 +263,7 @@ class ReplForJupyterImpl(val scriptClasspath: List<File> = emptyList(),
264263

265264
override fun checkComplete(executionNumber: Long, code: String): CheckResult {
266265
val codeLine = SourceCodeImpl(executionNumber.toInt(), code)
267-
val result = compiler.analyze(codeLine, 0, compilerConfiguration)
266+
val result = runBlocking { compiler.analyze(codeLine, 0.toSourceCodePosition(codeLine), compilerConfiguration) }
268267
return when {
269268
result.isIncomplete() -> CheckResult(false)
270269
result.hasErrors() -> throw ReplException(result.renderError())
@@ -322,7 +321,7 @@ class ReplForJupyterImpl(val scriptClasspath: List<File> = emptyList(),
322321
typeRenderers.putAll(p.typeRenderers.map { it.className to it.code })
323322
}
324323

325-
private fun lastReplLine() = evaluator.lastEvaluatedSnippet()?.snippetObject
324+
private fun lastReplLine() = evaluator.lastEvaluatedSnippet?.get()?.snippetClass
326325

327326
override fun eval(code: String, displayHandler: ((Any) -> Unit)?, jupyterId: Int): EvalResult {
328327
synchronized(this) {
@@ -413,7 +412,7 @@ class ReplForJupyterImpl(val scriptClasspath: List<File> = emptyList(),
413412
override suspend fun listErrors(code: String, callback: (ListErrorsResult) -> Unit) = doWithLock(ListErrorsArgs(code, callback), listErrorsQueue, ListErrorsResult(code)) {
414413
//val preprocessed = preprocessCode(code)
415414
val codeLine = SourceCodeImpl(executionCounter++, code)
416-
val errorsList = compiler.analyze(codeLine, 0, compilerConfiguration)
415+
val errorsList = runBlocking { compiler.analyze(codeLine, 0.toSourceCodePosition(codeLine), compilerConfiguration) }
417416
ListErrorsResult(code, errorsList.valueOrThrow())
418417
}
419418

@@ -463,25 +462,25 @@ class ReplForJupyterImpl(val scriptClasspath: List<File> = emptyList(),
463462
println(code)
464463
val id = executionCounter++
465464
val codeLine = SourceCodeImpl(id, code)
466-
when (val compileResultWithDiagnostics = compiler.compile(codeLine, compilerConfiguration)) {
465+
when (val compileResultWithDiagnostics = runBlocking { compiler.compile(codeLine, compilerConfiguration) }) {
467466
is ResultWithDiagnostics.Success -> {
468467
val compileResult = compileResultWithDiagnostics.value
469-
classWriter?.writeClasses(compileResult())
468+
classWriter?.writeClasses(compileResult.get())
470469
val repl = this
471470
val currentEvalConfig = ScriptEvaluationConfiguration(evaluatorConfiguration) {
472471
constructorArgs.invoke(repl as KotlinKernelHost)
473472
}
474-
val result = evaluator.eval(compileResult, currentEvalConfig).valueOrThrow()
473+
val result = runBlocking { evaluator.eval(compileResult, currentEvalConfig).valueOrThrow() }
475474
contextUpdater.update()
476475

477-
val pureResult = result()
476+
val pureResult = result.get()
478477
return when {
479478
pureResult.isErrorResult -> throw ReplEvalRuntimeException(pureResult.error?.message.orEmpty(), pureResult.error)
480479
pureResult.isUnitResult -> {
481480
InternalEvalResult(Unit, null)
482481
}
483482
pureResult.isValueResult -> {
484-
InternalEvalResult(pureResult.result, pureResult.compiledSnippet().resultField)
483+
InternalEvalResult(pureResult.result, pureResult.compiledSnippet.resultField)
485484
}
486485
else -> throw IllegalStateException("Unknown eval result type ${this}")
487486
}

src/main/kotlin/org/jetbrains/kotlin/jupyter/repl/completion/KotlinCompleter.kt

+6-6
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
package org.jetbrains.kotlin.jupyter.repl.completion
22

33
import com.beust.klaxon.JsonObject
4+
import kotlinx.coroutines.runBlocking
45
import org.jetbrains.annotations.TestOnly
56
import org.jetbrains.kotlin.jupyter.jsonObject
67
import java.io.PrintWriter
78
import java.io.StringWriter
89
import kotlin.script.experimental.api.*
9-
import kotlin.script.experimental.util.ReplCompletionVariant
10-
import kotlin.script.experimental.util.ReplDiagnosticMessage
10+
import kotlin.script.experimental.util.toSourceCodePosition
1111

1212
enum class CompletionStatus(private val value: String) {
1313
OK("ok"),
@@ -30,7 +30,7 @@ abstract class CompletionResult(
3030
open class Success(
3131
private val matches: List<String>,
3232
private val bounds: CompletionTokenBounds,
33-
private val metadata: List<ReplCompletionVariant>,
33+
private val metadata: List<SourceCodeCompletionVariant>,
3434
private val text: String,
3535
private val cursor: Int
3636
): CompletionResult(CompletionStatus.OK) {
@@ -91,7 +91,7 @@ abstract class CompletionResult(
9191
}
9292
}
9393

94-
data class ListErrorsResult(val code: String, val errors: Iterable<ReplDiagnosticMessage> = emptyList()) {
94+
data class ListErrorsResult(val code: String, val errors: Sequence<ScriptDiagnostic> = emptySequence()) {
9595
fun toJson(): JsonObject {
9696
return jsonObject("code" to code,
9797
"errors" to errors.map {
@@ -100,7 +100,7 @@ data class ListErrorsResult(val code: String, val errors: Iterable<ReplDiagnosti
100100
"severity" to it.severity.name
101101
)
102102

103-
val loc = it.loc
103+
val loc = it.location
104104
if (loc != null) {
105105
val start = loc.start
106106
val end = loc.end
@@ -122,7 +122,7 @@ class KotlinCompleter {
122122
fun complete(compiler: ReplCompleter, configuration: ScriptCompilationConfiguration, code: String, id: Int, cursor: Int): CompletionResult {
123123
return try {
124124
val codeLine = SourceCodeImpl(id, code)
125-
val completionResult = compiler.complete(codeLine, cursor, configuration)
125+
val completionResult = runBlocking { compiler.complete(codeLine, cursor.toSourceCodePosition(codeLine), configuration) }
126126

127127
completionResult.valueOrNull()?.toList()?.let { completionList ->
128128
val bounds = getTokenBounds(code, cursor)

src/main/kotlin/org/jetbrains/kotlin/jupyter/util.kt

+17-3
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,10 @@ import kotlinx.coroutines.*
44
import org.jetbrains.kotlin.scripting.ide_services.evaluator.KJvmEvaluatedSnippet
55
import org.slf4j.Logger
66
import java.io.File
7-
import kotlin.script.experimental.api.ILinkedPushStack
8-
import kotlin.script.experimental.api.toList
7+
import kotlin.script.experimental.api.ScriptDiagnostic
8+
import kotlin.script.experimental.api.SourceCode
9+
import kotlin.script.experimental.util.LinkedSnippet
10+
import kotlin.script.experimental.util.toList
911

1012
fun <T> catchAll(body: () -> T): T? = try {
1113
body()
@@ -46,4 +48,16 @@ fun File.tryReadIniConfig() =
4648

4749

4850

49-
fun ILinkedPushStack<KJvmEvaluatedSnippet>?.instances() = this.toList { it.snippetObject }.filterNotNull()
51+
fun LinkedSnippet<KJvmEvaluatedSnippet>?.instances() = this.toList { it.snippetObject }.filterNotNull()
52+
53+
fun generateDiagnostic(fromLine: Int, fromCol: Int, toLine: Int, toCol: Int, message: String, severity: String) =
54+
ScriptDiagnostic(
55+
ScriptDiagnostic.unspecifiedError,
56+
message,
57+
ScriptDiagnostic.Severity.valueOf(severity),
58+
null,
59+
SourceCode.Location(SourceCode.Position(fromLine, fromCol), SourceCode.Position(toLine, toCol))
60+
)
61+
62+
fun withPath(path: String?, diagnostics: List<ScriptDiagnostic>): List<ScriptDiagnostic> =
63+
diagnostics.map { it.copy(sourcePath = path) }

src/test/kotlin/org/jetbrains/kotlin/jupyter/test/replTests.kt

+8-7
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@ import org.junit.Assert
1111
import org.junit.Ignore
1212
import org.junit.Test
1313
import java.io.File
14-
import kotlin.script.experimental.util.ReplDiagnosticMessage
1514
import kotlin.script.experimental.api.SourceCode
1615
import kotlin.test.*
1716

@@ -186,12 +185,14 @@ class ReplTest {
186185
val b: Int = "str"
187186
val c = foob
188187
""".trimIndent()) {result ->
189-
Assert.assertEquals(listOf(
190-
ReplDiagnosticMessage(1, 16, 1, 20, "Type mismatch: inferred type is String but Int was expected", "ERROR"),
191-
ReplDiagnosticMessage(1, 22, 1, 26, "The floating-point literal does not conform to the expected type String", "ERROR"),
192-
ReplDiagnosticMessage(2, 14, 2, 19, "Type mismatch: inferred type is String but Int was expected", "ERROR"),
193-
ReplDiagnosticMessage(3, 9, 3, 13, "Unresolved reference: foob", "ERROR")
194-
), result.errors)
188+
val actualErrors = result.errors.toList()
189+
val path = actualErrors.first().sourcePath
190+
Assert.assertEquals(withPath(path, listOf(
191+
generateDiagnostic(1, 16, 1, 20, "Type mismatch: inferred type is String but Int was expected", "ERROR"),
192+
generateDiagnostic(1, 22, 1, 26, "The floating-point literal does not conform to the expected type String", "ERROR"),
193+
generateDiagnostic(2, 14, 2, 19, "Type mismatch: inferred type is String but Int was expected", "ERROR"),
194+
generateDiagnostic(3, 9, 3, 13, "Unresolved reference: foob", "ERROR")
195+
)), actualErrors)
195196
}
196197
}
197198
}

0 commit comments

Comments
 (0)