Improve script and REPL result handling:

- implement error result
- refactor other result classes
- implement handling in the script evaluation extension - also restores
  previous script error reporting functionality
- add possibility to customize result fileds in script and REPL
- refactor result calculation in the backend: cleanup, rename (since
  it is not only about REPL now)
This commit is contained in:
Ilya Chernikov
2019-07-04 13:33:15 +02:00
parent dc4370ff08
commit 9ae0ff03fa
23 changed files with 421 additions and 127 deletions
@@ -77,13 +77,16 @@ open class GenericReplCompiler(
val analysisResult = compilerState.analyzerEngine.analyzeReplLine(psiFile, codeLine)
AnalyzerWithCompilerReport.reportDiagnostics(analysisResult.diagnostics, errorHolder)
val scriptDescriptor = when (analysisResult) {
is ReplCodeAnalyzer.ReplLineAnalysisResult.WithErrors -> return ReplCompileResult.Error(errorHolder.renderMessage())
is ReplCodeAnalyzer.ReplLineAnalysisResult.Successful -> analysisResult.scriptDescriptor
is ReplCodeAnalyzer.ReplLineAnalysisResult.WithErrors -> {
return ReplCompileResult.Error(errorHolder.renderMessage())
}
is ReplCodeAnalyzer.ReplLineAnalysisResult.Successful -> {
(analysisResult.scriptDescriptor as? ScriptDescriptor)
?: error("Unexpected script descriptor type ${analysisResult.scriptDescriptor::class}")
}
else -> error("Unexpected result ${analysisResult::class.java}")
}
val type = (scriptDescriptor as ScriptDescriptor).resultValue?.returnType
val generationState = GenerationState.Builder(
psiFile.project,
ClassBuilderFactories.BINARIES,
@@ -93,9 +96,7 @@ open class GenericReplCompiler(
compilerConfiguration
).build()
generationState.replSpecific.resultType = type
generationState.replSpecific.scriptResultFieldName = scriptResultFieldName(codeLine.no)
generationState.replSpecific.earlierScriptsForReplInterpreter = compilerState.history.map { it.item }
generationState.scriptSpecific.earlierScriptsForReplInterpreter = compilerState.history.map { it.item }
generationState.beforeCompile()
KotlinCodegenFacade.generatePackage(
generationState,
@@ -114,9 +115,9 @@ open class GenericReplCompiler(
compilerState.history.map { it.id },
generatedClassname,
classes,
generationState.replSpecific.hasResult,
generationState.scriptSpecific.resultFieldName != null,
classpathAddendum ?: emptyList(),
generationState.replSpecific.resultType?.let {
generationState.scriptSpecific.resultType?.let {
DescriptorRenderer.FQ_NAMES_IN_TYPES.renderType(it)
},
null
@@ -90,14 +90,23 @@ class LazyScriptDescriptor(
}
fun resultFieldName(): String? {
val scriptPriority = scriptInfo.script.getUserData(ScriptPriorities.PRIORITY_KEY)
if (scriptPriority != null) {
return "res$scriptPriority"
// TODO: implement robust REPL/script selection
val replSnippetId =
scriptInfo.script.getUserData(ScriptPriorities.PRIORITY_KEY)?.toString()
?: run {
val scriptName = name.asString()
if (scriptName.startsWith("Line_"))
scriptName.split("_")[1]
else null
}
return if (replSnippetId != null) {
// assuming repl
scriptCompilationConfiguration()[ScriptCompilationConfiguration.repl.resultFieldPrefix]?.takeIf { it.isNotBlank() }?.let {
"$it$replSnippetId"
}
} else {
scriptCompilationConfiguration()[ScriptCompilationConfiguration.resultField]?.takeIf { it.isNotBlank() }
}
val scriptName = name.asString()
return if (scriptName.startsWith("Line_")) {
"res${scriptName.split("_")[1]}"
} else "\$\$result"
}
private val sourceElement = scriptInfo.script.toSourceElement()