diff --git a/libraries/scripting/jvm-host-test/test/kotlin/script/experimental/jvmhost/test/LegacyReplTest.kt b/libraries/scripting/jvm-host-test/test/kotlin/script/experimental/jvmhost/test/LegacyReplTest.kt index fe50d7ea948..301095543a5 100644 --- a/libraries/scripting/jvm-host-test/test/kotlin/script/experimental/jvmhost/test/LegacyReplTest.kt +++ b/libraries/scripting/jvm-host-test/test/kotlin/script/experimental/jvmhost/test/LegacyReplTest.kt @@ -44,6 +44,13 @@ class LegacyReplTest : TestCase() { } } + fun testReplSyntaxErrorsChecked() { + LegacyTestRepl().use { repl -> + val res = repl.compileAndEval(repl.nextCodeLine("data class Q(val x: Int, val: String)")) + TestCase.assertTrue("Expected compile error", res.first is ReplCompileResult.Error) + } + } + fun testReplCodeFormat() { LegacyTestRepl().use { repl -> val codeLine0 = ReplCodeLine(0, 0, "val l1 = 1\r\nl1\r\n") diff --git a/libraries/scripting/jvm-host-test/test/kotlin/script/experimental/jvmhost/test/ReplTest.kt b/libraries/scripting/jvm-host-test/test/kotlin/script/experimental/jvmhost/test/ReplTest.kt index c5bd2e1581e..0977f4392c0 100644 --- a/libraries/scripting/jvm-host-test/test/kotlin/script/experimental/jvmhost/test/ReplTest.kt +++ b/libraries/scripting/jvm-host-test/test/kotlin/script/experimental/jvmhost/test/ReplTest.kt @@ -10,6 +10,7 @@ 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.utils.addToStdlib.firstIsInstanceOrNull import org.junit.Assert import org.junit.Test import kotlin.script.experimental.api.* @@ -28,9 +29,7 @@ class ReplTest : TestCase() { @Test fun testCompileAndEval() { val out = captureOut { - chechEvaluateInRepl( - simpleScriptompilationConfiguration, - simpleScriptEvaluationConfiguration, + checkEvaluateInRepl( sequenceOf( "val x = 3", "x + 4", @@ -44,9 +43,7 @@ class ReplTest : TestCase() { @Test fun testEvalWithResult() { - chechEvaluateInRepl( - simpleScriptompilationConfiguration, - simpleScriptEvaluationConfiguration, + checkEvaluateInRepl( sequenceOf( "val x = 5", "x + 6", @@ -58,9 +55,7 @@ class ReplTest : TestCase() { @Test fun testEvalWithIfResult() { - chechEvaluateInRepl( - simpleScriptompilationConfiguration, - simpleScriptEvaluationConfiguration, + checkEvaluateInRepl( sequenceOf( "val x = 5", "x + 6", @@ -73,27 +68,25 @@ class ReplTest : TestCase() { @Test fun testImplicitReceiver() { val receiver = TestReceiver() - chechEvaluateInRepl( - simpleScriptompilationConfiguration.with { - implicitReceivers(TestReceiver::class) - }, - simpleScriptEvaluationConfiguration.with { - implicitReceivers(receiver) - }, + checkEvaluateInRepl( sequenceOf( "val x = 4", "x + prop1", "res1 * 3" ), - sequenceOf(null, 7, 21) + sequenceOf(null, 7, 21), + simpleScriptompilationConfiguration.with { + implicitReceivers(TestReceiver::class) + }, + simpleScriptEvaluationConfiguration.with { + implicitReceivers(receiver) + } ) } @Test fun testEvalWithError() { - chechEvaluateInRepl( - simpleScriptompilationConfiguration, - simpleScriptEvaluationConfiguration, + checkEvaluateInRepl( sequenceOf( "throw RuntimeException(\"abc\")", "val x = 3", @@ -102,12 +95,30 @@ class ReplTest : TestCase() { sequenceOf(RuntimeException("abc"), null, 4) ) } + + @Test + fun testSyntaxErrors() { + checkEvaluateInReplDiags( + sequenceOf( + "data class Q(val x: Int, val: String)", + "fun g(): Unit { return }}", + "fun f() : Int { return 1", + "6*7" + ), + sequenceOf( + makeFailureResult("Parameter name expected"), + makeFailureResult("Unexpected symbol"), + makeFailureResult("Expecting '}'"), + 42.asSuccess() + ) + ) + } } fun evaluateInRepl( - compilationConfiguration: ScriptCompilationConfiguration, - evaluationConfiguration: ScriptEvaluationConfiguration?, - snippets: Sequence + snippets: Sequence, + compilationConfiguration: ScriptCompilationConfiguration = simpleScriptompilationConfiguration, + evaluationConfiguration: ScriptEvaluationConfiguration? = simpleScriptEvaluationConfiguration ): Sequence> { val replCompilerProxy = KJvmReplCompilerImpl(defaultJvmScriptingHostConfiguration) @@ -139,18 +150,24 @@ fun evaluateInRepl( } } -fun chechEvaluateInRepl( - compilationConfiguration: ScriptCompilationConfiguration, - evaluationConfiguration: ScriptEvaluationConfiguration?, +fun checkEvaluateInReplDiags( snippets: Sequence, - expected: Sequence + expected: Sequence>, + compilationConfiguration: ScriptCompilationConfiguration = simpleScriptompilationConfiguration, + evaluationConfiguration: ScriptEvaluationConfiguration? = simpleScriptEvaluationConfiguration ) { 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() + evaluateInRepl(snippets, compilationConfiguration, evaluationConfiguration).forEachIndexed { index, res -> + val expectedRes = expectedIter.next() + when { + res is ResultWithDiagnostics.Failure && expectedRes is ResultWithDiagnostics.Failure -> { + Assert.assertTrue( + "#$index: Expected $expectedRes, got $res", + res.reports.map { it.message } == expectedRes.reports.map { it.message } + ) + } + 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", @@ -165,8 +182,21 @@ fun chechEvaluateInRepl( else -> Assert.assertTrue("#$index: Expected $expectedVal, got unknown result $resVal", expectedVal == null) } } + else -> { + Assert.fail("#$index: Expected $expectedRes, got $res") + } } } } +fun checkEvaluateInRepl( + snippets: Sequence, + expected: Sequence, + compilationConfiguration: ScriptCompilationConfiguration = simpleScriptompilationConfiguration, + evaluationConfiguration: ScriptEvaluationConfiguration? = simpleScriptEvaluationConfiguration +) = checkEvaluateInReplDiags( + snippets, expected.map { ResultWithDiagnostics.Success(it) }, compilationConfiguration, + evaluationConfiguration +) + class TestReceiver(val prop1: Int = 3) diff --git a/libraries/scripting/jvm-host-test/test/kotlin/script/experimental/jvmhost/test/ResolveDependenciesTest.kt b/libraries/scripting/jvm-host-test/test/kotlin/script/experimental/jvmhost/test/ResolveDependenciesTest.kt index 028ec11c692..8d838304362 100644 --- a/libraries/scripting/jvm-host-test/test/kotlin/script/experimental/jvmhost/test/ResolveDependenciesTest.kt +++ b/libraries/scripting/jvm-host-test/test/kotlin/script/experimental/jvmhost/test/ResolveDependenciesTest.kt @@ -60,15 +60,15 @@ class ResolveDependenciesTest : TestCase() { @Test fun testReplResolveFunAndValFromClassloader() { - chechEvaluateInRepl( - configurationWithDependenciesFromClassloader, null, - sequenceOf(funAndValAccessScriptText, funAndValAccessScriptText), - sequenceOf(42, 42) + checkEvaluateInRepl( + sequenceOf(funAndValAccessScriptText, funAndValAccessScriptText), sequenceOf(42, 42), + configurationWithDependenciesFromClassloader, + null ) - chechEvaluateInRepl( - configurationWithDependenciesFromClassloader, null, - funAndValImportScriptText.split('\n').asSequence(), - sequenceOf(null, null, 42) + checkEvaluateInRepl( + funAndValImportScriptText.split('\n').asSequence(), sequenceOf(null, null, 42), + configurationWithDependenciesFromClassloader, + null ) runScriptAndCheckResult(funAndValImportScript, configurationWithDependenciesFromClassloader, null, 42) } diff --git a/plugins/scripting/scripting-compiler/src/org/jetbrains/kotlin/scripting/compiler/plugin/impl/KJvmReplCompilerImpl.kt b/plugins/scripting/scripting-compiler/src/org/jetbrains/kotlin/scripting/compiler/plugin/impl/KJvmReplCompilerImpl.kt index 10309d61b98..003cb54300a 100644 --- a/plugins/scripting/scripting-compiler/src/org/jetbrains/kotlin/scripting/compiler/plugin/impl/KJvmReplCompilerImpl.kt +++ b/plugins/scripting/scripting-compiler/src/org/jetbrains/kotlin/scripting/compiler/plugin/impl/KJvmReplCompilerImpl.kt @@ -96,6 +96,9 @@ class KJvmReplCompilerImpl(val hostConfiguration: ScriptingHostConfiguration) : ) .valueOr { return it } + val syntaxErrorReport = AnalyzerWithCompilerReport.reportSyntaxErrors(snippetKtFile, errorHolder) + if (syntaxErrorReport.isHasErrors) return failure(messageCollector) + val (sourceFiles, sourceDependencies) = collectRefinedSourcesAndUpdateEnvironment( context, snippetKtFile,