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.jetbrains.kotlin.scripting.compiler.plugin.impl.KJvmReplCompilerImpl
|
||||||
import org.junit.Assert
|
import org.junit.Assert
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
import kotlin.script.experimental.annotations.KotlinScript
|
|
||||||
import kotlin.script.experimental.api.*
|
import kotlin.script.experimental.api.*
|
||||||
import kotlin.script.experimental.host.toScriptSource
|
import kotlin.script.experimental.host.toScriptSource
|
||||||
import kotlin.script.experimental.jvm.*import kotlin.script.experimental.jvm.util.classpathFromClass
|
import kotlin.script.experimental.jvm.BasicJvmScriptEvaluator
|
||||||
import kotlin.script.experimental.jvmhost.createJvmCompilationConfigurationFromTemplate
|
import kotlin.script.experimental.jvm.baseClassLoader
|
||||||
|
import kotlin.script.experimental.jvm.defaultJvmScriptingHostConfiguration
|
||||||
|
import kotlin.script.experimental.jvm.jvm
|
||||||
|
|
||||||
class ReplTest : TestCase() {
|
class ReplTest : TestCase() {
|
||||||
|
|
||||||
@@ -101,67 +102,67 @@ class ReplTest : TestCase() {
|
|||||||
sequenceOf(RuntimeException("abc"), null, 4)
|
sequenceOf(RuntimeException("abc"), null, 4)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fun evaluateInRepl(
|
fun evaluateInRepl(
|
||||||
compilationConfiguration: ScriptCompilationConfiguration,
|
compilationConfiguration: ScriptCompilationConfiguration,
|
||||||
evaluationConfiguration: ScriptEvaluationConfiguration,
|
evaluationConfiguration: ScriptEvaluationConfiguration?,
|
||||||
snippets: Sequence<String>
|
snippets: Sequence<String>
|
||||||
): Sequence<ResultWithDiagnostics<EvaluationResult>> {
|
): Sequence<ResultWithDiagnostics<EvaluationResult>> {
|
||||||
val replCompilerProxy =
|
val replCompilerProxy =
|
||||||
KJvmReplCompilerImpl(defaultJvmScriptingHostConfiguration)
|
KJvmReplCompilerImpl(defaultJvmScriptingHostConfiguration)
|
||||||
val compilationState = replCompilerProxy.createReplCompilationState(compilationConfiguration)
|
val compilationState = replCompilerProxy.createReplCompilationState(compilationConfiguration)
|
||||||
val compilationHistory = BasicReplStageHistory<ScriptDescriptor>()
|
val compilationHistory = BasicReplStageHistory<ScriptDescriptor>()
|
||||||
val replEvaluator = BasicJvmScriptEvaluator()
|
val replEvaluator = BasicJvmScriptEvaluator()
|
||||||
var currentEvalConfig = evaluationConfiguration
|
var currentEvalConfig = evaluationConfiguration ?: ScriptEvaluationConfiguration()
|
||||||
return snippets.mapIndexed { snippetNo, snippetText ->
|
return snippets.mapIndexed { snippetNo, snippetText ->
|
||||||
val snippetSource = snippetText.toScriptSource("Line_$snippetNo.simplescript.kts")
|
val snippetSource = snippetText.toScriptSource("Line_$snippetNo.${compilationConfiguration[ScriptCompilationConfiguration.fileExtension]}")
|
||||||
val snippetId = ReplSnippetIdImpl(snippetNo, 0, snippetSource)
|
val snippetId = ReplSnippetIdImpl(snippetNo, 0, snippetSource)
|
||||||
replCompilerProxy.compileReplSnippet(compilationState, snippetSource, snippetId, compilationHistory)
|
replCompilerProxy.compileReplSnippet(compilationState, snippetSource, snippetId, compilationHistory)
|
||||||
.onSuccess {
|
.onSuccess {
|
||||||
runBlocking {
|
runBlocking {
|
||||||
replEvaluator(it, currentEvalConfig)
|
replEvaluator(it, currentEvalConfig)
|
||||||
}
|
|
||||||
}
|
}
|
||||||
.onSuccess {
|
}
|
||||||
val snippetClass = it.returnValue.scriptClass
|
.onSuccess {
|
||||||
currentEvalConfig = ScriptEvaluationConfiguration(currentEvalConfig) {
|
val snippetClass = it.returnValue.scriptClass
|
||||||
previousSnippets.append(it.returnValue.scriptInstance)
|
currentEvalConfig = ScriptEvaluationConfiguration(currentEvalConfig) {
|
||||||
if (snippetClass != null) {
|
previousSnippets.append(it.returnValue.scriptInstance)
|
||||||
jvm {
|
if (snippetClass != null) {
|
||||||
baseClassLoader(snippetClass.java.classLoader)
|
jvm {
|
||||||
}
|
baseClassLoader(snippetClass.java.classLoader)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
it.asSuccess()
|
|
||||||
}
|
}
|
||||||
}
|
it.asSuccess()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fun chechEvaluateInRepl(
|
fun chechEvaluateInRepl(
|
||||||
compilationConfiguration: ScriptCompilationConfiguration,
|
compilationConfiguration: ScriptCompilationConfiguration,
|
||||||
evaluationConfiguration: ScriptEvaluationConfiguration,
|
evaluationConfiguration: ScriptEvaluationConfiguration?,
|
||||||
snippets: Sequence<String>,
|
snippets: Sequence<String>,
|
||||||
expected: Sequence<Any?>
|
expected: Sequence<Any?>
|
||||||
) {
|
) {
|
||||||
val expectedIter = expected.iterator()
|
val expectedIter = expected.iterator()
|
||||||
evaluateInRepl(compilationConfiguration, evaluationConfiguration, snippets).forEachIndexed { index, res ->
|
evaluateInRepl(compilationConfiguration, evaluationConfiguration, snippets).forEachIndexed { index, res ->
|
||||||
when (res) {
|
when (res) {
|
||||||
is ResultWithDiagnostics.Failure -> Assert.fail("#$index: Expected result, got $res")
|
is ResultWithDiagnostics.Failure -> Assert.fail("#$index: Expected result, got $res")
|
||||||
is ResultWithDiagnostics.Success -> {
|
is ResultWithDiagnostics.Success -> {
|
||||||
val expectedVal = expectedIter.next()
|
val expectedVal = expectedIter.next()
|
||||||
when (val resVal = res.value.returnValue) {
|
when (val resVal = res.value.returnValue) {
|
||||||
is ResultValue.Value -> Assert.assertEquals(
|
is ResultValue.Value -> Assert.assertEquals(
|
||||||
"#$index: Expected $expectedVal, got $resVal",
|
"#$index: Expected $expectedVal, got $resVal",
|
||||||
expectedVal,
|
expectedVal,
|
||||||
resVal.value
|
resVal.value
|
||||||
)
|
)
|
||||||
is ResultValue.Unit -> Assert.assertTrue("#$index: Expected $expectedVal, got Unit", expectedVal == null)
|
is ResultValue.Unit -> Assert.assertTrue("#$index: Expected $expectedVal, got Unit", expectedVal == null)
|
||||||
is ResultValue.Error -> Assert.assertTrue(
|
is ResultValue.Error -> Assert.assertTrue(
|
||||||
"#$index: Expected $expectedVal, got Error: ${resVal.error}",
|
"#$index: Expected $expectedVal, got Error: ${resVal.error}",
|
||||||
expectedVal is Throwable && expectedVal.message == resVal.error.message
|
expectedVal is Throwable && expectedVal.message == resVal.error.message
|
||||||
)
|
)
|
||||||
else -> Assert.assertTrue("#$index: Expected $expectedVal, got unknown result $resVal", expectedVal == null)
|
else -> Assert.assertTrue("#$index: Expected $expectedVal, got unknown result $resVal", expectedVal == null)
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+20
-7
@@ -6,7 +6,6 @@
|
|||||||
package kotlin.script.experimental.jvmhost.test
|
package kotlin.script.experimental.jvmhost.test
|
||||||
|
|
||||||
import junit.framework.TestCase
|
import junit.framework.TestCase
|
||||||
import org.junit.Ignore
|
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import kotlin.script.experimental.api.*
|
import kotlin.script.experimental.api.*
|
||||||
@@ -30,15 +29,16 @@ class ResolveDependenciesTest : TestCase() {
|
|||||||
private val classAccessScript = "${thisPackage}.ShouldBeVisibleFromScript().x".toScriptSource()
|
private val classAccessScript = "${thisPackage}.ShouldBeVisibleFromScript().x".toScriptSource()
|
||||||
private val classImportScript = "import ${thisPackage}.ShouldBeVisibleFromScript\nShouldBeVisibleFromScript().x".toScriptSource()
|
private val classImportScript = "import ${thisPackage}.ShouldBeVisibleFromScript\nShouldBeVisibleFromScript().x".toScriptSource()
|
||||||
|
|
||||||
private val funAndValAccessScript =
|
val funAndValAccessScriptText = "$thisPackage.funShouldBeVisibleFromScript($thisPackage.valShouldBeVisibleFromScript)"
|
||||||
"$thisPackage.funShouldBeVisibleFromScript($thisPackage.valShouldBeVisibleFromScript)".toScriptSource()
|
private val funAndValAccessScript = funAndValAccessScriptText.toScriptSource()
|
||||||
|
|
||||||
private val funAndValImportScript =
|
private val funAndValImportScriptText =
|
||||||
"""
|
"""
|
||||||
import $thisPackage.funShouldBeVisibleFromScript
|
import $thisPackage.funShouldBeVisibleFromScript
|
||||||
import $thisPackage.valShouldBeVisibleFromScript
|
import $thisPackage.valShouldBeVisibleFromScript
|
||||||
funShouldBeVisibleFromScript(valShouldBeVisibleFromScript)
|
funShouldBeVisibleFromScript(valShouldBeVisibleFromScript)
|
||||||
""".trimMargin().toScriptSource()
|
""".trimMargin()
|
||||||
|
private val funAndValImportScript = funAndValImportScriptText.toScriptSource()
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun testResolveClassFromClassloader() {
|
fun testResolveClassFromClassloader() {
|
||||||
@@ -53,12 +53,26 @@ class ResolveDependenciesTest : TestCase() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@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() {
|
fun testResolveFunAndValFromClassloader() {
|
||||||
runScriptAndCheckResult(funAndValAccessScript, configurationWithDependenciesFromClassloader, null, 42)
|
runScriptAndCheckResult(funAndValAccessScript, configurationWithDependenciesFromClassloader, null, 42)
|
||||||
runScriptAndCheckResult(funAndValImportScript, 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
|
@Test
|
||||||
fun testResolveFunAndValFromClasspath() {
|
fun testResolveFunAndValFromClasspath() {
|
||||||
runScriptAndCheckResult(funAndValAccessScript, configurationWithDependenciesFromClasspath, null, 42)
|
runScriptAndCheckResult(funAndValAccessScript, configurationWithDependenciesFromClasspath, null, 42)
|
||||||
@@ -105,7 +119,6 @@ class ResolveDependenciesTest : TestCase() {
|
|||||||
else -> throw Exception("Unexpected evaluation result: $res")
|
else -> throw Exception("Unexpected evaluation result: $res")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Suppress("unused")
|
@Suppress("unused")
|
||||||
|
|||||||
+7
@@ -103,6 +103,13 @@ class KJvmReplCompilerImpl(val hostConfiguration: ScriptingHostConfiguration) :
|
|||||||
messageCollector
|
messageCollector
|
||||||
)
|
)
|
||||||
|
|
||||||
|
if (history.isEmpty()) {
|
||||||
|
val updatedConfiguration = ScriptDependenciesProvider.getInstance(context.environment.project)
|
||||||
|
?.getScriptConfiguration(snippetKtFile)?.configuration
|
||||||
|
?: context.baseScriptCompilationConfiguration
|
||||||
|
registerPackageFragmetProvidersIfNeeded(updatedConfiguration, context.environment)
|
||||||
|
}
|
||||||
|
|
||||||
val analysisResult =
|
val analysisResult =
|
||||||
compilationState.analyzerEngine.analyzeReplLineWithImportedScripts(snippetKtFile, sourceFiles.drop(1), codeLine)
|
compilationState.analyzerEngine.analyzeReplLineWithImportedScripts(snippetKtFile, sourceFiles.drop(1), codeLine)
|
||||||
AnalyzerWithCompilerReport.reportDiagnostics(analysisResult.diagnostics, errorHolder)
|
AnalyzerWithCompilerReport.reportDiagnostics(analysisResult.diagnostics, errorHolder)
|
||||||
|
|||||||
Reference in New Issue
Block a user