J2K ReplInterpreter: convert

This commit is contained in:
Alexander Udalov
2016-02-03 09:39:00 +05:30
committed by Alexander Udalov
parent 2b2c4b3610
commit 5670e7f750
@@ -14,505 +14,445 @@
* limitations under the License. * limitations under the License.
*/ */
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.google.common.collect.Lists
import com.intellij.openapi.Disposable; import com.intellij.openapi.Disposable
import com.intellij.openapi.project.Project; 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.annotations.NotNull; import org.jetbrains.kotlin.backend.common.output.OutputFile
import org.jetbrains.annotations.Nullable; import org.jetbrains.kotlin.cli.common.messages.AnalyzerWithCompilerReport
import org.jetbrains.kotlin.backend.common.output.OutputFile; import org.jetbrains.kotlin.cli.common.messages.DiagnosticMessageReporter
import org.jetbrains.kotlin.cli.common.messages.AnalyzerWithCompilerReport; import org.jetbrains.kotlin.cli.jvm.compiler.CliLightClassGenerationSupport
import org.jetbrains.kotlin.cli.common.messages.DiagnosticMessageReporter; import org.jetbrains.kotlin.cli.jvm.compiler.EnvironmentConfigFiles
import org.jetbrains.kotlin.cli.jvm.compiler.CliLightClassGenerationSupport; import org.jetbrains.kotlin.cli.jvm.compiler.JvmPackagePartProvider
import org.jetbrains.kotlin.cli.jvm.compiler.EnvironmentConfigFiles; import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment
import org.jetbrains.kotlin.cli.jvm.compiler.JvmPackagePartProvider; import org.jetbrains.kotlin.cli.jvm.config.*
import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment; import org.jetbrains.kotlin.cli.jvm.config.*
import org.jetbrains.kotlin.cli.jvm.config.JvmContentRootsKt; import org.jetbrains.kotlin.cli.jvm.repl.di.ContainerForReplWithJava
import org.jetbrains.kotlin.cli.jvm.config.ModuleNameKt; import org.jetbrains.kotlin.cli.jvm.repl.di.*
import org.jetbrains.kotlin.cli.jvm.repl.di.ContainerForReplWithJava; import org.jetbrains.kotlin.cli.jvm.repl.di.ReplLastLineScopeProvider
import org.jetbrains.kotlin.cli.jvm.repl.di.InjectionKt; import org.jetbrains.kotlin.cli.jvm.repl.messages.DiagnosticMessageHolder
import org.jetbrains.kotlin.cli.jvm.repl.di.ReplLastLineScopeProvider; import org.jetbrains.kotlin.cli.jvm.repl.messages.ReplIdeDiagnosticMessageHolder
import org.jetbrains.kotlin.cli.jvm.repl.messages.DiagnosticMessageHolder; import org.jetbrains.kotlin.cli.jvm.repl.messages.ReplSystemInWrapper
import org.jetbrains.kotlin.cli.jvm.repl.messages.ReplIdeDiagnosticMessageHolder; import org.jetbrains.kotlin.cli.jvm.repl.messages.ReplTerminalDiagnosticMessageHolder
import org.jetbrains.kotlin.cli.jvm.repl.messages.ReplSystemInWrapper; import org.jetbrains.kotlin.codegen.ClassBuilderFactories
import org.jetbrains.kotlin.cli.jvm.repl.messages.ReplTerminalDiagnosticMessageHolder; import org.jetbrains.kotlin.codegen.CompilationErrorHandler
import org.jetbrains.kotlin.codegen.ClassBuilderFactories; import org.jetbrains.kotlin.codegen.KotlinCodegenFacade
import org.jetbrains.kotlin.codegen.CompilationErrorHandler; import org.jetbrains.kotlin.codegen.state.GenerationState
import org.jetbrains.kotlin.codegen.KotlinCodegenFacade; import org.jetbrains.kotlin.config.CommonConfigurationKeys
import org.jetbrains.kotlin.codegen.state.GenerationState; import org.jetbrains.kotlin.config.CompilerConfiguration
import org.jetbrains.kotlin.config.CommonConfigurationKeys; import org.jetbrains.kotlin.context.MutableModuleContext
import org.jetbrains.kotlin.config.CompilerConfiguration; import org.jetbrains.kotlin.descriptors.ScriptDescriptor
import org.jetbrains.kotlin.context.MutableModuleContext; import org.jetbrains.kotlin.descriptors.impl.CompositePackageFragmentProvider
import org.jetbrains.kotlin.descriptors.ScriptDescriptor; import org.jetbrains.kotlin.descriptors.impl.ModuleDescriptorImpl
import org.jetbrains.kotlin.descriptors.impl.CompositePackageFragmentProvider; import org.jetbrains.kotlin.idea.KotlinLanguage
import org.jetbrains.kotlin.descriptors.impl.ModuleDescriptorImpl; import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.idea.KotlinLanguage; import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.name.FqName; import org.jetbrains.kotlin.parsing.KotlinParserDefinition
import org.jetbrains.kotlin.name.Name; import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.parsing.KotlinParserDefinition; import org.jetbrains.kotlin.psi.KtScript
import org.jetbrains.kotlin.psi.KtFile; import org.jetbrains.kotlin.resolve.*
import org.jetbrains.kotlin.psi.KtScript; import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfoFactory
import org.jetbrains.kotlin.resolve.*; import org.jetbrains.kotlin.resolve.jvm.JvmClassName
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfoFactory; import org.jetbrains.kotlin.resolve.jvm.TopDownAnalyzerFacadeForJVM
import org.jetbrains.kotlin.resolve.jvm.JvmClassName; import org.jetbrains.kotlin.resolve.lazy.ResolveSession
import org.jetbrains.kotlin.resolve.jvm.TopDownAnalyzerFacadeForJVM; import org.jetbrains.kotlin.resolve.lazy.data.KtClassLikeInfo
import org.jetbrains.kotlin.resolve.lazy.ResolveSession; import org.jetbrains.kotlin.resolve.lazy.declarations.*
import org.jetbrains.kotlin.resolve.lazy.data.KtClassLikeInfo; import org.jetbrains.kotlin.resolve.lazy.descriptors.LazyScriptDescriptor
import org.jetbrains.kotlin.resolve.lazy.declarations.*; import org.jetbrains.kotlin.resolve.scopes.LexicalScope
import org.jetbrains.kotlin.resolve.lazy.descriptors.LazyScriptDescriptor; import org.jetbrains.kotlin.script.*
import org.jetbrains.kotlin.resolve.scopes.LexicalScope; import org.jetbrains.kotlin.utils.*
import org.jetbrains.kotlin.script.*;
import org.jetbrains.kotlin.utils.ExceptionUtilsKt;
import java.io.File; import java.io.File
import java.io.PrintWriter; import java.io.PrintWriter
import java.lang.reflect.Constructor; import java.lang.reflect.Constructor
import java.lang.reflect.Field; import java.lang.reflect.Field
import java.net.MalformedURLException; import java.net.MalformedURLException
import java.net.URL; import java.net.URL
import java.net.URLClassLoader; import java.net.URLClassLoader
import java.util.ArrayList; import java.util.ArrayList
import java.util.Arrays; import java.util.Arrays
import java.util.Collections; import java.util.Collections
import java.util.List;
public class ReplInterpreter { class ReplInterpreter(
private static final String SCRIPT_RESULT_FIELD_NAME = "$$result"; disposable: Disposable,
configuration: CompilerConfiguration,
private val ideMode: Boolean,
private val replReader: ReplSystemInWrapper?) {
private int lineNumber = 0; private var lineNumber = 0
@Nullable private var lastLineScope: LexicalScope? = null
private LexicalScope lastLineScope; private val earlierLines = Lists.newArrayList<EarlierLine>()
private final List<EarlierLine> earlierLines = Lists.newArrayList(); private val previousIncompleteLines = Lists.newArrayList<String>()
private final List<String> previousIncompleteLines = Lists.newArrayList(); private val classLoader: ReplClassLoader
private final ReplClassLoader classLoader;
private final PsiFileFactoryImpl psiFileFactory; private val psiFileFactory: PsiFileFactoryImpl
private final BindingTraceContext trace; private val trace: BindingTraceContext
private final ModuleDescriptorImpl module; private val module: ModuleDescriptorImpl
private final TopDownAnalysisContext topDownAnalysisContext; private val topDownAnalysisContext: TopDownAnalysisContext
private final LazyTopDownAnalyzerForTopLevel topDownAnalyzer; private val topDownAnalyzer: LazyTopDownAnalyzerForTopLevel
private final ResolveSession resolveSession; private val resolveSession: ResolveSession
private final ScriptMutableDeclarationProviderFactory scriptDeclarationFactory; private val scriptDeclarationFactory: ScriptMutableDeclarationProviderFactory
private final boolean ideMode; init {
private final ReplSystemInWrapper replReader; configuration.add(CommonConfigurationKeys.SCRIPT_DEFINITIONS_KEY, REPL_LINE_AS_SCRIPT_DEFINITION)
private final static KotlinScriptDefinition REPL_LINE_AS_SCRIPT_DEFINITION = new KotlinScriptDefinition() {
@NotNull
@Override
public List<ScriptParameter> getScriptParameters(@NotNull ScriptDescriptor scriptDescriptor) {
return Collections.emptyList();
}
@Override val environment = KotlinCoreEnvironment.createForProduction(disposable, configuration, EnvironmentConfigFiles.JVM_CONFIG_FILES)
public boolean isScript(@NotNull PsiFile file) { val project = environment.project
return StandardScriptDefinition.INSTANCE.isScript(file);
}
@NotNull this.psiFileFactory = PsiFileFactory.getInstance(project) as PsiFileFactoryImpl
@Override this.trace = CliLightClassGenerationSupport.NoScopeRecordCliBindingTrace()
public Name getScriptName(@NotNull KtScript script) { val moduleContext = TopDownAnalyzerFacadeForJVM.createContextWithSealedModule(project, environment.getModuleName())
return StandardScriptDefinition.INSTANCE.getScriptName(script); this.module = moduleContext.module
}
};
public ReplInterpreter( scriptDeclarationFactory = ScriptMutableDeclarationProviderFactory()
@NotNull Disposable disposable,
@NotNull CompilerConfiguration configuration,
boolean ideMode,
@Nullable ReplSystemInWrapper replReader
) {
configuration.add(CommonConfigurationKeys.SCRIPT_DEFINITIONS_KEY, REPL_LINE_AS_SCRIPT_DEFINITION);
KotlinCoreEnvironment environment = val container = createContainerForReplWithJava(
KotlinCoreEnvironment.createForProduction(disposable, configuration, EnvironmentConfigFiles.JVM_CONFIG_FILES);
Project project = environment.getProject();
this.psiFileFactory = (PsiFileFactoryImpl) PsiFileFactory.getInstance(project);
this.trace = new CliLightClassGenerationSupport.NoScopeRecordCliBindingTrace();
MutableModuleContext moduleContext = TopDownAnalyzerFacadeForJVM.createContextWithSealedModule(project, ModuleNameKt
.getModuleName(environment));
this.module = moduleContext.getModule();
scriptDeclarationFactory = new ScriptMutableDeclarationProviderFactory();
ContainerForReplWithJava container = InjectionKt.createContainerForReplWithJava(
moduleContext, moduleContext,
trace, trace,
scriptDeclarationFactory, scriptDeclarationFactory,
ProjectScope.getAllScope(project), ProjectScope.getAllScope(project),
new ReplLastLineScopeProvider() { object : ReplLastLineScopeProvider {
@Nullable override val lastLineScope: LexicalScope?
@Override get() = lastLineScope
public LexicalScope getLastLineScope() {
return lastLineScope;
}
}, },
new JvmPackagePartProvider(environment) JvmPackagePartProvider(environment))
);
this.topDownAnalysisContext = new TopDownAnalysisContext(TopDownAnalysisMode.LocalDeclarations, DataFlowInfoFactory.EMPTY, this.topDownAnalysisContext = TopDownAnalysisContext(TopDownAnalysisMode.LocalDeclarations, DataFlowInfoFactory.EMPTY,
container.getResolveSession().getDeclarationScopeProvider()); container.resolveSession.declarationScopeProvider)
this.topDownAnalyzer = container.getLazyTopDownAnalyzerForTopLevel(); this.topDownAnalyzer = container.lazyTopDownAnalyzerForTopLevel
this.resolveSession = container.getResolveSession(); this.resolveSession = container.resolveSession
moduleContext.initializeModuleContents(new CompositePackageFragmentProvider( moduleContext.initializeModuleContents(CompositePackageFragmentProvider(
Arrays.asList( Arrays.asList(
container.getResolveSession().getPackageFragmentProvider(), container.resolveSession.packageFragmentProvider,
container.getJavaDescriptorResolver().getPackageFragmentProvider() container.javaDescriptorResolver.packageFragmentProvider)))
)
));
List<URL> classpath = Lists.newArrayList(); val classpath = Lists.newArrayList<URL>()
for (File file : JvmContentRootsKt.getJvmClasspathRoots(configuration)) { for (file in configuration.jvmClasspathRoots) {
try { try {
classpath.add(file.toURI().toURL()); classpath.add(file.toURI().toURL())
} }
catch (MalformedURLException e) { catch (e: MalformedURLException) {
throw ExceptionUtilsKt.rethrow(e); throw rethrow(e)
} }
} }
this.classLoader = new ReplClassLoader(new URLClassLoader(classpath.toArray(new URL[classpath.size()]), null)); this.classLoader = ReplClassLoader(URLClassLoader(classpath.toArray<URL>(arrayOfNulls<URL>(classpath.size)), null))
this.ideMode = ideMode;
this.replReader = replReader;
} }
private static void prepareForTheNextReplLine(@NotNull TopDownAnalysisContext c) { enum class LineResultType {
c.getScripts().clear();
}
public enum LineResultType {
SUCCESS, SUCCESS,
COMPILE_ERROR, COMPILE_ERROR,
RUNTIME_ERROR, RUNTIME_ERROR,
INCOMPLETE, INCOMPLETE
} }
public static class LineResult { class LineResult private constructor(private val value: Any?, private val unit: Boolean, val errorText: String?, val type: LineResultType) {
private final Object value;
private final boolean unit;
private final String errorText;
private final LineResultType type;
private LineResult(Object value, boolean unit, String errorText, @NotNull LineResultType type) { private fun checkSuccessful() {
this.value = value; if (type != LineResultType.SUCCESS) {
this.unit = unit; throw IllegalStateException("it is error")
this.errorText = errorText;
this.type = type;
}
@NotNull
public LineResultType getType() {
return type;
}
private void checkSuccessful() {
if (getType() != LineResultType.SUCCESS) {
throw new IllegalStateException("it is error");
} }
} }
public Object getValue() { fun getValue(): Any? {
checkSuccessful(); checkSuccessful()
return value; return value
} }
public boolean isUnit() { val isUnit: Boolean
checkSuccessful(); get() {
return unit; checkSuccessful()
} return unit
@NotNull
public String getErrorText() {
return errorText;
}
@NotNull
private static LineResult error(@NotNull String errorText, @NotNull LineResultType errorType) {
if (errorText.isEmpty()) {
errorText = "<unknown error>";
}
else if (!errorText.endsWith("\n")) {
errorText += "\n";
} }
return new LineResult(null, false, errorText, errorType); companion object {
}
@NotNull private fun error(errorText: String, errorType: LineResultType): LineResult {
public static LineResult successful(Object value, boolean unit) { var errorText = errorText
return new LineResult(value, unit, null, LineResultType.SUCCESS); if (errorText.isEmpty()) {
} errorText = "<unknown error>"
}
else if (!errorText.endsWith("\n")) {
errorText += "\n"
}
@NotNull return LineResult(null, false, errorText, errorType)
public static LineResult compileError(@NotNull String errorText) { }
return error(errorText, LineResultType.COMPILE_ERROR);
}
@NotNull fun successful(value: Any, unit: Boolean): LineResult {
public static LineResult runtimeError(@NotNull String errorText) { return LineResult(value, unit, null, LineResultType.SUCCESS)
return error(errorText, LineResultType.RUNTIME_ERROR); }
}
public static LineResult incomplete() { fun compileError(errorText: String): LineResult {
return new LineResult(null, false, null, LineResultType.INCOMPLETE); 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)
}
} }
} }
@NotNull private fun createDiagnosticHolder(): DiagnosticMessageHolder {
private DiagnosticMessageHolder createDiagnosticHolder() { return if (ideMode)
return ideMode ? new ReplIdeDiagnosticMessageHolder() ReplIdeDiagnosticMessageHolder()
: new ReplTerminalDiagnosticMessageHolder(); else
ReplTerminalDiagnosticMessageHolder()
} }
@NotNull fun eval(line: String): LineResult {
public LineResult eval(@NotNull String line) { ++lineNumber
++lineNumber;
FqName scriptFqName = new FqName("Line" + lineNumber); val scriptFqName = FqName("Line" + lineNumber)
StringBuilder fullText = new StringBuilder(); val fullText = StringBuilder()
for (String prevLine : previousIncompleteLines) { for (prevLine in previousIncompleteLines) {
fullText.append(prevLine).append("\n"); fullText.append(prevLine).append("\n")
} }
fullText.append(line); fullText.append(line)
LightVirtualFile virtualFile = new LightVirtualFile("line" + lineNumber + KotlinParserDefinition.STD_SCRIPT_EXT, KotlinLanguage.INSTANCE, fullText.toString()); val virtualFile = LightVirtualFile("line" + lineNumber + KotlinParserDefinition.STD_SCRIPT_EXT, KotlinLanguage.INSTANCE, fullText.toString())
virtualFile.setCharset(CharsetToolkit.UTF8_CHARSET); virtualFile.setCharset(CharsetToolkit.UTF8_CHARSET)
KtFile psiFile = (KtFile) psiFileFactory.trySetupPsiForFile(virtualFile, KotlinLanguage.INSTANCE, true, false); val psiFile = psiFileFactory.trySetupPsiForFile(virtualFile, KotlinLanguage.INSTANCE, true, false) as KtFile? ?: error("Script file not analyzed at line $lineNumber: $fullText")
assert psiFile != null : "Script file not analyzed at line " + lineNumber + ": " + fullText;
DiagnosticMessageHolder errorHolder = createDiagnosticHolder(); val errorHolder = createDiagnosticHolder()
AnalyzerWithCompilerReport.SyntaxErrorReport syntaxErrorReport = AnalyzerWithCompilerReport.Companion val syntaxErrorReport = AnalyzerWithCompilerReport.reportSyntaxErrors(psiFile, errorHolder)
.reportSyntaxErrors(psiFile, errorHolder);
if (syntaxErrorReport.isHasErrors() && syntaxErrorReport.isAllErrorsAtEof()) { if (syntaxErrorReport.isHasErrors && syntaxErrorReport.isAllErrorsAtEof) {
if (ideMode) { if (ideMode) {
return LineResult.compileError(errorHolder.getRenderedDiagnostics()); return LineResult.compileError(errorHolder.renderedDiagnostics)
} }
else { else {
previousIncompleteLines.add(line); previousIncompleteLines.add(line)
return LineResult.incomplete(); return LineResult.incomplete()
} }
} }
previousIncompleteLines.clear(); previousIncompleteLines.clear()
if (syntaxErrorReport.isHasErrors()) { if (syntaxErrorReport.isHasErrors) {
return LineResult.compileError(errorHolder.getRenderedDiagnostics()); return LineResult.compileError(errorHolder.renderedDiagnostics)
} }
prepareForTheNextReplLine(topDownAnalysisContext); prepareForTheNextReplLine(topDownAnalysisContext)
trace.clearDiagnostics(); trace.clearDiagnostics()
//noinspection ConstantConditions //noinspection ConstantConditions
psiFile.getScript().putUserData(ScriptPriorities.PRIORITY_KEY, lineNumber); psiFile!!.script!!.putUserData(ScriptPriorities.PRIORITY_KEY, lineNumber)
ScriptDescriptor scriptDescriptor = doAnalyze(psiFile, errorHolder); val scriptDescriptor = doAnalyze(psiFile, errorHolder) ?: return LineResult.compileError(errorHolder.renderedDiagnostics)
if (scriptDescriptor == null) {
return LineResult.compileError(errorHolder.getRenderedDiagnostics()); val earlierScripts = Lists.newArrayList<ScriptDescriptor>()
for (earlierLine in earlierLines) {
earlierScripts.add(earlierLine.scriptDescriptor)
} }
List<ScriptDescriptor> earlierScripts = Lists.newArrayList(); val state = GenerationState(psiFile.project, ClassBuilderFactories.BINARIES,
module, trace.bindingContext, listOf(psiFile))
for (EarlierLine earlierLine : earlierLines) { compileScript(psiFile.script!!, earlierScripts, state, CompilationErrorHandler.THROW_EXCEPTION)
earlierScripts.add(earlierLine.getScriptDescriptor());
}
GenerationState state = new GenerationState(psiFile.getProject(), ClassBuilderFactories.BINARIES, for (outputFile in state.factory.asList()) {
module, trace.getBindingContext(), Collections.singletonList(psiFile)); if (outputFile.relativePath.endsWith(".class")) {
classLoader.addClass(JvmClassName.byInternalName(outputFile.relativePath.replaceFirst("\\.class$".toRegex(), "")),
compileScript(psiFile.getScript(), earlierScripts, state, CompilationErrorHandler.THROW_EXCEPTION); outputFile.asByteArray())
for (OutputFile outputFile : state.getFactory().asList()) {
if(outputFile.getRelativePath().endsWith(".class")) {
classLoader.addClass(JvmClassName.byInternalName(outputFile.getRelativePath().replaceFirst("\\.class$", "")),
outputFile.asByteArray());
} }
} }
try { try {
Class<?> scriptClass = classLoader.loadClass(scriptFqName.asString()); val scriptClass = classLoader.loadClass(scriptFqName.asString())
Class<?>[] constructorParams = new Class<?>[earlierLines.size()]; val constructorParams = arrayOfNulls<Class<*>>(earlierLines.size)
Object[] constructorArgs = new Object[earlierLines.size()]; val constructorArgs = arrayOfNulls<Any>(earlierLines.size)
for (int i = 0; i < earlierLines.size(); ++i) { for (i in earlierLines.indices) {
constructorParams[i] = earlierLines.get(i).getScriptClass(); constructorParams[i] = earlierLines[i].scriptClass
constructorArgs[i] = earlierLines.get(i).getScriptInstance(); constructorArgs[i] = earlierLines[i].scriptInstance
} }
Constructor<?> scriptInstanceConstructor = scriptClass.getConstructor(constructorParams); val scriptInstanceConstructor = scriptClass.getConstructor(*constructorParams)
Object scriptInstance; val scriptInstance: Any
try { try {
setReplScriptExecuting(true); setReplScriptExecuting(true)
scriptInstance = scriptInstanceConstructor.newInstance(constructorArgs); scriptInstance = scriptInstanceConstructor.newInstance(*constructorArgs)
} }
catch (Throwable e) { catch (e: Throwable) {
return LineResult.runtimeError(renderStackTrace(e.getCause())); return LineResult.runtimeError(renderStackTrace(e.cause!!))
} finally { }
setReplScriptExecuting(false); finally {
setReplScriptExecuting(false)
} }
Field rvField = scriptClass.getDeclaredField(SCRIPT_RESULT_FIELD_NAME); val rvField = scriptClass.getDeclaredField(SCRIPT_RESULT_FIELD_NAME)
rvField.setAccessible(true); rvField.isAccessible = true
Object rv = rvField.get(scriptInstance); val rv = rvField.get(scriptInstance)
earlierLines.add(new EarlierLine(line, scriptDescriptor, scriptClass, scriptInstance)); earlierLines.add(EarlierLine(line, scriptDescriptor, scriptClass, scriptInstance))
return LineResult.successful(rv, !state.getReplSpecific().getHasResult()); return LineResult.successful(rv, !state.replSpecific.hasResult)
} }
catch (Throwable e) { catch (e: Throwable) {
@SuppressWarnings("UseOfSystemOutOrSystemErr") @SuppressWarnings("UseOfSystemOutOrSystemErr")
PrintWriter writer = new PrintWriter(System.err); val writer = PrintWriter(System.err)
classLoader.dumpClasses(writer); classLoader.dumpClasses(writer)
writer.flush(); writer.flush()
throw ExceptionUtilsKt.rethrow(e); throw rethrow(e)
} }
} }
private void setReplScriptExecuting(boolean isExecuting) { private fun setReplScriptExecuting(isExecuting: Boolean) {
if (replReader != null) { if (replReader != null) {
replReader.setReplScriptExecuting(isExecuting); replReader.isReplScriptExecuting = isExecuting
} }
} }
@NotNull private fun doAnalyze(psiFile: KtFile, errorReporter: DiagnosticMessageReporter): ScriptDescriptor? {
private static String renderStackTrace(@NotNull Throwable cause) {
StackTraceElement[] oldTrace = cause.getStackTrace();
List<StackTraceElement> newTrace = new ArrayList<StackTraceElement>();
boolean skip = true;
for (int i = oldTrace.length - 1; i >= 0; i--) {
StackTraceElement element = oldTrace[i];
// 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
if (element.getMethodName().equals("<init>")) {
skip = false;
}
if (!skip) {
newTrace.add(element);
}
}
Collections.reverse(newTrace);
// throw away last element which contains Line1.kts<init>(Unknown source)
List<StackTraceElement> resultingTrace = newTrace.subList(0, newTrace.size() - 1);
cause.setStackTrace(resultingTrace.toArray(new StackTraceElement[resultingTrace.size()]));
return Throwables.getStackTraceAsString(cause);
}
@Nullable
private ScriptDescriptor doAnalyze(@NotNull KtFile psiFile, @NotNull DiagnosticMessageReporter errorReporter) {
scriptDeclarationFactory.setDelegateFactory( scriptDeclarationFactory.setDelegateFactory(
new FileBasedDeclarationProviderFactory(resolveSession.getStorageManager(), Collections.singletonList(psiFile))); FileBasedDeclarationProviderFactory(resolveSession.storageManager, listOf(psiFile)))
TopDownAnalysisContext context = topDownAnalyzer.analyzeDeclarations( val context = topDownAnalyzer.analyzeDeclarations(
topDownAnalysisContext.getTopDownAnalysisMode(), topDownAnalysisContext.topDownAnalysisMode,
Collections.singletonList(psiFile) 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))
} }
boolean hasErrors = AnalyzerWithCompilerReport.Companion val hasErrors = AnalyzerWithCompilerReport.reportDiagnostics(trace.bindingContext.diagnostics, errorReporter, false)
.reportDiagnostics(trace.getBindingContext().getDiagnostics(), errorReporter, false);
if (hasErrors) { if (hasErrors) {
return null; return null
} }
LazyScriptDescriptor scriptDescriptor = context.getScripts().get(psiFile.getScript()); val scriptDescriptor = context.scripts[psiFile.script]!!
lastLineScope = scriptDescriptor.getScopeForInitializerResolution(); lastLineScope = scriptDescriptor.getScopeForInitializerResolution()
return scriptDescriptor; return scriptDescriptor
} }
public void dumpClasses(@NotNull PrintWriter out) { fun dumpClasses(out: PrintWriter) {
classLoader.dumpClasses(out); classLoader.dumpClasses(out)
} }
public static void compileScript( private class ScriptMutableDeclarationProviderFactory : DeclarationProviderFactory {
@NotNull KtScript script, private var delegateFactory: DeclarationProviderFactory? = null
@NotNull List<ScriptDescriptor> earlierScripts, private var rootPackageProvider: AdaptablePackageMemberDeclarationProvider? = null
@NotNull GenerationState state,
@NotNull CompilationErrorHandler errorHandler
) {
state.getReplSpecific().setScriptResultFieldName(SCRIPT_RESULT_FIELD_NAME);
state.getReplSpecific().setEarlierScriptsForReplInterpreter(new ArrayList<ScriptDescriptor>(earlierScripts));
state.beforeCompile(); fun setDelegateFactory(delegateFactory: DeclarationProviderFactory) {
KotlinCodegenFacade.generatePackage( this.delegateFactory = delegateFactory
state,
script.getContainingKtFile().getPackageFqName(),
Collections.singleton(script.getContainingKtFile()),
errorHandler
);
}
private static class ScriptMutableDeclarationProviderFactory implements DeclarationProviderFactory { val provider = delegateFactory.getPackageMemberDeclarationProvider(FqName.ROOT)!!
private DeclarationProviderFactory delegateFactory;
private AdaptablePackageMemberDeclarationProvider rootPackageProvider;
public void setDelegateFactory(DeclarationProviderFactory delegateFactory) {
this.delegateFactory = delegateFactory;
PackageMemberDeclarationProvider provider = delegateFactory.getPackageMemberDeclarationProvider(FqName.ROOT);
if (rootPackageProvider == null) { if (rootPackageProvider == null) {
assert provider != null; rootPackageProvider = AdaptablePackageMemberDeclarationProvider(provider)
rootPackageProvider = new AdaptablePackageMemberDeclarationProvider(provider);
} }
else { else {
rootPackageProvider.addDelegateProvider(provider); rootPackageProvider!!.addDelegateProvider(provider)
} }
} }
@NotNull override fun getClassMemberDeclarationProvider(classLikeInfo: KtClassLikeInfo): ClassMemberDeclarationProvider {
@Override return delegateFactory!!.getClassMemberDeclarationProvider(classLikeInfo)
public ClassMemberDeclarationProvider getClassMemberDeclarationProvider(@NotNull KtClassLikeInfo classLikeInfo) {
return delegateFactory.getClassMemberDeclarationProvider(classLikeInfo);
} }
@Nullable override fun getPackageMemberDeclarationProvider(packageFqName: FqName): PackageMemberDeclarationProvider? {
@Override if (packageFqName.isRoot) {
public PackageMemberDeclarationProvider getPackageMemberDeclarationProvider(@NotNull FqName packageFqName) { return rootPackageProvider
if (packageFqName.isRoot()) {
return rootPackageProvider;
} }
return this.delegateFactory.getPackageMemberDeclarationProvider(packageFqName); return this.delegateFactory!!.getPackageMemberDeclarationProvider(packageFqName)
} }
@Override override fun diagnoseMissingPackageFragment(file: KtFile) {
public void diagnoseMissingPackageFragment(KtFile file) { this.delegateFactory!!.diagnoseMissingPackageFragment(file)
this.delegateFactory.diagnoseMissingPackageFragment(file);
} }
public static class AdaptablePackageMemberDeclarationProvider extends DelegatePackageMemberDeclarationProvider { class AdaptablePackageMemberDeclarationProvider(private var delegateProvider: PackageMemberDeclarationProvider) : DelegatePackageMemberDeclarationProvider(delegateProvider) {
@NotNull
private PackageMemberDeclarationProvider delegateProvider;
public AdaptablePackageMemberDeclarationProvider(@NotNull PackageMemberDeclarationProvider delegateProvider) { fun addDelegateProvider(provider: PackageMemberDeclarationProvider) {
super(delegateProvider); delegateProvider = CombinedPackageMemberDeclarationProvider(Lists.newArrayList(provider, delegateProvider))
this.delegateProvider = delegateProvider;
delegate = delegateProvider
}
}
}
companion object {
private val SCRIPT_RESULT_FIELD_NAME = "\$\$result"
private val REPL_LINE_AS_SCRIPT_DEFINITION = object : KotlinScriptDefinition {
override fun getScriptParameters(scriptDescriptor: ScriptDescriptor): List<ScriptParameter> {
return emptyList()
} }
public void addDelegateProvider(PackageMemberDeclarationProvider provider) { override fun isScript(file: PsiFile): Boolean {
delegateProvider = new CombinedPackageMemberDeclarationProvider(Lists.newArrayList(provider, delegateProvider)); return StandardScriptDefinition.isScript(file)
setDelegate(delegateProvider);
} }
override fun getScriptName(script: KtScript): Name {
return StandardScriptDefinition.getScriptName(script)
}
}
private fun prepareForTheNextReplLine(c: TopDownAnalysisContext) {
c.scripts.clear()
}
private fun renderStackTrace(cause: Throwable): String {
val oldTrace = cause.stackTrace
val newTrace = ArrayList<StackTraceElement>()
var skip = true
for (i in oldTrace.indices.reversed()) {
val element = oldTrace[i]
// 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
if (element.getMethodName() == "<init>") {
skip = false
}
if (!skip) {
newTrace.add(element)
}
}
Collections.reverse(newTrace)
// throw away last element which contains Line1.kts<init>(Unknown source)
val resultingTrace = newTrace.subList(0, newTrace.size - 1)
@Suppress("PLATFORM_CLASS_MAPPED_TO_KOTLIN")
(cause as java.lang.Throwable).setStackTrace(resultingTrace.toTypedArray())
return Throwables.getStackTraceAsString(cause)
}
fun compileScript(
script: KtScript,
earlierScripts: List<ScriptDescriptor>,
state: GenerationState,
errorHandler: CompilationErrorHandler) {
state.replSpecific.scriptResultFieldName = SCRIPT_RESULT_FIELD_NAME
state.replSpecific.earlierScriptsForReplInterpreter = ArrayList(earlierScripts)
state.beforeCompile()
KotlinCodegenFacade.generatePackage(
state,
script.getContainingKtFile().packageFqName,
setOf(script.getContainingKtFile()),
errorHandler)
} }
} }
} }