Extend GeneratorExtensions with previous script, implemt it for JS REPL

also refactor JS REPL for better compatibility with the generic
REPL/scripting infrastructure
This commit is contained in:
Ilya Chernikov
2021-01-07 18:15:05 +01:00
parent 83da5f61fd
commit bac6a7346e
10 changed files with 89 additions and 47 deletions
@@ -18,13 +18,17 @@ import org.jetbrains.kotlin.descriptors.ModuleDescriptor
import org.jetbrains.kotlin.ir.backend.js.JsIrBackendContext
import org.jetbrains.kotlin.ir.backend.js.generateJsCode
import org.jetbrains.kotlin.ir.backend.js.utils.NameTables
import org.jetbrains.kotlin.ir.declarations.IrModuleFragment
import org.jetbrains.kotlin.ir.declarations.IrScript
import org.jetbrains.kotlin.ir.descriptors.IrFunctionFactory
import org.jetbrains.kotlin.ir.symbols.IrScriptSymbol
import org.jetbrains.kotlin.ir.util.ExternalDependenciesGenerator
import org.jetbrains.kotlin.ir.util.SymbolTable
import org.jetbrains.kotlin.js.config.JSConfigurationKeys
import org.jetbrains.kotlin.psi2ir.Psi2IrConfiguration
import org.jetbrains.kotlin.psi2ir.Psi2IrTranslator
import org.jetbrains.kotlin.psi2ir.generators.generateTypicalIrProviderList
import org.jetbrains.kotlin.psi2ir.generators.GeneratorExtensions
import org.jetbrains.kotlin.scripting.compiler.plugin.repl.ReplCodeAnalyzerBase
import org.jetbrains.kotlin.serialization.js.ModuleKind
import kotlin.script.experimental.api.valueOr
@@ -35,7 +39,7 @@ class JsCoreScriptingCompiler(
private val nameTables: NameTables,
private val symbolTable: SymbolTable,
private val dependencyDescriptors: List<ModuleDescriptor>,
private val replState: ReplCodeAnalyzerBase.ResettableAnalyzerState = ReplCodeAnalyzerBase.ResettableAnalyzerState()
private val replCompilerState: JsReplCompilerState? = null
) {
fun compile(codeLine: ReplCodeLine): ReplCompileResult {
val snippet = codeLine.code
@@ -51,7 +55,10 @@ class JsCoreScriptingCompiler(
).valueOr { return ReplCompileResult.Error(it.reports.joinToString { r -> r.message }) }
val messageCollector = environment.configuration[CLIConfigurationKeys.MESSAGE_COLLECTOR_KEY] as MessageCollector
val analyzerEngine = JsReplCodeAnalyzer(environment, dependencyDescriptors, replState)
val analyzerState = replCompilerState?.analyzerState ?: ReplCodeAnalyzerBase.ResettableAnalyzerState()
val analyzerEngine = JsReplCodeAnalyzer(environment, dependencyDescriptors, analyzerState)
val analysisResult = analyzerEngine.analyzeReplLine(snippetKtFile, codeLine).also {
AnalyzerWithCompilerReport.reportDiagnostics(it.bindingContext.diagnostics, messageCollector)
if (messageCollector.hasErrors()) return ReplCompileResult.Error("Error while analysis")
@@ -60,7 +67,14 @@ class JsCoreScriptingCompiler(
val files = listOf(snippetKtFile)
val (bindingContext, module) = analysisResult
val psi2ir = Psi2IrTranslator(environment.configuration.languageVersionSettings, Psi2IrConfiguration())
val psi2irContext = psi2ir.createGeneratorContext(module, bindingContext, symbolTable)
val generatorExtensions =
if (replCompilerState == null) GeneratorExtensions()
else object : GeneratorExtensions() {
override fun getPreviousScripts() = replCompilerState.history.map { it.item.scriptSymbol }
}
val psi2irContext = psi2ir.createGeneratorContext(module, bindingContext, symbolTable, generatorExtensions)
val providers = generateTypicalIrProviderList(module, psi2irContext.irBuiltIns, psi2irContext.symbolTable)
val irModuleFragment = psi2ir.generateModuleFragment(psi2irContext, files, providers, emptyList(), null) // TODO: deserializer
@@ -91,6 +105,16 @@ class JsCoreScriptingCompiler(
val code = generateJsCode(context, irModuleFragment, nameTables)
updateHistory(codeLine, irModuleFragment)
return createCompileResult(LineId(codeLine.no, 0, codeLine.hashCode()), code)
}
private fun updateHistory(codeLine: ReplCodeLine, irModuleFragment: IrModuleFragment) {
if (replCompilerState != null) {
val lineId = LineId(codeLine.no, 0, codeLine.code.hashCode())
val scriptSymbol = irModuleFragment.files.single().declarations.single { it is IrScript }.symbol as IrScriptSymbol
replCompilerState.history.push(lineId, JsReplCompilationHistoryItem(scriptSymbol))
}
}
}
@@ -19,7 +19,7 @@ import java.util.concurrent.locks.ReentrantReadWriteLock
class JsReplCompiler(private val environment: KotlinCoreEnvironment) : ReplCompiler {
override fun createState(lock: ReentrantReadWriteLock): IReplStageState<*> {
return JsReplCompilationState(
return JsReplCompilerState(
lock,
NameTables(emptyList(), mappedNames = mutableMapOf()),
readLibrariesFromConfiguration(environment.configuration),
@@ -33,13 +33,13 @@ class JsReplCompiler(private val environment: KotlinCoreEnvironment) : ReplCompi
}
override fun compile(state: IReplStageState<*>, codeLine: ReplCodeLine): ReplCompileResult {
val compilationState = state.asState(JsReplCompilationState::class.java)
val compilationState = state.asState(JsReplCompilerState::class.java)
return JsCoreScriptingCompiler(
environment,
compilationState.nameTables,
compilationState.symbolTable,
compilationState.dependencies,
compilationState.replState
compilationState
).compile(codeLine)
}
}
@@ -0,0 +1,35 @@
/*
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.scripting.repl.js
import org.jetbrains.kotlin.cli.common.repl.BasicReplStageHistory
import org.jetbrains.kotlin.cli.common.repl.IReplStageState
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
import org.jetbrains.kotlin.ir.backend.js.utils.NameTables
import org.jetbrains.kotlin.ir.symbols.IrScriptSymbol
import org.jetbrains.kotlin.ir.util.SymbolTable
import org.jetbrains.kotlin.scripting.compiler.plugin.repl.ReplCodeAnalyzerBase
import java.util.concurrent.locks.ReentrantReadWriteLock
class JsReplCompilationHistoryItem(
val scriptSymbol: IrScriptSymbol
)
class JsReplCompilerStageHistory(lock: ReentrantReadWriteLock) : BasicReplStageHistory<JsReplCompilationHistoryItem>(lock)
// NOTE: the state management machinery is reduced in this implementation, since it is unused at the moment in the JS REPL (see JvmReplCompilerState for complete implementation, if needed)
class JsReplCompilerState(
override val lock: ReentrantReadWriteLock,
val nameTables: NameTables,
val dependencies: List<ModuleDescriptor>,
val analyzerState: ReplCodeAnalyzerBase.ResettableAnalyzerState,
val symbolTable: SymbolTable
) : IReplStageState<JsReplCompilationHistoryItem> {
override val history = JsReplCompilerStageHistory(lock)
override val currentGeneration: Int get() = (history as BasicReplStageHistory<*>).currentGeneration.get()
}
@@ -9,8 +9,8 @@ import com.intellij.openapi.project.Project
import com.intellij.psi.PsiFileFactory
import com.intellij.psi.impl.PsiFileFactoryImpl
import org.jetbrains.kotlin.cli.common.CLIConfigurationKeys
import org.jetbrains.kotlin.cli.common.messages.CompilerMessageSourceLocation
import org.jetbrains.kotlin.cli.common.messages.CompilerMessageSeverity
import org.jetbrains.kotlin.cli.common.messages.CompilerMessageSourceLocation
import org.jetbrains.kotlin.cli.common.messages.GroupingMessageCollector
import org.jetbrains.kotlin.cli.common.messages.MessageCollector
import org.jetbrains.kotlin.cli.common.repl.LineId
@@ -23,11 +23,9 @@ import org.jetbrains.kotlin.idea.KotlinLanguage
import org.jetbrains.kotlin.ir.backend.js.getModuleDescriptorByLibrary
import org.jetbrains.kotlin.ir.backend.js.jsResolveLibraries
import org.jetbrains.kotlin.ir.backend.js.utils.NameTables
import org.jetbrains.kotlin.ir.util.SymbolTable
import org.jetbrains.kotlin.library.resolver.TopologicalLibraryOrder
import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.psi.KtScript
import org.jetbrains.kotlin.scripting.compiler.plugin.repl.ReplCodeAnalyzerBase
import org.jetbrains.kotlin.scripting.configuration.ScriptingConfigurationKeys
import org.jetbrains.kotlin.scripting.resolve.ScriptLightVirtualFile
import org.jetbrains.kotlin.util.Logger
@@ -37,7 +35,6 @@ import java.io.FileOutputStream
import java.io.FileReader
import java.io.InputStreamReader
import java.nio.charset.Charset
import java.util.concurrent.locks.ReentrantReadWriteLock
import kotlin.script.experimental.api.*
import kotlin.script.experimental.host.FileBasedScriptSource
import kotlin.script.experimental.jvm.JsDependency
@@ -216,11 +213,3 @@ class DependencyLoader {
}
}
class JsReplCompilationState(
lock: ReentrantReadWriteLock,
nameTables: NameTables,
dependencies: List<ModuleDescriptor>,
val replState: ReplCodeAnalyzerBase.ResettableAnalyzerState,
val symbolTable: SymbolTable
) : JsCompilationState(lock, nameTables, dependencies)