Add new REPL API JVM implementation
This commit is contained in:
committed by
Ilya Chernikov
parent
4c2c44b106
commit
d2fec96f38
+5
-5
@@ -21,8 +21,8 @@ import kotlin.script.experimental.jvmhost.repl.JvmReplEvaluator
|
||||
class LegacyReplTest : TestCase() {
|
||||
fun testReplBasics() {
|
||||
LegacyTestRepl().use { repl ->
|
||||
val res1 = repl.replCompiler.check(repl.state, ReplCodeLine(0, 0, "val x ="))
|
||||
TestCase.assertTrue("Unexpected check results: $res1", res1 is ReplCheckResult.Incomplete)
|
||||
val res1 = repl.replCompiler.compile(repl.state, ReplCodeLine(0, 0, "val x ="))
|
||||
TestCase.assertTrue("Unexpected check results: $res1", res1 is ReplCompileResult.Incomplete)
|
||||
|
||||
assertEvalResult(repl, "val l1 = listOf(1 + 2)\nl1.first()", 3)
|
||||
|
||||
@@ -54,8 +54,8 @@ class LegacyReplTest : TestCase() {
|
||||
fun testReplCodeFormat() {
|
||||
LegacyTestRepl().use { repl ->
|
||||
val codeLine0 = ReplCodeLine(0, 0, "val l1 = 1\r\nl1\r\n")
|
||||
val res0 = repl.replCompiler.check(repl.state, codeLine0)
|
||||
val res0c = res0 as? ReplCheckResult.Ok
|
||||
val res0 = repl.replCompiler.compile(repl.state, codeLine0)
|
||||
val res0c = res0 as? ReplCompileResult.CompiledClasses
|
||||
TestCase.assertNotNull("Unexpected compile result: $res0", res0c)
|
||||
}
|
||||
}
|
||||
@@ -125,7 +125,7 @@ internal class LegacyTestRepl : Closeable {
|
||||
fun nextCodeLine(code: String): ReplCodeLine = ReplCodeLine(currentLineCounter.getAndIncrement(), 0, code)
|
||||
|
||||
val replCompiler: JvmReplCompiler by lazy {
|
||||
JvmReplCompiler(simpleScriptCompilationConfiguration)
|
||||
JvmReplCompiler(simpleScriptCompilationConfiguration, false)
|
||||
}
|
||||
|
||||
val compiledEvaluator: ReplEvaluator by lazy {
|
||||
|
||||
+91
-104
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
@@ -7,24 +7,16 @@ package kotlin.script.experimental.jvmhost.test
|
||||
|
||||
import junit.framework.TestCase
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import org.jetbrains.kotlin.cli.common.repl.BasicReplStageHistory
|
||||
import org.jetbrains.kotlin.descriptors.ScriptDescriptor
|
||||
import org.jetbrains.kotlin.scripting.compiler.plugin.impl.KJvmReplCompilerImpl
|
||||
import org.jetbrains.kotlin.scripting.compiler.plugin.impl.KJvmReplCompilerBase
|
||||
import org.junit.Assert
|
||||
import org.junit.Test
|
||||
import kotlin.script.experimental.api.*
|
||||
import kotlin.script.experimental.host.toScriptSource
|
||||
import kotlin.script.experimental.jvm.BasicJvmScriptEvaluator
|
||||
import kotlin.script.experimental.jvm.baseClassLoader
|
||||
import kotlin.script.experimental.jvm.BasicJvmReplEvaluator
|
||||
import kotlin.script.experimental.jvm.defaultJvmScriptingHostConfiguration
|
||||
import kotlin.script.experimental.jvm.jvm
|
||||
|
||||
class ReplTest : TestCase() {
|
||||
|
||||
companion object {
|
||||
const val TEST_DATA_DIR = "libraries/scripting/jvm-host-test/testData"
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testCompileAndEval() {
|
||||
val out = captureOut {
|
||||
@@ -156,103 +148,98 @@ class ReplTest : TestCase() {
|
||||
limit = 100
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fun evaluateInRepl(
|
||||
snippets: Sequence<String>,
|
||||
compilationConfiguration: ScriptCompilationConfiguration = simpleScriptCompilationConfiguration,
|
||||
evaluationConfiguration: ScriptEvaluationConfiguration? = simpleScriptEvaluationConfiguration,
|
||||
limit: Int = 0
|
||||
): Sequence<ResultWithDiagnostics<EvaluationResult>> {
|
||||
val replCompilerProxy =
|
||||
KJvmReplCompilerImpl(defaultJvmScriptingHostConfiguration)
|
||||
val compilationState = replCompilerProxy.createReplCompilationState(compilationConfiguration)
|
||||
val compilationHistory = BasicReplStageHistory<ScriptDescriptor>()
|
||||
val replEvaluator = BasicJvmScriptEvaluator()
|
||||
var currentEvalConfig = evaluationConfiguration ?: ScriptEvaluationConfiguration()
|
||||
val snipetsLimited = if (limit == 0) snippets else snippets.take(limit)
|
||||
return snipetsLimited.mapIndexed { snippetNo, snippetText ->
|
||||
val snippetSource =
|
||||
snippetText.toScriptSource("Line_$snippetNo.${compilationConfiguration[ScriptCompilationConfiguration.fileExtension]}")
|
||||
val snippetId = ReplSnippetIdImpl(snippetNo, 0, snippetSource)
|
||||
replCompilerProxy.compileReplSnippet(compilationState, snippetSource, snippetId, compilationHistory)
|
||||
.onSuccess {
|
||||
runBlocking {
|
||||
replEvaluator(it, currentEvalConfig)
|
||||
}
|
||||
}
|
||||
.onSuccess {
|
||||
val snippetClass = it.returnValue.scriptClass
|
||||
currentEvalConfig = ScriptEvaluationConfiguration(currentEvalConfig) {
|
||||
previousSnippets.append(it.returnValue.scriptInstance)
|
||||
if (snippetClass != null) {
|
||||
jvm {
|
||||
baseClassLoader(snippetClass.java.classLoader)
|
||||
}
|
||||
companion object {
|
||||
private fun evaluateInRepl(
|
||||
snippets: Sequence<String>,
|
||||
compilationConfiguration: ScriptCompilationConfiguration = simpleScriptCompilationConfiguration,
|
||||
evaluationConfiguration: ScriptEvaluationConfiguration? = simpleScriptEvaluationConfiguration,
|
||||
limit: Int = 0
|
||||
): Sequence<ResultWithDiagnostics<EvaluatedSnippet>> {
|
||||
val replCompiler = KJvmReplCompilerBase.create(defaultJvmScriptingHostConfiguration)
|
||||
val replEvaluator = BasicJvmReplEvaluator()
|
||||
val currentEvalConfig = evaluationConfiguration ?: ScriptEvaluationConfiguration()
|
||||
val snipetsLimited = if (limit == 0) snippets else snippets.take(limit)
|
||||
return snipetsLimited.mapIndexed { snippetNo, snippetText ->
|
||||
val snippetSource =
|
||||
snippetText.toScriptSource("Line_$snippetNo.${compilationConfiguration[ScriptCompilationConfiguration.fileExtension]}")
|
||||
runBlocking { replCompiler.compile(snippetSource, compilationConfiguration) }
|
||||
.onSuccess {
|
||||
runBlocking { replEvaluator.eval(it, currentEvalConfig) }
|
||||
}
|
||||
}
|
||||
it.asSuccess()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun checkEvaluateInReplDiags(
|
||||
snippets: Sequence<String>,
|
||||
expected: Sequence<ResultWithDiagnostics<Any?>>,
|
||||
compilationConfiguration: ScriptCompilationConfiguration = simpleScriptCompilationConfiguration,
|
||||
evaluationConfiguration: ScriptEvaluationConfiguration? = simpleScriptEvaluationConfiguration,
|
||||
limit: Int = 0
|
||||
) {
|
||||
val expectedIter = (if (limit == 0) expected else expected.take(limit)).iterator()
|
||||
evaluateInRepl(snippets, compilationConfiguration, evaluationConfiguration, limit).forEachIndexed { index, res ->
|
||||
val expectedRes = expectedIter.next()
|
||||
when {
|
||||
res is ResultWithDiagnostics.Failure && expectedRes is ResultWithDiagnostics.Failure -> {
|
||||
Assert.assertTrue(
|
||||
"#$index: Expected $expectedRes, got $res. Messages are different",
|
||||
res.reports.map { it.message } == expectedRes.reports.map { it.message }
|
||||
)
|
||||
Assert.assertTrue(
|
||||
"#$index: Expected $expectedRes, got $res. Locations are different",
|
||||
res.reports.map { it.location }.zip(expectedRes.reports.map { it.location }).all {
|
||||
it.second == null || it.second == it.first
|
||||
.onSuccess {
|
||||
it.get().asSuccess()
|
||||
}
|
||||
)
|
||||
}
|
||||
res is ResultWithDiagnostics.Success && expectedRes is ResultWithDiagnostics.Success -> {
|
||||
val expectedVal = expectedRes.value
|
||||
when (val resVal = res.value.returnValue) {
|
||||
is ResultValue.Value -> Assert.assertEquals(
|
||||
"#$index: Expected $expectedVal, got $resVal",
|
||||
expectedVal,
|
||||
resVal.value
|
||||
)
|
||||
is ResultValue.Unit -> Assert.assertTrue("#$index: Expected $expectedVal, got Unit", expectedVal == null)
|
||||
is ResultValue.Error -> Assert.assertTrue(
|
||||
"#$index: Expected $expectedVal, got Error: ${resVal.error}",
|
||||
expectedVal is Throwable && expectedVal.message == resVal.error.message
|
||||
)
|
||||
else -> Assert.assertTrue("#$index: Expected $expectedVal, got unknown result $resVal", expectedVal == null)
|
||||
}
|
||||
}
|
||||
else -> {
|
||||
Assert.fail("#$index: Expected $expectedRes, got $res")
|
||||
}
|
||||
}
|
||||
}
|
||||
if (expectedIter.hasNext()) {
|
||||
Assert.fail("Expected ${expectedIter.next()} got end of results stream")
|
||||
|
||||
fun checkEvaluateInReplDiags(
|
||||
snippets: Sequence<String>,
|
||||
expected: Sequence<ResultWithDiagnostics<Any?>>,
|
||||
compilationConfiguration: ScriptCompilationConfiguration = simpleScriptCompilationConfiguration,
|
||||
evaluationConfiguration: ScriptEvaluationConfiguration? = simpleScriptEvaluationConfiguration,
|
||||
limit: Int = 0
|
||||
) {
|
||||
val expectedIter = (if (limit == 0) expected else expected.take(limit)).iterator()
|
||||
evaluateInRepl(snippets, compilationConfiguration, evaluationConfiguration, limit).forEachIndexed { index, res ->
|
||||
val expectedRes = expectedIter.next()
|
||||
when {
|
||||
res is ResultWithDiagnostics.Failure && expectedRes is ResultWithDiagnostics.Failure -> {
|
||||
|
||||
val resReports = res.reports.filter {
|
||||
it.code != ScriptDiagnostic.incompleteCode
|
||||
}
|
||||
Assert.assertTrue(
|
||||
"#$index: Expected $expectedRes, got $res. Messages are different",
|
||||
resReports.map { it.message } == expectedRes.reports.map { it.message }
|
||||
)
|
||||
Assert.assertTrue(
|
||||
"#$index: Expected $expectedRes, got $res. Locations are different",
|
||||
resReports.map { it.location }.zip(expectedRes.reports.map { it.location }).all {
|
||||
it.second == null || it.second == it.first
|
||||
}
|
||||
)
|
||||
}
|
||||
res is ResultWithDiagnostics.Success && expectedRes is ResultWithDiagnostics.Success -> {
|
||||
val expectedVal = expectedRes.value
|
||||
val resVal = res.value.result
|
||||
when (resVal) {
|
||||
is ResultValue.Value -> Assert.assertEquals(
|
||||
"#$index: Expected $expectedVal, got $resVal",
|
||||
expectedVal,
|
||||
resVal.value
|
||||
)
|
||||
is ResultValue.Unit -> Assert.assertNull("#$index: Expected $expectedVal, got Unit", expectedVal)
|
||||
is ResultValue.Error -> Assert.assertTrue(
|
||||
"#$index: Expected $expectedVal, got Error: ${resVal.error}",
|
||||
expectedVal is Throwable && expectedVal.message == resVal.error?.message
|
||||
)
|
||||
else -> Assert.assertTrue("#$index: Expected $expectedVal, got unknown result $resVal", expectedVal == null)
|
||||
}
|
||||
}
|
||||
else -> {
|
||||
Assert.fail("#$index: Expected $expectedRes, got $res")
|
||||
}
|
||||
}
|
||||
}
|
||||
if (expectedIter.hasNext()) {
|
||||
Assert.fail("Expected ${expectedIter.next()} got end of results stream")
|
||||
}
|
||||
}
|
||||
|
||||
fun checkEvaluateInRepl(
|
||||
snippets: Sequence<String>,
|
||||
expected: Sequence<Any?>,
|
||||
compilationConfiguration: ScriptCompilationConfiguration = simpleScriptCompilationConfiguration,
|
||||
evaluationConfiguration: ScriptEvaluationConfiguration? = simpleScriptEvaluationConfiguration,
|
||||
limit: Int = 0
|
||||
) = checkEvaluateInReplDiags(
|
||||
snippets, expected.map { ResultWithDiagnostics.Success(it) }, compilationConfiguration, evaluationConfiguration, limit
|
||||
)
|
||||
|
||||
class TestReceiver(
|
||||
@Suppress("unused")
|
||||
val prop1: Int = 3
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fun checkEvaluateInRepl(
|
||||
snippets: Sequence<String>,
|
||||
expected: Sequence<Any?>,
|
||||
compilationConfiguration: ScriptCompilationConfiguration = simpleScriptCompilationConfiguration,
|
||||
evaluationConfiguration: ScriptEvaluationConfiguration? = simpleScriptEvaluationConfiguration,
|
||||
limit: Int = 0
|
||||
) = checkEvaluateInReplDiags(
|
||||
snippets, expected.map { ResultWithDiagnostics.Success(it) }, compilationConfiguration, evaluationConfiguration, limit
|
||||
)
|
||||
|
||||
class TestReceiver(val prop1: Int = 3)
|
||||
|
||||
+1
@@ -13,6 +13,7 @@ import kotlin.script.experimental.host.toScriptSource
|
||||
import kotlin.script.experimental.jvm.*
|
||||
import kotlin.script.experimental.jvm.util.classpathFromClass
|
||||
import kotlin.script.experimental.jvmhost.BasicJvmScriptingHost
|
||||
import kotlin.script.experimental.jvmhost.test.ReplTest.Companion.checkEvaluateInRepl
|
||||
|
||||
class ResolveDependenciesTest : TestCase() {
|
||||
|
||||
|
||||
+1
-2
@@ -21,7 +21,6 @@ import java.net.URLClassLoader
|
||||
import java.nio.file.Files
|
||||
import java.util.concurrent.TimeUnit
|
||||
import java.util.jar.JarFile
|
||||
import kotlin.reflect.KClass
|
||||
import kotlin.script.experimental.api.*
|
||||
import kotlin.script.experimental.host.BasicScriptingHost
|
||||
import kotlin.script.experimental.host.FileBasedScriptSource
|
||||
@@ -348,7 +347,7 @@ class ScriptingHostTest : TestCase() {
|
||||
assertTrue(compiledScript is ResultWithDiagnostics.Success)
|
||||
|
||||
val jvmCompiledScript = compiledScript.valueOrNull()!! as KJvmCompiledScript
|
||||
val jvmCompiledModule = jvmCompiledScript.compiledModule as KJvmCompiledModuleInMemoryImpl
|
||||
val jvmCompiledModule = jvmCompiledScript.getCompiledModule() as KJvmCompiledModuleInMemoryImpl
|
||||
val bytes = jvmCompiledModule.compilerOutputFiles["SavedScript.class"]!!
|
||||
|
||||
var classFileVersion: Int? = null
|
||||
|
||||
Reference in New Issue
Block a user