Add resolving from classloader to REPL pipeline
This commit is contained in:
+58
-57
@@ -12,11 +12,12 @@ import org.jetbrains.kotlin.descriptors.ScriptDescriptor
|
||||
import org.jetbrains.kotlin.scripting.compiler.plugin.impl.KJvmReplCompilerImpl
|
||||
import org.junit.Assert
|
||||
import org.junit.Test
|
||||
import kotlin.script.experimental.annotations.KotlinScript
|
||||
import kotlin.script.experimental.api.*
|
||||
import kotlin.script.experimental.host.toScriptSource
|
||||
import kotlin.script.experimental.jvm.*import kotlin.script.experimental.jvm.util.classpathFromClass
|
||||
import kotlin.script.experimental.jvmhost.createJvmCompilationConfigurationFromTemplate
|
||||
import kotlin.script.experimental.jvm.BasicJvmScriptEvaluator
|
||||
import kotlin.script.experimental.jvm.baseClassLoader
|
||||
import kotlin.script.experimental.jvm.defaultJvmScriptingHostConfiguration
|
||||
import kotlin.script.experimental.jvm.jvm
|
||||
|
||||
class ReplTest : TestCase() {
|
||||
|
||||
@@ -101,67 +102,67 @@ class ReplTest : TestCase() {
|
||||
sequenceOf(RuntimeException("abc"), null, 4)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fun evaluateInRepl(
|
||||
compilationConfiguration: ScriptCompilationConfiguration,
|
||||
evaluationConfiguration: ScriptEvaluationConfiguration,
|
||||
snippets: Sequence<String>
|
||||
): Sequence<ResultWithDiagnostics<EvaluationResult>> {
|
||||
val replCompilerProxy =
|
||||
KJvmReplCompilerImpl(defaultJvmScriptingHostConfiguration)
|
||||
val compilationState = replCompilerProxy.createReplCompilationState(compilationConfiguration)
|
||||
val compilationHistory = BasicReplStageHistory<ScriptDescriptor>()
|
||||
val replEvaluator = BasicJvmScriptEvaluator()
|
||||
var currentEvalConfig = evaluationConfiguration
|
||||
return snippets.mapIndexed { snippetNo, snippetText ->
|
||||
val snippetSource = snippetText.toScriptSource("Line_$snippetNo.simplescript.kts")
|
||||
val snippetId = ReplSnippetIdImpl(snippetNo, 0, snippetSource)
|
||||
replCompilerProxy.compileReplSnippet(compilationState, snippetSource, snippetId, compilationHistory)
|
||||
.onSuccess {
|
||||
runBlocking {
|
||||
replEvaluator(it, currentEvalConfig)
|
||||
}
|
||||
fun evaluateInRepl(
|
||||
compilationConfiguration: ScriptCompilationConfiguration,
|
||||
evaluationConfiguration: ScriptEvaluationConfiguration?,
|
||||
snippets: Sequence<String>
|
||||
): Sequence<ResultWithDiagnostics<EvaluationResult>> {
|
||||
val replCompilerProxy =
|
||||
KJvmReplCompilerImpl(defaultJvmScriptingHostConfiguration)
|
||||
val compilationState = replCompilerProxy.createReplCompilationState(compilationConfiguration)
|
||||
val compilationHistory = BasicReplStageHistory<ScriptDescriptor>()
|
||||
val replEvaluator = BasicJvmScriptEvaluator()
|
||||
var currentEvalConfig = evaluationConfiguration ?: ScriptEvaluationConfiguration()
|
||||
return snippets.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)
|
||||
}
|
||||
}
|
||||
.onSuccess {
|
||||
val snippetClass = it.returnValue.scriptClass
|
||||
currentEvalConfig = ScriptEvaluationConfiguration(currentEvalConfig) {
|
||||
previousSnippets.append(it.returnValue.scriptInstance)
|
||||
if (snippetClass != null) {
|
||||
jvm {
|
||||
baseClassLoader(snippetClass.java.classLoader)
|
||||
}
|
||||
}
|
||||
it.asSuccess()
|
||||
}
|
||||
}
|
||||
it.asSuccess()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun chechEvaluateInRepl(
|
||||
compilationConfiguration: ScriptCompilationConfiguration,
|
||||
evaluationConfiguration: ScriptEvaluationConfiguration,
|
||||
snippets: Sequence<String>,
|
||||
expected: Sequence<Any?>
|
||||
) {
|
||||
val expectedIter = expected.iterator()
|
||||
evaluateInRepl(compilationConfiguration, evaluationConfiguration, snippets).forEachIndexed { index, res ->
|
||||
when (res) {
|
||||
is ResultWithDiagnostics.Failure -> Assert.fail("#$index: Expected result, got $res")
|
||||
is ResultWithDiagnostics.Success -> {
|
||||
val expectedVal = expectedIter.next()
|
||||
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)
|
||||
}
|
||||
fun chechEvaluateInRepl(
|
||||
compilationConfiguration: ScriptCompilationConfiguration,
|
||||
evaluationConfiguration: ScriptEvaluationConfiguration?,
|
||||
snippets: Sequence<String>,
|
||||
expected: Sequence<Any?>
|
||||
) {
|
||||
val expectedIter = expected.iterator()
|
||||
evaluateInRepl(compilationConfiguration, evaluationConfiguration, snippets).forEachIndexed { index, res ->
|
||||
when (res) {
|
||||
is ResultWithDiagnostics.Failure -> Assert.fail("#$index: Expected result, got $res")
|
||||
is ResultWithDiagnostics.Success -> {
|
||||
val expectedVal = expectedIter.next()
|
||||
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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+20
-7
@@ -6,7 +6,6 @@
|
||||
package kotlin.script.experimental.jvmhost.test
|
||||
|
||||
import junit.framework.TestCase
|
||||
import org.junit.Ignore
|
||||
import org.junit.Test
|
||||
import java.io.File
|
||||
import kotlin.script.experimental.api.*
|
||||
@@ -30,15 +29,16 @@ class ResolveDependenciesTest : TestCase() {
|
||||
private val classAccessScript = "${thisPackage}.ShouldBeVisibleFromScript().x".toScriptSource()
|
||||
private val classImportScript = "import ${thisPackage}.ShouldBeVisibleFromScript\nShouldBeVisibleFromScript().x".toScriptSource()
|
||||
|
||||
private val funAndValAccessScript =
|
||||
"$thisPackage.funShouldBeVisibleFromScript($thisPackage.valShouldBeVisibleFromScript)".toScriptSource()
|
||||
val funAndValAccessScriptText = "$thisPackage.funShouldBeVisibleFromScript($thisPackage.valShouldBeVisibleFromScript)"
|
||||
private val funAndValAccessScript = funAndValAccessScriptText.toScriptSource()
|
||||
|
||||
private val funAndValImportScript =
|
||||
private val funAndValImportScriptText =
|
||||
"""
|
||||
import $thisPackage.funShouldBeVisibleFromScript
|
||||
import $thisPackage.valShouldBeVisibleFromScript
|
||||
funShouldBeVisibleFromScript(valShouldBeVisibleFromScript)
|
||||
""".trimMargin().toScriptSource()
|
||||
""".trimMargin()
|
||||
private val funAndValImportScript = funAndValImportScriptText.toScriptSource()
|
||||
|
||||
@Test
|
||||
fun testResolveClassFromClassloader() {
|
||||
@@ -53,12 +53,26 @@ class ResolveDependenciesTest : TestCase() {
|
||||
}
|
||||
|
||||
@Test
|
||||
// This doesn't work since there is no way to resolve a top-level function/property via reflection now (see #KT-33892)
|
||||
fun testResolveFunAndValFromClassloader() {
|
||||
runScriptAndCheckResult(funAndValAccessScript, configurationWithDependenciesFromClassloader, null, 42)
|
||||
runScriptAndCheckResult(funAndValImportScript, configurationWithDependenciesFromClassloader, null, 42)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testReplResolveFunAndValFromClassloader() {
|
||||
chechEvaluateInRepl(
|
||||
configurationWithDependenciesFromClassloader, null,
|
||||
sequenceOf(funAndValAccessScriptText, funAndValAccessScriptText),
|
||||
sequenceOf(42, 42)
|
||||
)
|
||||
chechEvaluateInRepl(
|
||||
configurationWithDependenciesFromClassloader, null,
|
||||
funAndValImportScriptText.split('\n').asSequence(),
|
||||
sequenceOf(null, null, 42)
|
||||
)
|
||||
runScriptAndCheckResult(funAndValImportScript, configurationWithDependenciesFromClassloader, null, 42)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testResolveFunAndValFromClasspath() {
|
||||
runScriptAndCheckResult(funAndValAccessScript, configurationWithDependenciesFromClasspath, null, 42)
|
||||
@@ -105,7 +119,6 @@ class ResolveDependenciesTest : TestCase() {
|
||||
else -> throw Exception("Unexpected evaluation result: $res")
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Suppress("unused")
|
||||
|
||||
Reference in New Issue
Block a user