[JS BE] Drop JS scripting support
JS scripting uses the old IR to JS transformer. The new IR to JS transformer can not be used for JS scripting out of the box. Patching the new transformer for JS scripting is potentially dangerous and requires a lot of effort. Dropping JS scripting and the old IR to JS transformer allows to refactor and simplify JS BE codebase.
This commit is contained in:
committed by
Space Team
parent
d75bbc49e7
commit
d5e9e87538
@@ -1,32 +0,0 @@
|
||||
description = "Kotlin Scripting Compiler JS Plugin"
|
||||
|
||||
plugins {
|
||||
kotlin("jvm")
|
||||
id("jps-compatible")
|
||||
}
|
||||
|
||||
dependencies {
|
||||
compileOnly(project(":compiler:frontend"))
|
||||
compileOnly(project(":compiler:psi"))
|
||||
compileOnly(project(":compiler:plugin-api"))
|
||||
compileOnly(project(":compiler:cli"))
|
||||
compileOnly(project(":compiler:backend.js"))
|
||||
compileOnly(project(":core:descriptors.runtime"))
|
||||
compileOnly(project(":compiler:ir.tree"))
|
||||
api(project(":kotlin-scripting-common"))
|
||||
api(project(":kotlin-scripting-js"))
|
||||
api(project(":kotlin-util-klib"))
|
||||
api(project(":kotlin-scripting-compiler"))
|
||||
api(kotlinStdlib())
|
||||
compileOnly(intellijCore())
|
||||
}
|
||||
|
||||
sourceSets {
|
||||
"main" { projectDefault() }
|
||||
}
|
||||
|
||||
tasks.withType<org.jetbrains.kotlin.gradle.dsl.KotlinCompile<*>> {
|
||||
kotlinOptions {
|
||||
freeCompilerArgs = freeCompilerArgs - "-progressive" + "-Xskip-metadata-version-check"
|
||||
}
|
||||
}
|
||||
-87
@@ -1,87 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010-2019 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.js
|
||||
|
||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||
import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment
|
||||
import org.jetbrains.kotlin.cli.jvm.compiler.NoScopeRecordCliBindingTrace
|
||||
import org.jetbrains.kotlin.config.languageVersionSettings
|
||||
import org.jetbrains.kotlin.context.ContextForNewModule
|
||||
import org.jetbrains.kotlin.context.ProjectContext
|
||||
import org.jetbrains.kotlin.descriptors.ClassDescriptorWithResolutionScopes
|
||||
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.PackageFragmentProvider
|
||||
import org.jetbrains.kotlin.descriptors.impl.ModuleDescriptorImpl
|
||||
import org.jetbrains.kotlin.diagnostics.Severity
|
||||
import org.jetbrains.kotlin.frontend.js.di.createTopDownAnalyzerForJs
|
||||
import org.jetbrains.kotlin.incremental.components.EnumWhenTracker
|
||||
import org.jetbrains.kotlin.incremental.components.ExpectActualTracker
|
||||
import org.jetbrains.kotlin.incremental.components.InlineConstTracker
|
||||
import org.jetbrains.kotlin.incremental.components.LookupTracker
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.psi.KtFile
|
||||
import org.jetbrains.kotlin.resolve.BindingContext
|
||||
import org.jetbrains.kotlin.resolve.BindingTraceContext
|
||||
import org.jetbrains.kotlin.resolve.CompilerEnvironment
|
||||
import org.jetbrains.kotlin.resolve.TopDownAnalysisMode
|
||||
import org.jetbrains.kotlin.resolve.lazy.declarations.FileBasedDeclarationProviderFactory
|
||||
|
||||
abstract class AbstractJsScriptlikeCodeAnalyser(
|
||||
private val environment: KotlinCoreEnvironment,
|
||||
private val dependencies: List<ModuleDescriptor>
|
||||
) {
|
||||
|
||||
protected class JsScriptAnalysisResult(
|
||||
val moduleDescriptor: ModuleDescriptor,
|
||||
private val scriptDescriptor: ClassDescriptorWithResolutionScopes?,
|
||||
val bindingContext: BindingContext
|
||||
) {
|
||||
val isSuccess: Boolean get() = scriptDescriptor != null
|
||||
val script: ClassDescriptorWithResolutionScopes get() = scriptDescriptor ?: error("Error occurred")
|
||||
}
|
||||
|
||||
protected fun analysisImpl(psi: KtFile): JsScriptAnalysisResult {
|
||||
val trace: BindingTraceContext = NoScopeRecordCliBindingTrace()
|
||||
val project = environment.project
|
||||
val builtIns: KotlinBuiltIns = dependencies.single { it.allDependencyModules.isEmpty() }.builtIns
|
||||
val moduleContext = ContextForNewModule(
|
||||
ProjectContext(project, "TopDownAnalyzer for JS Script"),
|
||||
Name.special("<script>"),
|
||||
builtIns,
|
||||
platform = null
|
||||
)
|
||||
val languageVersionSettings = environment.configuration.languageVersionSettings
|
||||
val lookupTracker = LookupTracker.DO_NOTHING
|
||||
val expectActualTracker = ExpectActualTracker.DoNothing
|
||||
val inlineConstTracker = InlineConstTracker.DoNothing
|
||||
val enumWhenTracker = EnumWhenTracker.DoNothing
|
||||
val additionalPackages = emptyList<PackageFragmentProvider>()
|
||||
val moduleDescriptor = moduleContext.module
|
||||
|
||||
moduleDescriptor.setDependencies(dependencies.map { it as ModuleDescriptorImpl } + moduleDescriptor)
|
||||
|
||||
val analyzer = createTopDownAnalyzerForJs(
|
||||
moduleContext, trace,
|
||||
FileBasedDeclarationProviderFactory(moduleContext.storageManager, listOf(psi)),
|
||||
languageVersionSettings,
|
||||
lookupTracker,
|
||||
expectActualTracker,
|
||||
inlineConstTracker,
|
||||
enumWhenTracker,
|
||||
additionalPackages,
|
||||
CompilerEnvironment,
|
||||
)
|
||||
val analyzerContext = analyzer.analyzeDeclarations(TopDownAnalysisMode.TopLevelDeclarations, listOf(psi))
|
||||
|
||||
val diagnostics = trace.bindingContext.diagnostics
|
||||
val hasErrors = diagnostics.any { it.severity == Severity.ERROR }
|
||||
val scriptDescriptor = analyzerContext.scripts[psi.script]
|
||||
|
||||
assert(scriptDescriptor != null || hasErrors) { "If no errors occurred script descriptor has to be existed" }
|
||||
|
||||
return JsScriptAnalysisResult(moduleDescriptor, scriptDescriptor, trace.bindingContext)
|
||||
}
|
||||
}
|
||||
-127
@@ -1,127 +0,0 @@
|
||||
/*
|
||||
* 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.js
|
||||
|
||||
import org.jetbrains.kotlin.backend.common.serialization.DescriptorByIdSignatureFinderImpl
|
||||
import org.jetbrains.kotlin.backend.common.serialization.linkerissues.checkNoUnboundSymbols
|
||||
import org.jetbrains.kotlin.cli.common.CLIConfigurationKeys
|
||||
import org.jetbrains.kotlin.cli.common.environment.setIdeaIoUseFallback
|
||||
import org.jetbrains.kotlin.cli.common.messages.AnalyzerWithCompilerReport
|
||||
import org.jetbrains.kotlin.cli.common.messages.MessageCollector
|
||||
import org.jetbrains.kotlin.cli.common.repl.LineId
|
||||
import org.jetbrains.kotlin.cli.common.repl.ReplCodeLine
|
||||
import org.jetbrains.kotlin.cli.common.repl.ReplCompileResult
|
||||
import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment
|
||||
import org.jetbrains.kotlin.config.languageVersionSettings
|
||||
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.lower.serialization.ir.JsManglerDesc
|
||||
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.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.GeneratorExtensions
|
||||
import org.jetbrains.kotlin.psi2ir.generators.generateTypicalIrProviderList
|
||||
import org.jetbrains.kotlin.scripting.compiler.plugin.repl.ReplCodeAnalyzerBase
|
||||
import org.jetbrains.kotlin.serialization.js.ModuleKind
|
||||
import kotlin.script.experimental.api.valueOr
|
||||
import kotlin.script.experimental.host.StringScriptSource
|
||||
|
||||
class JsCoreScriptingCompiler(
|
||||
private val environment: KotlinCoreEnvironment,
|
||||
private val nameTables: NameTables,
|
||||
private val symbolTable: SymbolTable,
|
||||
private val dependencyDescriptors: List<ModuleDescriptor>,
|
||||
private val replCompilerState: JsReplCompilerState? = null
|
||||
) {
|
||||
fun compile(codeLine: ReplCodeLine): ReplCompileResult {
|
||||
val snippet = codeLine.code
|
||||
val snippetId = codeLine.no
|
||||
|
||||
setIdeaIoUseFallback()
|
||||
|
||||
val sourceCode = StringScriptSource(snippet, "line-$snippetId.kts")
|
||||
val snippetKtFile = getScriptKtFile(
|
||||
sourceCode,
|
||||
snippet,
|
||||
environment.project
|
||||
).valueOr { return ReplCompileResult.Error(it.reports.joinToString { r -> r.message }) }
|
||||
|
||||
val messageCollector = environment.configuration[CLIConfigurationKeys.MESSAGE_COLLECTOR_KEY] as MessageCollector
|
||||
|
||||
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, renderInternalDiagnosticName = false)
|
||||
if (messageCollector.hasErrors()) return ReplCompileResult.Error("Error while analysis")
|
||||
}
|
||||
|
||||
val files = listOf(snippetKtFile)
|
||||
val (bindingContext, module) = analysisResult
|
||||
val psi2ir = Psi2IrTranslator(
|
||||
environment.configuration.languageVersionSettings,
|
||||
Psi2IrConfiguration(),
|
||||
environment.configuration::checkNoUnboundSymbols
|
||||
)
|
||||
|
||||
val generatorExtensions =
|
||||
if (replCompilerState == null) GeneratorExtensions()
|
||||
else object : GeneratorExtensions() {
|
||||
override fun getPreviousScripts() = replCompilerState.history.map { it.item.scriptSymbol }
|
||||
override val lowerScriptToClass: Boolean = false
|
||||
}
|
||||
|
||||
val psi2irContext = psi2ir.createGeneratorContext(module, bindingContext, symbolTable, generatorExtensions)
|
||||
val providers = generateTypicalIrProviderList(
|
||||
module, psi2irContext.irBuiltIns, psi2irContext.symbolTable, DescriptorByIdSignatureFinderImpl(module, JsManglerDesc)
|
||||
)
|
||||
val irModuleFragment = psi2ir.generateModuleFragment(psi2irContext, files, providers, emptyList(), null) // TODO: deserializer
|
||||
|
||||
val context = JsIrBackendContext(
|
||||
irModuleFragment.descriptor,
|
||||
psi2irContext.irBuiltIns,
|
||||
psi2irContext.symbolTable,
|
||||
irModuleFragment,
|
||||
additionalExportedDeclarationNames = emptySet(),
|
||||
keep = emptySet(),
|
||||
environment.configuration,
|
||||
true
|
||||
)
|
||||
|
||||
ExternalDependenciesGenerator(
|
||||
psi2irContext.symbolTable,
|
||||
generateTypicalIrProviderList(
|
||||
irModuleFragment.descriptor,
|
||||
psi2irContext.irBuiltIns,
|
||||
psi2irContext.symbolTable,
|
||||
DescriptorByIdSignatureFinderImpl(irModuleFragment.descriptor, JsManglerDesc)
|
||||
)
|
||||
).generateUnboundSymbolsAsDependencies()
|
||||
|
||||
environment.configuration.put(JSConfigurationKeys.MODULE_KIND, ModuleKind.PLAIN)
|
||||
|
||||
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))
|
||||
}
|
||||
}
|
||||
}
|
||||
-37
@@ -1,37 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010-2019 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.js
|
||||
|
||||
import org.jetbrains.kotlin.analyzer.AnalysisResult
|
||||
import org.jetbrains.kotlin.cli.common.repl.ReplCodeLine
|
||||
import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment
|
||||
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
|
||||
import org.jetbrains.kotlin.psi.KtFile
|
||||
import org.jetbrains.kotlin.scripting.compiler.plugin.repl.ReplCodeAnalyzerBase
|
||||
import org.jetbrains.kotlin.scripting.compiler.plugin.repl.toSourceCode
|
||||
import org.jetbrains.kotlin.scripting.definitions.ScriptPriorities
|
||||
|
||||
class JsReplCodeAnalyzer(
|
||||
environment: KotlinCoreEnvironment,
|
||||
dependencies: List<ModuleDescriptor>,
|
||||
private val replState: ReplCodeAnalyzerBase.ResettableAnalyzerState
|
||||
) : AbstractJsScriptlikeCodeAnalyser(environment, dependencies) {
|
||||
|
||||
fun analyzeReplLine(linePsi: KtFile, codeLine: ReplCodeLine): AnalysisResult {
|
||||
linePsi.script!!.putUserData(ScriptPriorities.PRIORITY_KEY, codeLine.no)
|
||||
replState.submitLine(linePsi)
|
||||
|
||||
val result = analysisImpl(linePsi)
|
||||
|
||||
return if (result.isSuccess) {
|
||||
replState.lineSuccess(linePsi, codeLine.toSourceCode(), result.script)
|
||||
AnalysisResult.success(result.bindingContext, result.moduleDescriptor)
|
||||
} else {
|
||||
replState.lineFailure(linePsi)
|
||||
AnalysisResult.compilationError(result.bindingContext)
|
||||
}
|
||||
}
|
||||
}
|
||||
-45
@@ -1,45 +0,0 @@
|
||||
/*
|
||||
* 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.js
|
||||
|
||||
import org.jetbrains.kotlin.backend.common.serialization.signature.IdSignatureDescriptor
|
||||
import org.jetbrains.kotlin.cli.common.repl.*
|
||||
import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment
|
||||
import org.jetbrains.kotlin.ir.backend.js.lower.serialization.ir.JsManglerDesc
|
||||
import org.jetbrains.kotlin.ir.backend.js.utils.NameTables
|
||||
import org.jetbrains.kotlin.ir.declarations.impl.IrFactoryImpl
|
||||
import org.jetbrains.kotlin.ir.util.SymbolTable
|
||||
import org.jetbrains.kotlin.scripting.compiler.plugin.repl.ReplCodeAnalyzerBase
|
||||
import java.util.concurrent.locks.ReentrantReadWriteLock
|
||||
|
||||
// Used to compile REPL code lines
|
||||
class JsReplCompiler(private val environment: KotlinCoreEnvironment) : ReplCompiler {
|
||||
|
||||
override fun createState(lock: ReentrantReadWriteLock): IReplStageState<*> {
|
||||
return JsReplCompilerState(
|
||||
lock,
|
||||
NameTables(emptyList(), mappedNames = mutableMapOf()),
|
||||
readLibrariesFromConfiguration(environment.configuration),
|
||||
ReplCodeAnalyzerBase.ResettableAnalyzerState(),
|
||||
SymbolTable(IdSignatureDescriptor(JsManglerDesc), IrFactoryImpl)
|
||||
)
|
||||
}
|
||||
|
||||
override fun check(state: IReplStageState<*>, codeLine: ReplCodeLine): ReplCheckResult {
|
||||
return ReplCheckResult.Ok()
|
||||
}
|
||||
|
||||
override fun compile(state: IReplStageState<*>, codeLine: ReplCodeLine): ReplCompileResult {
|
||||
val compilationState = state.asState(JsReplCompilerState::class.java)
|
||||
return JsCoreScriptingCompiler(
|
||||
environment,
|
||||
compilationState.nameTables,
|
||||
compilationState.symbolTable,
|
||||
compilationState.dependencies,
|
||||
compilationState
|
||||
).compile(codeLine)
|
||||
}
|
||||
}
|
||||
-35
@@ -1,35 +0,0 @@
|
||||
/*
|
||||
* 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.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()
|
||||
}
|
||||
-215
@@ -1,215 +0,0 @@
|
||||
/*
|
||||
* 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.js
|
||||
|
||||
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.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
|
||||
import org.jetbrains.kotlin.cli.common.repl.ReplCodeLine
|
||||
import org.jetbrains.kotlin.cli.common.repl.ReplCompileResult
|
||||
import org.jetbrains.kotlin.config.CompilerConfiguration
|
||||
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.impl.ModuleDescriptorImpl
|
||||
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.library.resolver.TopologicalLibraryOrder
|
||||
import org.jetbrains.kotlin.psi.KtFile
|
||||
import org.jetbrains.kotlin.psi.KtScript
|
||||
import org.jetbrains.kotlin.scripting.configuration.ScriptingConfigurationKeys
|
||||
import org.jetbrains.kotlin.scripting.resolve.ScriptLightVirtualFile
|
||||
import org.jetbrains.kotlin.util.Logger
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstanceOrNull
|
||||
import java.io.BufferedReader
|
||||
import java.io.FileOutputStream
|
||||
import java.io.FileReader
|
||||
import java.io.InputStreamReader
|
||||
import java.nio.charset.Charset
|
||||
import kotlin.script.experimental.api.*
|
||||
import kotlin.script.experimental.host.FileBasedScriptSource
|
||||
import kotlin.script.experimental.jvm.JsDependency
|
||||
|
||||
fun getScriptKtFile(
|
||||
script: SourceCode,
|
||||
scriptText: String,
|
||||
project: Project
|
||||
): ResultWithDiagnostics<KtFile> {
|
||||
val psiFileFactory: PsiFileFactoryImpl = PsiFileFactory.getInstance(project) as PsiFileFactoryImpl
|
||||
val virtualFile = ScriptLightVirtualFile(
|
||||
script.name!!,
|
||||
(script as? FileBasedScriptSource)?.file?.path,
|
||||
scriptText
|
||||
)
|
||||
val ktFile = psiFileFactory.trySetupPsiForFile(virtualFile, KotlinLanguage.INSTANCE, true, false) as KtFile?
|
||||
return when {
|
||||
ktFile == null -> ResultWithDiagnostics.Failure(
|
||||
ScriptDiagnostic(
|
||||
ScriptDiagnostic.unspecifiedError,
|
||||
message = "Cannot create PSI",
|
||||
severity = ScriptDiagnostic.Severity.ERROR
|
||||
)
|
||||
)
|
||||
ktFile.declarations.firstIsInstanceOrNull<KtScript>() == null -> ResultWithDiagnostics.Failure(
|
||||
ScriptDiagnostic(
|
||||
ScriptDiagnostic.unspecifiedError,
|
||||
message = "There is not Script",
|
||||
severity = ScriptDiagnostic.Severity.ERROR
|
||||
)
|
||||
)
|
||||
else -> ktFile.asSuccess()
|
||||
}
|
||||
}
|
||||
|
||||
fun makeReplCodeLine(no: Int, code: String): ReplCodeLine = ReplCodeLine(no, 0, code)
|
||||
|
||||
//TODO: remove and use collector from kotlin-scripting-compiler
|
||||
class ReplMessageCollector : MessageCollector {
|
||||
private var hasErrors = false
|
||||
private var messages = mutableListOf<Pair<CompilerMessageSeverity, String>>()
|
||||
|
||||
override fun clear() {
|
||||
hasErrors = false
|
||||
messages.clear()
|
||||
}
|
||||
|
||||
override fun report(severity: CompilerMessageSeverity, message: String, location: CompilerMessageSourceLocation?) {
|
||||
if (severity == CompilerMessageSeverity.ERROR) hasErrors = true
|
||||
messages.add(Pair(severity, message))
|
||||
}
|
||||
|
||||
override fun hasErrors(): Boolean {
|
||||
return hasErrors
|
||||
}
|
||||
|
||||
fun hasNotErrors(): Boolean {
|
||||
return !hasErrors
|
||||
}
|
||||
|
||||
fun getMessage(): String {
|
||||
val resultMessage = StringBuilder("Found ${messages.size} problems:\n")
|
||||
for (m in messages) {
|
||||
resultMessage.append(m.first.toString() + " : " + m.second + "\n")
|
||||
}
|
||||
return resultMessage.toString()
|
||||
}
|
||||
}
|
||||
|
||||
fun readLibrariesFromConfiguration(configuration: CompilerConfiguration): List<ModuleDescriptor> {
|
||||
// TODO: Reimplement this code once we get proper klib dependency resolver
|
||||
val scriptConfig = configuration[ScriptingConfigurationKeys.SCRIPT_DEFINITIONS]!!
|
||||
val scriptCompilationConfig = scriptConfig.find { (it).platform == "JS" }!!.compilationConfiguration
|
||||
val scriptDependencies = scriptCompilationConfig[ScriptCompilationConfiguration.dependencies]!!
|
||||
val descriptorMap = mutableMapOf<String, ModuleDescriptorImpl>()
|
||||
val libraries = scriptDependencies.map { (it as JsDependency).path }
|
||||
val resolvedLibraries = jsResolveLibraries(
|
||||
libraries,
|
||||
emptyList(),
|
||||
object : Logger {
|
||||
private val collector = configuration[CLIConfigurationKeys.MESSAGE_COLLECTOR_KEY] ?: MessageCollector.NONE
|
||||
override fun warning(message: String) = collector.report(CompilerMessageSeverity.STRONG_WARNING, message)
|
||||
override fun error(message: String) = collector.report(CompilerMessageSeverity.ERROR, message)
|
||||
override fun log(message: String) = collector.report(CompilerMessageSeverity.LOGGING, message)
|
||||
override fun fatal(message: String): Nothing {
|
||||
collector.report(CompilerMessageSeverity.ERROR, message)
|
||||
(collector as? GroupingMessageCollector)?.flush()
|
||||
kotlin.error(message)
|
||||
}
|
||||
}
|
||||
)
|
||||
return resolvedLibraries.getFullList(TopologicalLibraryOrder)
|
||||
.map { descriptorMap.getOrPut(it.libraryName) { getModuleDescriptorByLibrary(it, descriptorMap) } }
|
||||
}
|
||||
|
||||
fun createCompileResult(code: String) = createCompileResult(LineId(0, 0, 0), code)
|
||||
|
||||
fun createCompileResult(lineId: LineId, code: String): ReplCompileResult.CompiledClasses {
|
||||
return ReplCompileResult.CompiledClasses(
|
||||
lineId,
|
||||
emptyList(),
|
||||
"",
|
||||
emptyList(),
|
||||
false,
|
||||
emptyList(),
|
||||
"Any?",
|
||||
code
|
||||
)
|
||||
}
|
||||
|
||||
class DependencyLoader {
|
||||
// TODO: this should be taken from CompilerConfiguration
|
||||
private val commonPath = "libraries/stdlib/js-ir/build/classes/kotlin/js/main/"
|
||||
private val mappedNamesPath = "$commonPath/mappedNames.txt"
|
||||
private val scriptDependencyBinaryPath = "$commonPath/scriptDependencyBinary.js"
|
||||
|
||||
fun saveNames(nameTables: NameTables, path: String = mappedNamesPath) {
|
||||
writeDataByPath(writeNames(nameTables), path)
|
||||
}
|
||||
|
||||
fun loadNames(path: String = mappedNamesPath): NameTables {
|
||||
return readNames(readDataByPath(path))
|
||||
}
|
||||
|
||||
fun saveScriptDependencyBinary(stdlibCompiledResult: String, path: String = scriptDependencyBinaryPath) {
|
||||
writeDataByPath(writeScriptDependencyBinary(stdlibCompiledResult), path)
|
||||
}
|
||||
|
||||
fun loadScriptDependencyBinary(path: String = scriptDependencyBinaryPath): String {
|
||||
return readScriptDependencyBinary(readDataByPath(path))
|
||||
}
|
||||
|
||||
|
||||
fun writeNames(nameTables: NameTables): ByteArray {
|
||||
val result = StringBuilder()
|
||||
for (entry in nameTables.mappedNames.orEmpty()) {
|
||||
result.append("${entry.key} ${entry.value}" + System.lineSeparator())
|
||||
}
|
||||
return result.toString().toByteArray(Charset.defaultCharset())
|
||||
}
|
||||
|
||||
fun readNames(data: ByteArray): NameTables {
|
||||
val mappedNames = mutableMapOf<String, String>()
|
||||
val reserved = mutableSetOf<String>()
|
||||
|
||||
BufferedReader(InputStreamReader(data.inputStream())).use { reader ->
|
||||
for (line in reader.readLines()) {
|
||||
val (key, value) = line.split(" ")
|
||||
mappedNames[key] = value
|
||||
reserved += value
|
||||
}
|
||||
}
|
||||
|
||||
return NameTables(emptyList(), mappedNames = mappedNames, reservedForGlobal = reserved)
|
||||
}
|
||||
|
||||
fun writeScriptDependencyBinary(stdlibCompiledResult: String): ByteArray {
|
||||
return stdlibCompiledResult.toByteArray(Charset.defaultCharset())
|
||||
}
|
||||
|
||||
fun readScriptDependencyBinary(data: ByteArray): String {
|
||||
return data.toString(Charset.defaultCharset())
|
||||
}
|
||||
|
||||
fun readDataByPath(path: String): ByteArray {
|
||||
FileReader(path).use { reader ->
|
||||
val stdlibCompiledResult = reader.readText()
|
||||
return stdlibCompiledResult.toByteArray(Charset.defaultCharset())
|
||||
}
|
||||
}
|
||||
|
||||
fun writeDataByPath(data: ByteArray, path: String) {
|
||||
FileOutputStream(path).use {
|
||||
it.write(data)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
-82
@@ -1,82 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010-2019 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.js
|
||||
|
||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||
import org.jetbrains.kotlin.config.CompilerConfiguration
|
||||
import org.jetbrains.kotlin.config.LanguageVersionSettingsImpl
|
||||
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.PackageFragmentProvider
|
||||
import org.jetbrains.kotlin.descriptors.impl.ModuleDescriptorImpl
|
||||
import org.jetbrains.kotlin.descriptors.konan.kotlinLibrary
|
||||
import org.jetbrains.kotlin.ir.ObsoleteDescriptorBasedAPI
|
||||
import org.jetbrains.kotlin.ir.backend.js.JsIrBackendContext
|
||||
import org.jetbrains.kotlin.ir.backend.js.generateJsCode
|
||||
import org.jetbrains.kotlin.ir.backend.js.lower.serialization.ir.JsIrLinker
|
||||
import org.jetbrains.kotlin.ir.backend.js.utils.NameTables
|
||||
import org.jetbrains.kotlin.ir.util.*
|
||||
import org.jetbrains.kotlin.js.config.JSConfigurationKeys
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.psi2ir.descriptors.IrBuiltInsOverDescriptors
|
||||
import org.jetbrains.kotlin.psi2ir.generators.TypeTranslatorImpl
|
||||
import org.jetbrains.kotlin.serialization.js.ModuleKind
|
||||
import org.jetbrains.kotlin.storage.LockBasedStorageManager
|
||||
|
||||
// Transforms klib into js code in script-friendly way
|
||||
@OptIn(ObsoleteDescriptorBasedAPI::class)
|
||||
class JsScriptDependencyCompiler(
|
||||
private val configuration: CompilerConfiguration,
|
||||
private val nameTables: NameTables,
|
||||
private val symbolTable: SymbolTable
|
||||
) {
|
||||
fun compile(dependencies: List<ModuleDescriptor>): String {
|
||||
val builtIns: KotlinBuiltIns = dependencies.single { it.allDependencyModules.isEmpty() }.builtIns
|
||||
val languageVersionSettings = LanguageVersionSettingsImpl.DEFAULT
|
||||
val messageLogger = configuration.irMessageLogger
|
||||
val moduleName = Name.special("<script-dependencies>")
|
||||
val storageManager = LockBasedStorageManager.NO_LOCKS
|
||||
val moduleDescriptor = ModuleDescriptorImpl(moduleName, storageManager, builtIns, null).also {
|
||||
it.setDependencies(dependencies.map { d -> d as ModuleDescriptorImpl } + it)
|
||||
it.initialize(PackageFragmentProvider.Empty)
|
||||
}
|
||||
|
||||
val typeTranslator = TypeTranslatorImpl(symbolTable, languageVersionSettings, moduleDescriptor)
|
||||
val irBuiltIns = IrBuiltInsOverDescriptors(builtIns, typeTranslator, symbolTable)
|
||||
val jsLinker = JsIrLinker(null, messageLogger, irBuiltIns, symbolTable, partialLinkageEnabled = false, null)
|
||||
|
||||
val irDependencies = dependencies.map { jsLinker.deserializeFullModule(it, it.kotlinLibrary) }
|
||||
val moduleFragment = irDependencies.last()
|
||||
val irProviders = listOf(jsLinker)
|
||||
|
||||
jsLinker.init(null, emptyList())
|
||||
|
||||
ExternalDependenciesGenerator(symbolTable, irProviders)
|
||||
.generateUnboundSymbolsAsDependencies()
|
||||
moduleFragment.patchDeclarationParents()
|
||||
|
||||
val backendContext = JsIrBackendContext(
|
||||
moduleDescriptor,
|
||||
irBuiltIns,
|
||||
symbolTable,
|
||||
moduleFragment,
|
||||
additionalExportedDeclarationNames = emptySet(),
|
||||
keep = emptySet(),
|
||||
configuration,
|
||||
true
|
||||
)
|
||||
|
||||
ExternalDependenciesGenerator(symbolTable, irProviders)
|
||||
.generateUnboundSymbolsAsDependencies()
|
||||
moduleFragment.patchDeclarationParents()
|
||||
jsLinker.postProcess()
|
||||
|
||||
moduleFragment.files += irDependencies.filter { it !== moduleFragment }.flatMap { it.files }
|
||||
|
||||
configuration.put(JSConfigurationKeys.MODULE_KIND, ModuleKind.PLAIN)
|
||||
|
||||
return generateJsCode(backendContext, moduleFragment, nameTables)
|
||||
}
|
||||
}
|
||||
-69
@@ -1,69 +0,0 @@
|
||||
/*
|
||||
* 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.js
|
||||
|
||||
import org.jetbrains.kotlin.cli.common.arguments.CommonCompilerArguments
|
||||
import org.jetbrains.kotlin.cli.common.arguments.K2JSCompilerArguments
|
||||
import org.jetbrains.kotlin.cli.jvm.compiler.EnvironmentConfigFiles
|
||||
import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment
|
||||
import org.jetbrains.kotlin.config.CompilerConfiguration
|
||||
import org.jetbrains.kotlin.scripting.compiler.plugin.AbstractScriptEvaluationExtension
|
||||
import org.jetbrains.kotlin.scripting.compiler.plugin.ScriptCompilerProxy
|
||||
import org.jetbrains.kotlin.scripting.configuration.ScriptingConfigurationKeys
|
||||
import org.jetbrains.kotlin.scripting.definitions.ScriptDefinition
|
||||
import org.jetbrains.kotlin.scripting.definitions.platform
|
||||
import org.jetbrains.kotlin.scripting.repl.js.JsScriptEvaluator
|
||||
import kotlin.script.experimental.api.*
|
||||
import kotlin.script.experimental.host.ScriptingHostConfiguration
|
||||
import kotlin.script.experimental.jvm.JsDependency
|
||||
|
||||
// TODO: the code below has to be considered as temporary hack and removed ASAP.
|
||||
// Actual ScriptCompilationConfiguration should be set up from CompilerConfiguration.
|
||||
fun loadScriptConfiguration(configuration: CompilerConfiguration) {
|
||||
val scriptConfiguration = ScriptCompilationConfiguration {
|
||||
baseClass("kotlin.Any")
|
||||
dependencies.append(JsDependency("libraries/stdlib/js-ir/build/classes/kotlin/js/main/"))
|
||||
platform.put("JS")
|
||||
}
|
||||
configuration.add(
|
||||
ScriptingConfigurationKeys.SCRIPT_DEFINITIONS,
|
||||
ScriptDefinition.FromConfigurations(ScriptingHostConfiguration(), scriptConfiguration, null)
|
||||
)
|
||||
}
|
||||
|
||||
class JsScriptEvaluationExtension : AbstractScriptEvaluationExtension() {
|
||||
|
||||
override fun setupScriptConfiguration(configuration: CompilerConfiguration) {
|
||||
loadScriptConfiguration(configuration)
|
||||
}
|
||||
|
||||
override fun createEnvironment(
|
||||
projectEnvironment: KotlinCoreEnvironment.ProjectEnvironment,
|
||||
configuration: CompilerConfiguration
|
||||
): KotlinCoreEnvironment {
|
||||
return KotlinCoreEnvironment.createForProduction(
|
||||
projectEnvironment,
|
||||
configuration,
|
||||
EnvironmentConfigFiles.JS_CONFIG_FILES
|
||||
)
|
||||
}
|
||||
|
||||
override fun createScriptEvaluator(): ScriptEvaluator {
|
||||
return JsScriptEvaluator()
|
||||
}
|
||||
|
||||
private var scriptCompilerProxy: ScriptCompilerProxy? = null
|
||||
|
||||
override fun createScriptCompiler(environment: KotlinCoreEnvironment): ScriptCompilerProxy {
|
||||
return scriptCompilerProxy ?: JsScriptCompilerWithDependenciesProxy(environment).also { scriptCompilerProxy = it }
|
||||
}
|
||||
|
||||
override fun ScriptEvaluationConfiguration.Builder.platformEvaluationConfiguration() {}
|
||||
|
||||
override fun isAccepted(arguments: CommonCompilerArguments): Boolean {
|
||||
return arguments is K2JSCompilerArguments
|
||||
}
|
||||
}
|
||||
-63
@@ -1,63 +0,0 @@
|
||||
/*
|
||||
* 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.js
|
||||
|
||||
import org.jetbrains.kotlin.backend.common.serialization.signature.IdSignatureDescriptor
|
||||
import org.jetbrains.kotlin.cli.common.CLIConfigurationKeys
|
||||
import org.jetbrains.kotlin.cli.common.repl.ReplCompileResult
|
||||
import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment
|
||||
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
|
||||
import org.jetbrains.kotlin.ir.backend.js.lower.serialization.ir.JsManglerDesc
|
||||
import org.jetbrains.kotlin.ir.backend.js.utils.NameTables
|
||||
import org.jetbrains.kotlin.ir.declarations.impl.IrFactoryImpl
|
||||
import org.jetbrains.kotlin.ir.util.SymbolTable
|
||||
import org.jetbrains.kotlin.scripting.compiler.plugin.ScriptCompilerProxy
|
||||
import org.jetbrains.kotlin.scripting.compiler.plugin.impl.withMessageCollector
|
||||
import org.jetbrains.kotlin.scripting.repl.js.JsCompiledScript
|
||||
import kotlin.script.experimental.api.*
|
||||
|
||||
class JsScriptCompilerWithDependenciesProxy(private val environment: KotlinCoreEnvironment) : ScriptCompilerProxy {
|
||||
private val nameTables = NameTables(emptyList(), mappedNames = mutableMapOf())
|
||||
private val symbolTable = SymbolTable(IdSignatureDescriptor(JsManglerDesc), IrFactoryImpl)
|
||||
private val dependencies: List<ModuleDescriptor> = readLibrariesFromConfiguration(environment.configuration)
|
||||
private val compiler = JsCoreScriptingCompiler(environment, nameTables, symbolTable, dependencies)
|
||||
private var scriptDependencyCompiler: JsScriptDependencyCompiler? =
|
||||
JsScriptDependencyCompiler(environment.configuration, nameTables, symbolTable)
|
||||
|
||||
override fun compile(
|
||||
script: SourceCode,
|
||||
scriptCompilationConfiguration: ScriptCompilationConfiguration
|
||||
): ResultWithDiagnostics<CompiledScript> {
|
||||
val parentMessageCollector = environment.configuration[CLIConfigurationKeys.MESSAGE_COLLECTOR_KEY]
|
||||
return withMessageCollector(script = script, parentMessageCollector = parentMessageCollector) { messageCollector ->
|
||||
environment.configuration.put(CLIConfigurationKeys.MESSAGE_COLLECTOR_KEY, messageCollector)
|
||||
try {
|
||||
val dependenciesCode = scriptDependencyCompiler?.let { scriptDependencyCompiler = null; it.compile(dependencies) } ?: ""
|
||||
when (val compileResult = compiler.compile(makeReplCodeLine(0, script.text))) {
|
||||
is ReplCompileResult.CompiledClasses -> {
|
||||
val compileJsCode = compileResult.data as String
|
||||
ResultWithDiagnostics.Success(
|
||||
JsCompiledScript(dependenciesCode + "\n" + compileJsCode, scriptCompilationConfiguration)
|
||||
)
|
||||
}
|
||||
is ReplCompileResult.Incomplete -> ResultWithDiagnostics.Failure(
|
||||
ScriptDiagnostic(ScriptDiagnostic.incompleteCode, "Incomplete code")
|
||||
)
|
||||
is ReplCompileResult.Error -> ResultWithDiagnostics.Failure(
|
||||
ScriptDiagnostic(
|
||||
ScriptDiagnostic.unspecifiedError,
|
||||
message = compileResult.message,
|
||||
severity = ScriptDiagnostic.Severity.ERROR
|
||||
)
|
||||
)
|
||||
}
|
||||
} finally {
|
||||
if (parentMessageCollector != null)
|
||||
environment.configuration.put(CLIConfigurationKeys.MESSAGE_COLLECTOR_KEY, parentMessageCollector)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user