From bac6a7346e44ba87d08389129f323d8b941b061d Mon Sep 17 00:00:00 2001 From: Ilya Chernikov Date: Thu, 7 Jan 2021 18:15:05 +0100 Subject: [PATCH] Extend GeneratorExtensions with previous script, implemt it for JS REPL also refactor JS REPL for better compatibility with the generic REPL/scripting infrastructure --- .../psi2ir/generators/GeneratorExtensions.kt | 3 ++ .../psi2ir/generators/ScriptGenerator.kt | 6 ++-- .../repl/js/test/AbstractJsReplTest.kt | 8 ++--- .../repl/js/test/JsReplTestAgainstBinaries.kt | 4 +-- .../repl/js/test/JsReplTestAgainstKlib.kt | 4 +-- .../kotlin/scripting/repl/js/JsReplUtils.kt | 27 +++++--------- .../repl/js/JsCoreScriptingCompiler.kt | 30 ++++++++++++++-- .../scripting/repl/js/JsReplCompiler.kt | 6 ++-- .../kotlin/scripting/repl/js/JsReplState.kt | 35 +++++++++++++++++++ .../kotlin/scripting/repl/js/JsReplUtils.kt | 13 +------ 10 files changed, 89 insertions(+), 47 deletions(-) create mode 100644 plugins/scripting/scripting-compiler/src/org/jetbrains/kotlin/scripting/repl/js/JsReplState.kt diff --git a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/GeneratorExtensions.kt b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/GeneratorExtensions.kt index 293dba5e463..7f2178fadeb 100644 --- a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/GeneratorExtensions.kt +++ b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/GeneratorExtensions.kt @@ -10,6 +10,7 @@ import org.jetbrains.kotlin.descriptors.DescriptorVisibility import org.jetbrains.kotlin.descriptors.PropertyDescriptor import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor import org.jetbrains.kotlin.ir.expressions.IrDelegatingConstructorCall +import org.jetbrains.kotlin.ir.symbols.IrScriptSymbol import org.jetbrains.kotlin.ir.util.StubGeneratorExtensions import org.jetbrains.kotlin.psi.KtPureClassOrObject import org.jetbrains.kotlin.resolve.scopes.MemberScope @@ -39,4 +40,6 @@ open class GeneratorExtensions : StubGeneratorExtensions() { open val shouldPreventDeprecatedIntegerValueTypeLiteralConversion: Boolean get() = false + + open fun getPreviousScripts(): List = emptyList() } diff --git a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/ScriptGenerator.kt b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/ScriptGenerator.kt index 6ff3a093fc7..3927ab63014 100644 --- a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/ScriptGenerator.kt +++ b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/ScriptGenerator.kt @@ -39,7 +39,7 @@ class ScriptGenerator(declarationGenerator: DeclarationGenerator) : DeclarationG fun generateScriptDeclaration(ktScript: KtScript): IrDeclaration? { val descriptor = getOrFail(BindingContext.DECLARATION_TO_DESCRIPTOR, ktScript) as ScriptDescriptor - val existedScripts = context.symbolTable.listExistedScripts() + val previousScripts = context.extensions.getPreviousScripts() return context.symbolTable.declareScript(descriptor).buildWithScope { irScript -> @@ -54,7 +54,7 @@ class ScriptGenerator(declarationGenerator: DeclarationGenerator) : DeclarationG // TODO: since script could reference instances of previous one their receivers have to be enlisted in its scope // Remove this code once script is no longer represented by Class - existedScripts.forEach { + previousScripts.forEach { if (it.owner != irScript && it.descriptor !in importedScripts) { context.symbolTable.introduceValueParameter(it.owner.thisReceiver) } @@ -117,7 +117,7 @@ class ScriptGenerator(declarationGenerator: DeclarationGenerator) : DeclarationG valueParameter to irProperty.symbol } - irScript.earlierScripts = existedScripts + irScript.earlierScripts = previousScripts for (d in ktScript.declarations) { when (d) { diff --git a/libraries/scripting/js-test/test/org/jetbrains/kotlin/scripting/repl/js/test/AbstractJsReplTest.kt b/libraries/scripting/js-test/test/org/jetbrains/kotlin/scripting/repl/js/test/AbstractJsReplTest.kt index 6dfc7965700..f605cb2b570 100644 --- a/libraries/scripting/js-test/test/org/jetbrains/kotlin/scripting/repl/js/test/AbstractJsReplTest.kt +++ b/libraries/scripting/js-test/test/org/jetbrains/kotlin/scripting/repl/js/test/AbstractJsReplTest.kt @@ -29,14 +29,14 @@ import kotlin.script.experimental.host.ScriptingHostConfiguration import kotlin.script.experimental.jvm.JsDependency abstract class AbstractJsReplTest : Closeable { - protected lateinit var compilationState: JsReplCompilationState + protected lateinit var compilerState: JsReplCompilerState protected lateinit var evaluationState: JsEvaluationState - protected abstract fun createCompilationState(): JsReplCompilationState + protected abstract fun createCompilationState(): JsReplCompilerState protected abstract fun createEvaluationState(): JsEvaluationState fun compile(codeLine: ReplCodeLine): ReplCompileResult { - return JsReplCompiler(environment).compile(compilationState, codeLine) + return JsReplCompiler(environment).compile(compilerState, codeLine) } fun evaluate(compileResult: ReplCompileResult.CompiledClasses): ReplEvalResult { @@ -45,7 +45,7 @@ abstract class AbstractJsReplTest : Closeable { fun reset() { collector.clear() - compilationState = createCompilationState() + compilerState = createCompilationState() evaluationState = createEvaluationState() } diff --git a/libraries/scripting/js-test/test/org/jetbrains/kotlin/scripting/repl/js/test/JsReplTestAgainstBinaries.kt b/libraries/scripting/js-test/test/org/jetbrains/kotlin/scripting/repl/js/test/JsReplTestAgainstBinaries.kt index 3c90fdc4ce2..6bc0a375f3f 100644 --- a/libraries/scripting/js-test/test/org/jetbrains/kotlin/scripting/repl/js/test/JsReplTestAgainstBinaries.kt +++ b/libraries/scripting/js-test/test/org/jetbrains/kotlin/scripting/repl/js/test/JsReplTestAgainstBinaries.kt @@ -31,9 +31,9 @@ class JsReplTestAgainstBinaries : AbstractJsReplTest() { dependencyLoader.saveNames(nameTable) } - override fun createCompilationState(): JsReplCompilationState { + override fun createCompilationState(): JsReplCompilerState { val replState = ReplCodeAnalyzerBase.ResettableAnalyzerState() - return JsReplCompilationState(ReentrantReadWriteLock(), dependencyLoader.loadNames(), dependencies, replState, createSymbolTable()) + return JsReplCompilerState(ReentrantReadWriteLock(), dependencyLoader.loadNames(), dependencies, replState, createSymbolTable()) } private fun createSymbolTable(): SymbolTable = diff --git a/libraries/scripting/js-test/test/org/jetbrains/kotlin/scripting/repl/js/test/JsReplTestAgainstKlib.kt b/libraries/scripting/js-test/test/org/jetbrains/kotlin/scripting/repl/js/test/JsReplTestAgainstKlib.kt index 6c33f486da7..2cf11a41770 100644 --- a/libraries/scripting/js-test/test/org/jetbrains/kotlin/scripting/repl/js/test/JsReplTestAgainstKlib.kt +++ b/libraries/scripting/js-test/test/org/jetbrains/kotlin/scripting/repl/js/test/JsReplTestAgainstKlib.kt @@ -20,14 +20,14 @@ class JsReplTestAgainstKlib : AbstractJsReplTest() { private var dependencyCode: String? = null - override fun createCompilationState(): JsReplCompilationState { + override fun createCompilationState(): JsReplCompilerState { val nameTables = NameTables(emptyList(), mappedNames = mutableMapOf()) val symbolTable = SymbolTable(IdSignatureDescriptor(JsManglerDesc), IrFactoryImpl) val dependencyCompiler = JsScriptDependencyCompiler(environment.configuration, nameTables, symbolTable) val dependencies = readLibrariesFromConfiguration(environment.configuration) dependencyCode = dependencyCompiler.compile(dependencies) - return JsReplCompilationState( + return JsReplCompilerState( ReentrantReadWriteLock(), nameTables, dependencies, diff --git a/libraries/scripting/js/src/org/jetbrains/kotlin/scripting/repl/js/JsReplUtils.kt b/libraries/scripting/js/src/org/jetbrains/kotlin/scripting/repl/js/JsReplUtils.kt index 6fe2772dbd3..c361a640601 100644 --- a/libraries/scripting/js/src/org/jetbrains/kotlin/scripting/repl/js/JsReplUtils.kt +++ b/libraries/scripting/js/src/org/jetbrains/kotlin/scripting/repl/js/JsReplUtils.kt @@ -5,10 +5,8 @@ package org.jetbrains.kotlin.scripting.repl.js -import org.jetbrains.kotlin.cli.common.repl.* -import org.jetbrains.kotlin.descriptors.ModuleDescriptor -import org.jetbrains.kotlin.descriptors.ScriptDescriptor -import org.jetbrains.kotlin.ir.backend.js.utils.NameTables +import org.jetbrains.kotlin.cli.common.repl.IReplStageHistory +import org.jetbrains.kotlin.cli.common.repl.IReplStageState import org.jetbrains.kotlin.js.engine.ScriptEngineWithTypedResult import java.util.concurrent.locks.ReentrantReadWriteLock import kotlin.reflect.KClass @@ -17,24 +15,17 @@ import kotlin.script.experimental.api.ResultWithDiagnostics import kotlin.script.experimental.api.ScriptCompilationConfiguration import kotlin.script.experimental.api.ScriptEvaluationConfiguration -abstract class JsState(override val lock: ReentrantReadWriteLock) : IReplStageState { - override val history: IReplStageHistory +// NOTE: the state management machinery is not implemented here, since it is unused at the moment in the JS REPL (see JvmReplEvaluatorState for complete implementation, if needed) +class JsEvaluationState(override val lock: ReentrantReadWriteLock, val engine: ScriptEngineWithTypedResult) : IReplStageState { + override fun dispose() { + engine.reset() + } + + override val history: IReplStageHistory get() = TODO("not implemented") override val currentGeneration: Int get() = TODO("not implemented") - -} - -abstract class JsCompilationState( - lock: ReentrantReadWriteLock, - val nameTables: NameTables, - val dependencies: List) : JsState(lock) - -class JsEvaluationState(lock: ReentrantReadWriteLock, val engine: ScriptEngineWithTypedResult) : JsState(lock) { - override fun dispose() { - engine.reset() - } } class JsCompiledScript( diff --git a/plugins/scripting/scripting-compiler/src/org/jetbrains/kotlin/scripting/repl/js/JsCoreScriptingCompiler.kt b/plugins/scripting/scripting-compiler/src/org/jetbrains/kotlin/scripting/repl/js/JsCoreScriptingCompiler.kt index b86bfc21b7f..b480141bb7c 100644 --- a/plugins/scripting/scripting-compiler/src/org/jetbrains/kotlin/scripting/repl/js/JsCoreScriptingCompiler.kt +++ b/plugins/scripting/scripting-compiler/src/org/jetbrains/kotlin/scripting/repl/js/JsCoreScriptingCompiler.kt @@ -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, - 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)) + } + } } diff --git a/plugins/scripting/scripting-compiler/src/org/jetbrains/kotlin/scripting/repl/js/JsReplCompiler.kt b/plugins/scripting/scripting-compiler/src/org/jetbrains/kotlin/scripting/repl/js/JsReplCompiler.kt index ea537e441af..851169ce85f 100644 --- a/plugins/scripting/scripting-compiler/src/org/jetbrains/kotlin/scripting/repl/js/JsReplCompiler.kt +++ b/plugins/scripting/scripting-compiler/src/org/jetbrains/kotlin/scripting/repl/js/JsReplCompiler.kt @@ -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) } } diff --git a/plugins/scripting/scripting-compiler/src/org/jetbrains/kotlin/scripting/repl/js/JsReplState.kt b/plugins/scripting/scripting-compiler/src/org/jetbrains/kotlin/scripting/repl/js/JsReplState.kt new file mode 100644 index 00000000000..a8693c39a24 --- /dev/null +++ b/plugins/scripting/scripting-compiler/src/org/jetbrains/kotlin/scripting/repl/js/JsReplState.kt @@ -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(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, + val analyzerState: ReplCodeAnalyzerBase.ResettableAnalyzerState, + val symbolTable: SymbolTable +) : IReplStageState { + + override val history = JsReplCompilerStageHistory(lock) + + override val currentGeneration: Int get() = (history as BasicReplStageHistory<*>).currentGeneration.get() +} diff --git a/plugins/scripting/scripting-compiler/src/org/jetbrains/kotlin/scripting/repl/js/JsReplUtils.kt b/plugins/scripting/scripting-compiler/src/org/jetbrains/kotlin/scripting/repl/js/JsReplUtils.kt index 494da8dae31..033fb10361a 100644 --- a/plugins/scripting/scripting-compiler/src/org/jetbrains/kotlin/scripting/repl/js/JsReplUtils.kt +++ b/plugins/scripting/scripting-compiler/src/org/jetbrains/kotlin/scripting/repl/js/JsReplUtils.kt @@ -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, - val replState: ReplCodeAnalyzerBase.ResettableAnalyzerState, - val symbolTable: SymbolTable -) : JsCompilationState(lock, nameTables, dependencies) -