From 8ac40d7401b0ee0457f5a1e1267de646b053704f Mon Sep 17 00:00:00 2001 From: "Pavel V. Talanov" Date: Tue, 31 May 2016 17:42:46 +0300 Subject: [PATCH] Refactor Repl: use sealed class to represent line result --- .../kotlin/cli/jvm/repl/ReplFromTerminal.kt | 34 +++----- .../kotlin/cli/jvm/repl/ReplInterpreter.kt | 87 +++++-------------- .../repl/AbstractReplInterpreterTest.kt | 14 +-- 3 files changed, 43 insertions(+), 92 deletions(-) diff --git a/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/repl/ReplFromTerminal.kt b/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/repl/ReplFromTerminal.kt index a6f380eee9f..e84f5fd94c7 100644 --- a/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/repl/ReplFromTerminal.kt +++ b/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/repl/ReplFromTerminal.kt @@ -19,6 +19,7 @@ package org.jetbrains.kotlin.cli.jvm.repl import com.intellij.openapi.Disposable import com.intellij.openapi.util.io.FileUtil import org.jetbrains.kotlin.cli.common.KotlinVersion +import org.jetbrains.kotlin.cli.jvm.repl.LineResult.* import org.jetbrains.kotlin.cli.jvm.repl.messages.unescapeLineBreaks import org.jetbrains.kotlin.config.CompilerConfiguration import java.io.File @@ -84,8 +85,8 @@ class ReplFromTerminal( return if (notQuit) WhatNextAfterOneLine.READ_LINE else WhatNextAfterOneLine.QUIT } - val lineResultType = eval(line) - if (lineResultType === ReplInterpreter.LineResultType.INCOMPLETE) { + val lineResult = eval(line) + if (lineResult is LineResult.Incomplete) { return WhatNextAfterOneLine.INCOMPLETE } else { @@ -93,27 +94,20 @@ class ReplFromTerminal( } } - private fun eval(line: String): ReplInterpreter.LineResultType { + private fun eval(line: String): LineResult { val lineResult = replInterpreter.eval(line) - if (lineResult.type === ReplInterpreter.LineResultType.SUCCESS) { - writer.notifyCommandSuccess() - if (!lineResult.isUnit) { - writer.outputCommandResult(lineResult.value) + when (lineResult) { + is ValueResult, UnitResult -> { + writer.notifyCommandSuccess() + if (lineResult is ValueResult) { + writer.outputCommandResult(lineResult.value) + } } + Incomplete -> writer.notifyIncomplete() + is Error.CompileTime -> writer.outputCompileError(lineResult.errorText) + is Error.Runtime -> writer.outputRuntimeError(lineResult.errorText) } - else if (lineResult.type === ReplInterpreter.LineResultType.INCOMPLETE) { - writer.notifyIncomplete() - } - else if (lineResult.type === ReplInterpreter.LineResultType.COMPILE_ERROR) { - writer.outputCompileError(lineResult.errorText!!) - } - else if (lineResult.type === ReplInterpreter.LineResultType.RUNTIME_ERROR) { - writer.outputRuntimeError(lineResult.errorText!!) - } - else { - throw IllegalStateException("unknown line result type: " + lineResult) - } - return lineResult.type + return lineResult } @Throws(Exception::class) diff --git a/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/repl/ReplInterpreter.kt b/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/repl/ReplInterpreter.kt index cc5610ac85d..dd413fbca06 100644 --- a/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/repl/ReplInterpreter.kt +++ b/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/repl/ReplInterpreter.kt @@ -70,66 +70,6 @@ class ReplInterpreter( private val psiFileFactory: PsiFileFactoryImpl = PsiFileFactory.getInstance(environment.project) as PsiFileFactoryImpl private val analyzerEngine = CliReplAnalyzerEngine(environment) - enum class LineResultType { - SUCCESS, - COMPILE_ERROR, - RUNTIME_ERROR, - INCOMPLETE - } - - class LineResult private constructor( - private val resultingValue: Any?, - private val unit: Boolean, - val errorText: String?, - val type: LineResultType - ) { - val value: Any? - get() { - checkSuccessful() - return resultingValue - } - - val isUnit: Boolean - get() { - checkSuccessful() - return unit - } - - private fun checkSuccessful() { - if (type != LineResultType.SUCCESS) { - error("it is error") - } - } - - companion object { - private fun error(errorText: String, errorType: LineResultType): LineResult { - val resultingErrorText = when { - errorText.isEmpty() -> "" - !errorText.endsWith("\n") -> errorText + "\n" - else -> errorText - } - - return LineResult(null, false, resultingErrorText, errorType) - } - - fun successful(value: Any?, unit: Boolean): LineResult { - return LineResult(value, unit, null, LineResultType.SUCCESS) - } - - fun compileError(errorText: String): LineResult { - return error(errorText, LineResultType.COMPILE_ERROR) - } - - fun runtimeError(errorText: String): LineResult { - return error(errorText, LineResultType.RUNTIME_ERROR) - } - - fun incomplete(): LineResult { - return LineResult(null, false, null, LineResultType.INCOMPLETE) - } - } - } - fun eval(line: String): LineResult { ++lineNumber @@ -149,23 +89,23 @@ class ReplInterpreter( if (syntaxErrorReport.isHasErrors && syntaxErrorReport.isAllErrorsAtEof) { return if (allowIncompleteLines) { previousIncompleteLines.add(line) - LineResult.incomplete() + LineResult.Incomplete } else { - LineResult.compileError(errorHolder.renderedDiagnostics) + LineResult.Error.CompileTime(errorHolder.renderedDiagnostics) } } previousIncompleteLines.clear() if (syntaxErrorReport.isHasErrors) { - return LineResult.compileError(errorHolder.renderedDiagnostics) + return LineResult.Error.CompileTime(errorHolder.renderedDiagnostics) } val analysisResult = analyzerEngine.analyzeReplLine(psiFile, lineNumber) AnalyzerWithCompilerReport.reportDiagnostics(analysisResult.diagnostics, errorHolder, false) val scriptDescriptor = when (analysisResult) { - is WithErrors -> return LineResult.compileError(errorHolder.renderedDiagnostics) + is WithErrors -> return LineResult.Error.CompileTime(errorHolder.renderedDiagnostics) is Successful -> analysisResult.scriptDescriptor else -> error("Unexpected result ${analysisResult.javaClass}") } @@ -196,7 +136,7 @@ class ReplInterpreter( scriptInstanceConstructor.newInstance(*constructorArgs) } catch (e: Throwable) { - return LineResult.runtimeError(renderStackTrace(e.cause!!)) + return LineResult.Error.Runtime(renderStackTrace(e.cause!!)) } finally { onUserCodeExecuting(false) @@ -207,7 +147,10 @@ class ReplInterpreter( earlierLines.add(EarlierLine(line, scriptDescriptor, scriptClass, scriptInstance)) - return LineResult.successful(rv, !state.replSpecific.hasResult) + if (!state.replSpecific.hasResult) { + return LineResult.UnitResult + } + return LineResult.ValueResult(rv) } catch (e: Throwable) { val writer = PrintWriter(System.err) @@ -275,3 +218,15 @@ class ReplInterpreter( } } } + +sealed class LineResult { + class ValueResult(val value: Any?): LineResult() + + object UnitResult: LineResult() + object Incomplete : LineResult() + + sealed class Error(val errorText: String): LineResult() { + class Runtime(errorText: String): Error(errorText) + class CompileTime(errorText: String): Error(errorText) + } +} diff --git a/compiler/tests/org/jetbrains/kotlin/repl/AbstractReplInterpreterTest.kt b/compiler/tests/org/jetbrains/kotlin/repl/AbstractReplInterpreterTest.kt index 5b859685b64..3e13a7618bc 100644 --- a/compiler/tests/org/jetbrains/kotlin/repl/AbstractReplInterpreterTest.kt +++ b/compiler/tests/org/jetbrains/kotlin/repl/AbstractReplInterpreterTest.kt @@ -17,6 +17,8 @@ package org.jetbrains.kotlin.repl import com.intellij.openapi.util.text.StringUtil +import org.jetbrains.kotlin.cli.jvm.repl.ConsoleReplConfiguration +import org.jetbrains.kotlin.cli.jvm.repl.LineResult import org.jetbrains.kotlin.cli.jvm.repl.ReplInterpreter import org.jetbrains.kotlin.test.ConfigurationKind import org.jetbrains.kotlin.test.KotlinTestUtils @@ -81,7 +83,7 @@ abstract class AbstractReplInterpreterTest : KtUsefulTestCase() { protected fun doTest(path: String) { val configuration = KotlinTestUtils.newConfiguration(ConfigurationKind.ALL, TestJdkKind.MOCK_JDK) - val repl = ReplInterpreter(testRootDisposable, configuration, false, null) + val repl = ReplInterpreter(testRootDisposable, configuration, ConsoleReplConfiguration()) for ((code, expected) in loadLines(File(path))) { val lineResult = repl.eval(code) @@ -90,11 +92,11 @@ abstract class AbstractReplInterpreterTest : KtUsefulTestCase() { repl.dumpClasses(PrintWriter(System.out)) } - val actual = when (lineResult.type) { - ReplInterpreter.LineResultType.SUCCESS -> if (!lineResult.isUnit) "${lineResult.value}" else "" - ReplInterpreter.LineResultType.RUNTIME_ERROR, - ReplInterpreter.LineResultType.COMPILE_ERROR -> lineResult.errorText!! - ReplInterpreter.LineResultType.INCOMPLETE -> INCOMPLETE_LINE_MESSAGE + val actual = when (lineResult) { + is LineResult.ValueResult -> "${lineResult.value}" + is LineResult.Error -> lineResult.errorText + LineResult.Incomplete -> INCOMPLETE_LINE_MESSAGE + LineResult.UnitResult -> "" } Assert.assertEquals(