J2K ReplInterpreter: prettify
This commit is contained in:
committed by
Alexander Udalov
parent
5670e7f750
commit
2e13377d4a
@@ -17,27 +17,23 @@
|
|||||||
package org.jetbrains.kotlin.cli.jvm.repl
|
package org.jetbrains.kotlin.cli.jvm.repl
|
||||||
|
|
||||||
import com.google.common.base.Throwables
|
import com.google.common.base.Throwables
|
||||||
import com.google.common.collect.Lists
|
|
||||||
import com.intellij.openapi.Disposable
|
import com.intellij.openapi.Disposable
|
||||||
import com.intellij.openapi.project.Project
|
|
||||||
import com.intellij.openapi.vfs.CharsetToolkit
|
import com.intellij.openapi.vfs.CharsetToolkit
|
||||||
import com.intellij.psi.PsiFile
|
import com.intellij.psi.PsiFile
|
||||||
import com.intellij.psi.PsiFileFactory
|
import com.intellij.psi.PsiFileFactory
|
||||||
import com.intellij.psi.impl.PsiFileFactoryImpl
|
import com.intellij.psi.impl.PsiFileFactoryImpl
|
||||||
import com.intellij.psi.search.ProjectScope
|
import com.intellij.psi.search.ProjectScope
|
||||||
import com.intellij.testFramework.LightVirtualFile
|
import com.intellij.testFramework.LightVirtualFile
|
||||||
import org.jetbrains.kotlin.backend.common.output.OutputFile
|
|
||||||
import org.jetbrains.kotlin.cli.common.messages.AnalyzerWithCompilerReport
|
import org.jetbrains.kotlin.cli.common.messages.AnalyzerWithCompilerReport
|
||||||
import org.jetbrains.kotlin.cli.common.messages.DiagnosticMessageReporter
|
import org.jetbrains.kotlin.cli.common.messages.DiagnosticMessageReporter
|
||||||
import org.jetbrains.kotlin.cli.jvm.compiler.CliLightClassGenerationSupport
|
import org.jetbrains.kotlin.cli.jvm.compiler.CliLightClassGenerationSupport
|
||||||
import org.jetbrains.kotlin.cli.jvm.compiler.EnvironmentConfigFiles
|
import org.jetbrains.kotlin.cli.jvm.compiler.EnvironmentConfigFiles
|
||||||
import org.jetbrains.kotlin.cli.jvm.compiler.JvmPackagePartProvider
|
import org.jetbrains.kotlin.cli.jvm.compiler.JvmPackagePartProvider
|
||||||
import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment
|
import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment
|
||||||
import org.jetbrains.kotlin.cli.jvm.config.*
|
import org.jetbrains.kotlin.cli.jvm.config.getModuleName
|
||||||
import org.jetbrains.kotlin.cli.jvm.config.*
|
import org.jetbrains.kotlin.cli.jvm.config.jvmClasspathRoots
|
||||||
import org.jetbrains.kotlin.cli.jvm.repl.di.ContainerForReplWithJava
|
|
||||||
import org.jetbrains.kotlin.cli.jvm.repl.di.*
|
|
||||||
import org.jetbrains.kotlin.cli.jvm.repl.di.ReplLastLineScopeProvider
|
import org.jetbrains.kotlin.cli.jvm.repl.di.ReplLastLineScopeProvider
|
||||||
|
import org.jetbrains.kotlin.cli.jvm.repl.di.createContainerForReplWithJava
|
||||||
import org.jetbrains.kotlin.cli.jvm.repl.messages.DiagnosticMessageHolder
|
import org.jetbrains.kotlin.cli.jvm.repl.messages.DiagnosticMessageHolder
|
||||||
import org.jetbrains.kotlin.cli.jvm.repl.messages.ReplIdeDiagnosticMessageHolder
|
import org.jetbrains.kotlin.cli.jvm.repl.messages.ReplIdeDiagnosticMessageHolder
|
||||||
import org.jetbrains.kotlin.cli.jvm.repl.messages.ReplSystemInWrapper
|
import org.jetbrains.kotlin.cli.jvm.repl.messages.ReplSystemInWrapper
|
||||||
@@ -48,7 +44,6 @@ import org.jetbrains.kotlin.codegen.KotlinCodegenFacade
|
|||||||
import org.jetbrains.kotlin.codegen.state.GenerationState
|
import org.jetbrains.kotlin.codegen.state.GenerationState
|
||||||
import org.jetbrains.kotlin.config.CommonConfigurationKeys
|
import org.jetbrains.kotlin.config.CommonConfigurationKeys
|
||||||
import org.jetbrains.kotlin.config.CompilerConfiguration
|
import org.jetbrains.kotlin.config.CompilerConfiguration
|
||||||
import org.jetbrains.kotlin.context.MutableModuleContext
|
|
||||||
import org.jetbrains.kotlin.descriptors.ScriptDescriptor
|
import org.jetbrains.kotlin.descriptors.ScriptDescriptor
|
||||||
import org.jetbrains.kotlin.descriptors.impl.CompositePackageFragmentProvider
|
import org.jetbrains.kotlin.descriptors.impl.CompositePackageFragmentProvider
|
||||||
import org.jetbrains.kotlin.descriptors.impl.ModuleDescriptorImpl
|
import org.jetbrains.kotlin.descriptors.impl.ModuleDescriptorImpl
|
||||||
@@ -65,33 +60,25 @@ import org.jetbrains.kotlin.resolve.jvm.TopDownAnalyzerFacadeForJVM
|
|||||||
import org.jetbrains.kotlin.resolve.lazy.ResolveSession
|
import org.jetbrains.kotlin.resolve.lazy.ResolveSession
|
||||||
import org.jetbrains.kotlin.resolve.lazy.data.KtClassLikeInfo
|
import org.jetbrains.kotlin.resolve.lazy.data.KtClassLikeInfo
|
||||||
import org.jetbrains.kotlin.resolve.lazy.declarations.*
|
import org.jetbrains.kotlin.resolve.lazy.declarations.*
|
||||||
import org.jetbrains.kotlin.resolve.lazy.descriptors.LazyScriptDescriptor
|
|
||||||
import org.jetbrains.kotlin.resolve.scopes.LexicalScope
|
import org.jetbrains.kotlin.resolve.scopes.LexicalScope
|
||||||
import org.jetbrains.kotlin.script.*
|
import org.jetbrains.kotlin.script.KotlinScriptDefinition
|
||||||
import org.jetbrains.kotlin.utils.*
|
import org.jetbrains.kotlin.script.ScriptParameter
|
||||||
|
import org.jetbrains.kotlin.script.ScriptPriorities
|
||||||
import java.io.File
|
import org.jetbrains.kotlin.script.StandardScriptDefinition
|
||||||
import java.io.PrintWriter
|
import java.io.PrintWriter
|
||||||
import java.lang.reflect.Constructor
|
|
||||||
import java.lang.reflect.Field
|
|
||||||
import java.net.MalformedURLException
|
|
||||||
import java.net.URL
|
|
||||||
import java.net.URLClassLoader
|
import java.net.URLClassLoader
|
||||||
import java.util.ArrayList
|
|
||||||
import java.util.Arrays
|
|
||||||
import java.util.Collections
|
|
||||||
|
|
||||||
class ReplInterpreter(
|
class ReplInterpreter(
|
||||||
disposable: Disposable,
|
disposable: Disposable,
|
||||||
configuration: CompilerConfiguration,
|
configuration: CompilerConfiguration,
|
||||||
private val ideMode: Boolean,
|
private val ideMode: Boolean,
|
||||||
private val replReader: ReplSystemInWrapper?) {
|
private val replReader: ReplSystemInWrapper?
|
||||||
|
) {
|
||||||
private var lineNumber = 0
|
private var lineNumber = 0
|
||||||
|
|
||||||
private var lastLineScope: LexicalScope? = null
|
private var lastLineScope: LexicalScope? = null
|
||||||
private val earlierLines = Lists.newArrayList<EarlierLine>()
|
private val earlierLines = arrayListOf<EarlierLine>()
|
||||||
private val previousIncompleteLines = Lists.newArrayList<String>()
|
private val previousIncompleteLines = arrayListOf<String>()
|
||||||
private val classLoader: ReplClassLoader
|
private val classLoader: ReplClassLoader
|
||||||
|
|
||||||
private val psiFileFactory: PsiFileFactoryImpl
|
private val psiFileFactory: PsiFileFactoryImpl
|
||||||
@@ -123,32 +110,27 @@ class ReplInterpreter(
|
|||||||
ProjectScope.getAllScope(project),
|
ProjectScope.getAllScope(project),
|
||||||
object : ReplLastLineScopeProvider {
|
object : ReplLastLineScopeProvider {
|
||||||
override val lastLineScope: LexicalScope?
|
override val lastLineScope: LexicalScope?
|
||||||
get() = lastLineScope
|
get() = this@ReplInterpreter.lastLineScope
|
||||||
},
|
},
|
||||||
JvmPackagePartProvider(environment))
|
JvmPackagePartProvider(environment)
|
||||||
|
)
|
||||||
|
|
||||||
this.topDownAnalysisContext = TopDownAnalysisContext(TopDownAnalysisMode.LocalDeclarations, DataFlowInfoFactory.EMPTY,
|
this.topDownAnalysisContext = TopDownAnalysisContext(
|
||||||
container.resolveSession.declarationScopeProvider)
|
TopDownAnalysisMode.LocalDeclarations, DataFlowInfoFactory.EMPTY, container.resolveSession.declarationScopeProvider
|
||||||
|
)
|
||||||
this.topDownAnalyzer = container.lazyTopDownAnalyzerForTopLevel
|
this.topDownAnalyzer = container.lazyTopDownAnalyzerForTopLevel
|
||||||
this.resolveSession = container.resolveSession
|
this.resolveSession = container.resolveSession
|
||||||
|
|
||||||
moduleContext.initializeModuleContents(CompositePackageFragmentProvider(
|
moduleContext.initializeModuleContents(CompositePackageFragmentProvider(
|
||||||
Arrays.asList(
|
listOf(
|
||||||
container.resolveSession.packageFragmentProvider,
|
container.resolveSession.packageFragmentProvider,
|
||||||
container.javaDescriptorResolver.packageFragmentProvider)))
|
container.javaDescriptorResolver.packageFragmentProvider
|
||||||
|
)
|
||||||
|
))
|
||||||
|
|
||||||
val classpath = Lists.newArrayList<URL>()
|
val classpath = configuration.jvmClasspathRoots.map { it.toURI().toURL() }
|
||||||
for (file in configuration.jvmClasspathRoots) {
|
|
||||||
try {
|
|
||||||
classpath.add(file.toURI().toURL())
|
|
||||||
}
|
|
||||||
catch (e: MalformedURLException) {
|
|
||||||
throw rethrow(e)
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
this.classLoader = ReplClassLoader(URLClassLoader(classpath.toTypedArray(), null))
|
||||||
|
|
||||||
this.classLoader = ReplClassLoader(URLClassLoader(classpath.toArray<URL>(arrayOfNulls<URL>(classpath.size)), null))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
enum class LineResultType {
|
enum class LineResultType {
|
||||||
@@ -158,18 +140,17 @@ class ReplInterpreter(
|
|||||||
INCOMPLETE
|
INCOMPLETE
|
||||||
}
|
}
|
||||||
|
|
||||||
class LineResult private constructor(private val value: Any?, private val unit: Boolean, val errorText: String?, val type: LineResultType) {
|
class LineResult private constructor(
|
||||||
|
private val resultingValue: Any?,
|
||||||
private fun checkSuccessful() {
|
private val unit: Boolean,
|
||||||
if (type != LineResultType.SUCCESS) {
|
val errorText: String?,
|
||||||
throw IllegalStateException("it is error")
|
val type: LineResultType
|
||||||
|
) {
|
||||||
|
val value: Any?
|
||||||
|
get() {
|
||||||
|
checkSuccessful()
|
||||||
|
return resultingValue
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
fun getValue(): Any? {
|
|
||||||
checkSuccessful()
|
|
||||||
return value
|
|
||||||
}
|
|
||||||
|
|
||||||
val isUnit: Boolean
|
val isUnit: Boolean
|
||||||
get() {
|
get() {
|
||||||
@@ -177,21 +158,24 @@ class ReplInterpreter(
|
|||||||
return unit
|
return unit
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun checkSuccessful() {
|
||||||
|
if (type != LineResultType.SUCCESS) {
|
||||||
|
error("it is error")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
|
||||||
private fun error(errorText: String, errorType: LineResultType): LineResult {
|
private fun error(errorText: String, errorType: LineResultType): LineResult {
|
||||||
var errorText = errorText
|
val resultingErrorText = when {
|
||||||
if (errorText.isEmpty()) {
|
errorText.isEmpty() -> "<unknown error>"
|
||||||
errorText = "<unknown error>"
|
!errorText.endsWith("\n") -> errorText + "\n"
|
||||||
}
|
else -> errorText
|
||||||
else if (!errorText.endsWith("\n")) {
|
|
||||||
errorText += "\n"
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return LineResult(null, false, errorText, errorType)
|
return LineResult(null, false, resultingErrorText, errorType)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun successful(value: Any, unit: Boolean): LineResult {
|
fun successful(value: Any?, unit: Boolean): LineResult {
|
||||||
return LineResult(value, unit, null, LineResultType.SUCCESS)
|
return LineResult(value, unit, null, LineResultType.SUCCESS)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -209,39 +193,35 @@ class ReplInterpreter(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun createDiagnosticHolder(): DiagnosticMessageHolder {
|
private fun createDiagnosticHolder(): DiagnosticMessageHolder =
|
||||||
return if (ideMode)
|
if (ideMode)
|
||||||
ReplIdeDiagnosticMessageHolder()
|
ReplIdeDiagnosticMessageHolder()
|
||||||
else
|
else
|
||||||
ReplTerminalDiagnosticMessageHolder()
|
ReplTerminalDiagnosticMessageHolder()
|
||||||
}
|
|
||||||
|
|
||||||
fun eval(line: String): LineResult {
|
fun eval(line: String): LineResult {
|
||||||
++lineNumber
|
++lineNumber
|
||||||
|
|
||||||
val scriptFqName = FqName("Line" + lineNumber)
|
val fullText = (previousIncompleteLines + line).joinToString(separator = "\n")
|
||||||
|
|
||||||
val fullText = StringBuilder()
|
val virtualFile =
|
||||||
for (prevLine in previousIncompleteLines) {
|
LightVirtualFile("line$lineNumber${KotlinParserDefinition.STD_SCRIPT_EXT}", KotlinLanguage.INSTANCE, fullText).apply {
|
||||||
fullText.append(prevLine).append("\n")
|
charset = CharsetToolkit.UTF8_CHARSET
|
||||||
}
|
}
|
||||||
fullText.append(line)
|
val psiFile = psiFileFactory.trySetupPsiForFile(virtualFile, KotlinLanguage.INSTANCE, true, false) as KtFile?
|
||||||
|
?: error("Script file not analyzed at line $lineNumber: $fullText")
|
||||||
val virtualFile = LightVirtualFile("line" + lineNumber + KotlinParserDefinition.STD_SCRIPT_EXT, KotlinLanguage.INSTANCE, fullText.toString())
|
|
||||||
virtualFile.setCharset(CharsetToolkit.UTF8_CHARSET)
|
|
||||||
val psiFile = psiFileFactory.trySetupPsiForFile(virtualFile, KotlinLanguage.INSTANCE, true, false) as KtFile? ?: error("Script file not analyzed at line $lineNumber: $fullText")
|
|
||||||
|
|
||||||
val errorHolder = createDiagnosticHolder()
|
val errorHolder = createDiagnosticHolder()
|
||||||
|
|
||||||
val syntaxErrorReport = AnalyzerWithCompilerReport.reportSyntaxErrors(psiFile, errorHolder)
|
val syntaxErrorReport = AnalyzerWithCompilerReport.reportSyntaxErrors(psiFile, errorHolder)
|
||||||
|
|
||||||
if (syntaxErrorReport.isHasErrors && syntaxErrorReport.isAllErrorsAtEof) {
|
if (syntaxErrorReport.isHasErrors && syntaxErrorReport.isAllErrorsAtEof) {
|
||||||
if (ideMode) {
|
return if (ideMode) {
|
||||||
return LineResult.compileError(errorHolder.renderedDiagnostics)
|
LineResult.compileError(errorHolder.renderedDiagnostics)
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
previousIncompleteLines.add(line)
|
previousIncompleteLines.add(line)
|
||||||
return LineResult.incomplete()
|
LineResult.incomplete()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -254,21 +234,14 @@ class ReplInterpreter(
|
|||||||
prepareForTheNextReplLine(topDownAnalysisContext)
|
prepareForTheNextReplLine(topDownAnalysisContext)
|
||||||
trace.clearDiagnostics()
|
trace.clearDiagnostics()
|
||||||
|
|
||||||
//noinspection ConstantConditions
|
psiFile.script!!.putUserData(ScriptPriorities.PRIORITY_KEY, lineNumber)
|
||||||
psiFile!!.script!!.putUserData(ScriptPriorities.PRIORITY_KEY, lineNumber)
|
|
||||||
|
|
||||||
val scriptDescriptor = doAnalyze(psiFile, errorHolder) ?: return LineResult.compileError(errorHolder.renderedDiagnostics)
|
val scriptDescriptor = doAnalyze(psiFile, errorHolder)
|
||||||
|
?: return LineResult.compileError(errorHolder.renderedDiagnostics)
|
||||||
|
|
||||||
val earlierScripts = Lists.newArrayList<ScriptDescriptor>()
|
val state = GenerationState(psiFile.project, ClassBuilderFactories.BINARIES, module, trace.bindingContext, listOf(psiFile))
|
||||||
|
|
||||||
for (earlierLine in earlierLines) {
|
compileScript(psiFile.script!!, earlierLines.map(EarlierLine::getScriptDescriptor), state, CompilationErrorHandler.THROW_EXCEPTION)
|
||||||
earlierScripts.add(earlierLine.scriptDescriptor)
|
|
||||||
}
|
|
||||||
|
|
||||||
val state = GenerationState(psiFile.project, ClassBuilderFactories.BINARIES,
|
|
||||||
module, trace.bindingContext, listOf(psiFile))
|
|
||||||
|
|
||||||
compileScript(psiFile.script!!, earlierScripts, state, CompilationErrorHandler.THROW_EXCEPTION)
|
|
||||||
|
|
||||||
for (outputFile in state.factory.asList()) {
|
for (outputFile in state.factory.asList()) {
|
||||||
if (outputFile.relativePath.endsWith(".class")) {
|
if (outputFile.relativePath.endsWith(".class")) {
|
||||||
@@ -278,31 +251,24 @@ class ReplInterpreter(
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
val scriptClass = classLoader.loadClass(scriptFqName.asString())
|
val scriptClass = classLoader.loadClass("Line$lineNumber")
|
||||||
|
|
||||||
val constructorParams = arrayOfNulls<Class<*>>(earlierLines.size)
|
val constructorParams = earlierLines.map(EarlierLine::getScriptClass).toTypedArray()
|
||||||
val constructorArgs = arrayOfNulls<Any>(earlierLines.size)
|
val constructorArgs = earlierLines.map(EarlierLine::getScriptInstance).toTypedArray()
|
||||||
|
|
||||||
for (i in earlierLines.indices) {
|
|
||||||
constructorParams[i] = earlierLines[i].scriptClass
|
|
||||||
constructorArgs[i] = earlierLines[i].scriptInstance
|
|
||||||
}
|
|
||||||
|
|
||||||
val scriptInstanceConstructor = scriptClass.getConstructor(*constructorParams)
|
val scriptInstanceConstructor = scriptClass.getConstructor(*constructorParams)
|
||||||
val scriptInstance: Any
|
val scriptInstance = try {
|
||||||
try {
|
replReader?.isReplScriptExecuting = true
|
||||||
setReplScriptExecuting(true)
|
scriptInstanceConstructor.newInstance(*constructorArgs)
|
||||||
scriptInstance = scriptInstanceConstructor.newInstance(*constructorArgs)
|
|
||||||
}
|
}
|
||||||
catch (e: Throwable) {
|
catch (e: Throwable) {
|
||||||
return LineResult.runtimeError(renderStackTrace(e.cause!!))
|
return LineResult.runtimeError(renderStackTrace(e.cause!!))
|
||||||
}
|
}
|
||||||
finally {
|
finally {
|
||||||
setReplScriptExecuting(false)
|
replReader?.isReplScriptExecuting = false
|
||||||
}
|
}
|
||||||
|
|
||||||
val rvField = scriptClass.getDeclaredField(SCRIPT_RESULT_FIELD_NAME)
|
val rvField = scriptClass.getDeclaredField(SCRIPT_RESULT_FIELD_NAME).apply { isAccessible = true }
|
||||||
rvField.isAccessible = true
|
|
||||||
val rv = rvField.get(scriptInstance)
|
val rv = rvField.get(scriptInstance)
|
||||||
|
|
||||||
earlierLines.add(EarlierLine(line, scriptDescriptor, scriptClass, scriptInstance))
|
earlierLines.add(EarlierLine(line, scriptDescriptor, scriptClass, scriptInstance))
|
||||||
@@ -310,28 +276,17 @@ class ReplInterpreter(
|
|||||||
return LineResult.successful(rv, !state.replSpecific.hasResult)
|
return LineResult.successful(rv, !state.replSpecific.hasResult)
|
||||||
}
|
}
|
||||||
catch (e: Throwable) {
|
catch (e: Throwable) {
|
||||||
@SuppressWarnings("UseOfSystemOutOrSystemErr")
|
|
||||||
val writer = PrintWriter(System.err)
|
val writer = PrintWriter(System.err)
|
||||||
classLoader.dumpClasses(writer)
|
classLoader.dumpClasses(writer)
|
||||||
writer.flush()
|
writer.flush()
|
||||||
throw rethrow(e)
|
throw e
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun setReplScriptExecuting(isExecuting: Boolean) {
|
|
||||||
if (replReader != null) {
|
|
||||||
replReader.isReplScriptExecuting = isExecuting
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun doAnalyze(psiFile: KtFile, errorReporter: DiagnosticMessageReporter): ScriptDescriptor? {
|
private fun doAnalyze(psiFile: KtFile, errorReporter: DiagnosticMessageReporter): ScriptDescriptor? {
|
||||||
scriptDeclarationFactory.setDelegateFactory(
|
scriptDeclarationFactory.setDelegateFactory(FileBasedDeclarationProviderFactory(resolveSession.storageManager, listOf(psiFile)))
|
||||||
FileBasedDeclarationProviderFactory(resolveSession.storageManager, listOf(psiFile)))
|
|
||||||
|
|
||||||
val context = topDownAnalyzer.analyzeDeclarations(
|
val context = topDownAnalyzer.analyzeDeclarations(topDownAnalysisContext.topDownAnalysisMode, listOf(psiFile))
|
||||||
topDownAnalysisContext.topDownAnalysisMode,
|
|
||||||
listOf(psiFile))
|
|
||||||
|
|
||||||
if (trace.get(BindingContext.FILE_TO_PACKAGE_FRAGMENT, psiFile) == null) {
|
if (trace.get(BindingContext.FILE_TO_PACKAGE_FRAGMENT, psiFile) == null) {
|
||||||
trace.record(BindingContext.FILE_TO_PACKAGE_FRAGMENT, psiFile, resolveSession.getPackageFragment(FqName.ROOT))
|
trace.record(BindingContext.FILE_TO_PACKAGE_FRAGMENT, psiFile, resolveSession.getPackageFragment(FqName.ROOT))
|
||||||
@@ -342,9 +297,9 @@ class ReplInterpreter(
|
|||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
val scriptDescriptor = context.scripts[psiFile.script]!!
|
return context.scripts[psiFile.script]?.apply {
|
||||||
lastLineScope = scriptDescriptor.getScopeForInitializerResolution()
|
lastLineScope = this.scopeForInitializerResolution
|
||||||
return scriptDescriptor
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun dumpClasses(out: PrintWriter) {
|
fun dumpClasses(out: PrintWriter) {
|
||||||
@@ -352,23 +307,23 @@ class ReplInterpreter(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private class ScriptMutableDeclarationProviderFactory : DeclarationProviderFactory {
|
private class ScriptMutableDeclarationProviderFactory : DeclarationProviderFactory {
|
||||||
private var delegateFactory: DeclarationProviderFactory? = null
|
private lateinit var delegateFactory: DeclarationProviderFactory
|
||||||
private var rootPackageProvider: AdaptablePackageMemberDeclarationProvider? = null
|
private lateinit var rootPackageProvider: AdaptablePackageMemberDeclarationProvider
|
||||||
|
|
||||||
fun setDelegateFactory(delegateFactory: DeclarationProviderFactory) {
|
fun setDelegateFactory(delegateFactory: DeclarationProviderFactory) {
|
||||||
this.delegateFactory = delegateFactory
|
this.delegateFactory = delegateFactory
|
||||||
|
|
||||||
val provider = delegateFactory.getPackageMemberDeclarationProvider(FqName.ROOT)!!
|
val provider = delegateFactory.getPackageMemberDeclarationProvider(FqName.ROOT)!!
|
||||||
if (rootPackageProvider == null) {
|
try {
|
||||||
rootPackageProvider = AdaptablePackageMemberDeclarationProvider(provider)
|
rootPackageProvider.addDelegateProvider(provider)
|
||||||
}
|
}
|
||||||
else {
|
catch (e: UninitializedPropertyAccessException) {
|
||||||
rootPackageProvider!!.addDelegateProvider(provider)
|
rootPackageProvider = AdaptablePackageMemberDeclarationProvider(provider)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getClassMemberDeclarationProvider(classLikeInfo: KtClassLikeInfo): ClassMemberDeclarationProvider {
|
override fun getClassMemberDeclarationProvider(classLikeInfo: KtClassLikeInfo): ClassMemberDeclarationProvider {
|
||||||
return delegateFactory!!.getClassMemberDeclarationProvider(classLikeInfo)
|
return delegateFactory.getClassMemberDeclarationProvider(classLikeInfo)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getPackageMemberDeclarationProvider(packageFqName: FqName): PackageMemberDeclarationProvider? {
|
override fun getPackageMemberDeclarationProvider(packageFqName: FqName): PackageMemberDeclarationProvider? {
|
||||||
@@ -376,17 +331,18 @@ class ReplInterpreter(
|
|||||||
return rootPackageProvider
|
return rootPackageProvider
|
||||||
}
|
}
|
||||||
|
|
||||||
return this.delegateFactory!!.getPackageMemberDeclarationProvider(packageFqName)
|
return delegateFactory.getPackageMemberDeclarationProvider(packageFqName)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun diagnoseMissingPackageFragment(file: KtFile) {
|
override fun diagnoseMissingPackageFragment(file: KtFile) {
|
||||||
this.delegateFactory!!.diagnoseMissingPackageFragment(file)
|
delegateFactory.diagnoseMissingPackageFragment(file)
|
||||||
}
|
}
|
||||||
|
|
||||||
class AdaptablePackageMemberDeclarationProvider(private var delegateProvider: PackageMemberDeclarationProvider) : DelegatePackageMemberDeclarationProvider(delegateProvider) {
|
class AdaptablePackageMemberDeclarationProvider(
|
||||||
|
private var delegateProvider: PackageMemberDeclarationProvider
|
||||||
|
) : DelegatePackageMemberDeclarationProvider(delegateProvider) {
|
||||||
fun addDelegateProvider(provider: PackageMemberDeclarationProvider) {
|
fun addDelegateProvider(provider: PackageMemberDeclarationProvider) {
|
||||||
delegateProvider = CombinedPackageMemberDeclarationProvider(Lists.newArrayList(provider, delegateProvider))
|
delegateProvider = CombinedPackageMemberDeclarationProvider(listOf(provider, delegateProvider))
|
||||||
|
|
||||||
delegate = delegateProvider
|
delegate = delegateProvider
|
||||||
}
|
}
|
||||||
@@ -396,17 +352,11 @@ class ReplInterpreter(
|
|||||||
companion object {
|
companion object {
|
||||||
private val SCRIPT_RESULT_FIELD_NAME = "\$\$result"
|
private val SCRIPT_RESULT_FIELD_NAME = "\$\$result"
|
||||||
private val REPL_LINE_AS_SCRIPT_DEFINITION = object : KotlinScriptDefinition {
|
private val REPL_LINE_AS_SCRIPT_DEFINITION = object : KotlinScriptDefinition {
|
||||||
override fun getScriptParameters(scriptDescriptor: ScriptDescriptor): List<ScriptParameter> {
|
override fun getScriptParameters(scriptDescriptor: ScriptDescriptor): List<ScriptParameter> = emptyList()
|
||||||
return emptyList()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun isScript(file: PsiFile): Boolean {
|
override fun isScript(file: PsiFile): Boolean = StandardScriptDefinition.isScript(file)
|
||||||
return StandardScriptDefinition.isScript(file)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun getScriptName(script: KtScript): Name {
|
override fun getScriptName(script: KtScript): Name = StandardScriptDefinition.getScriptName(script)
|
||||||
return StandardScriptDefinition.getScriptName(script)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun prepareForTheNextReplLine(c: TopDownAnalysisContext) {
|
private fun prepareForTheNextReplLine(c: TopDownAnalysisContext) {
|
||||||
@@ -414,26 +364,23 @@ class ReplInterpreter(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun renderStackTrace(cause: Throwable): String {
|
private fun renderStackTrace(cause: Throwable): String {
|
||||||
val oldTrace = cause.stackTrace
|
val newTrace = arrayListOf<StackTraceElement>()
|
||||||
val newTrace = ArrayList<StackTraceElement>()
|
|
||||||
var skip = true
|
var skip = true
|
||||||
for (i in oldTrace.indices.reversed()) {
|
for ((i, element) in cause.stackTrace.withIndex().reversed()) {
|
||||||
val element = oldTrace[i]
|
|
||||||
// All our code happens in the script constructor, and no reflection/native code happens in constructors.
|
// All our code happens in the script constructor, and no reflection/native code happens in constructors.
|
||||||
// So we ignore everything in the stack trace until the first constructor
|
// So we ignore everything in the stack trace until the first constructor
|
||||||
if (element.getMethodName() == "<init>") {
|
if (element.methodName == "<init>") {
|
||||||
skip = false
|
skip = false
|
||||||
}
|
}
|
||||||
if (!skip) {
|
if (!skip) {
|
||||||
newTrace.add(element)
|
newTrace.add(element)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Collections.reverse(newTrace)
|
|
||||||
|
|
||||||
// throw away last element which contains Line1.kts<init>(Unknown source)
|
// throw away last element which contains Line1.kts<init>(Unknown source)
|
||||||
val resultingTrace = newTrace.subList(0, newTrace.size - 1)
|
val resultingTrace = newTrace.reversed().dropLast(1)
|
||||||
|
|
||||||
@Suppress("PLATFORM_CLASS_MAPPED_TO_KOTLIN")
|
@Suppress("PLATFORM_CLASS_MAPPED_TO_KOTLIN", "UsePropertyAccessSyntax")
|
||||||
(cause as java.lang.Throwable).setStackTrace(resultingTrace.toTypedArray())
|
(cause as java.lang.Throwable).setStackTrace(resultingTrace.toTypedArray())
|
||||||
|
|
||||||
return Throwables.getStackTraceAsString(cause)
|
return Throwables.getStackTraceAsString(cause)
|
||||||
@@ -443,16 +390,18 @@ class ReplInterpreter(
|
|||||||
script: KtScript,
|
script: KtScript,
|
||||||
earlierScripts: List<ScriptDescriptor>,
|
earlierScripts: List<ScriptDescriptor>,
|
||||||
state: GenerationState,
|
state: GenerationState,
|
||||||
errorHandler: CompilationErrorHandler) {
|
errorHandler: CompilationErrorHandler
|
||||||
|
) {
|
||||||
state.replSpecific.scriptResultFieldName = SCRIPT_RESULT_FIELD_NAME
|
state.replSpecific.scriptResultFieldName = SCRIPT_RESULT_FIELD_NAME
|
||||||
state.replSpecific.earlierScriptsForReplInterpreter = ArrayList(earlierScripts)
|
state.replSpecific.earlierScriptsForReplInterpreter = earlierScripts.toList()
|
||||||
|
|
||||||
state.beforeCompile()
|
state.beforeCompile()
|
||||||
KotlinCodegenFacade.generatePackage(
|
KotlinCodegenFacade.generatePackage(
|
||||||
state,
|
state,
|
||||||
script.getContainingKtFile().packageFqName,
|
script.getContainingKtFile().packageFqName,
|
||||||
setOf(script.getContainingKtFile()),
|
setOf(script.getContainingKtFile()),
|
||||||
errorHandler)
|
errorHandler
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -27,7 +27,6 @@ import java.io.File
|
|||||||
import java.io.PrintWriter
|
import java.io.PrintWriter
|
||||||
import java.util.*
|
import java.util.*
|
||||||
import java.util.regex.Pattern
|
import java.util.regex.Pattern
|
||||||
import kotlin.text.Regex
|
|
||||||
|
|
||||||
// Switch this flag to render bytecode after each line in the REPL test. Useful for debugging verify errors or other codegen problems
|
// Switch this flag to render bytecode after each line in the REPL test. Useful for debugging verify errors or other codegen problems
|
||||||
private val DUMP_BYTECODE = false
|
private val DUMP_BYTECODE = false
|
||||||
@@ -94,7 +93,7 @@ abstract class AbstractReplInterpreterTest : UsefulTestCase() {
|
|||||||
val actual = when (lineResult.type) {
|
val actual = when (lineResult.type) {
|
||||||
ReplInterpreter.LineResultType.SUCCESS -> if (!lineResult.isUnit) "${lineResult.value}" else ""
|
ReplInterpreter.LineResultType.SUCCESS -> if (!lineResult.isUnit) "${lineResult.value}" else ""
|
||||||
ReplInterpreter.LineResultType.RUNTIME_ERROR,
|
ReplInterpreter.LineResultType.RUNTIME_ERROR,
|
||||||
ReplInterpreter.LineResultType.COMPILE_ERROR -> lineResult.errorText
|
ReplInterpreter.LineResultType.COMPILE_ERROR -> lineResult.errorText!!
|
||||||
ReplInterpreter.LineResultType.INCOMPLETE -> INCOMPLETE_LINE_MESSAGE
|
ReplInterpreter.LineResultType.INCOMPLETE -> INCOMPLETE_LINE_MESSAGE
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user