Refactor Repl: use sealed class to represent line result

This commit is contained in:
Pavel V. Talanov
2016-05-31 17:42:46 +03:00
parent 17832e10e7
commit 8ac40d7401
3 changed files with 43 additions and 92 deletions
@@ -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)
@@ -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() -> "<unknown error>"
!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)
}
}