[JS SCRIPT] refactor js script infrastructure
- Implement proper script compiler proxy to correctly handle script and its closed-world dependencies - Clean up zoo of JsScriptCompilers
This commit is contained in:
@@ -44,7 +44,7 @@ class JsIrBackendContext(
|
||||
val symbolTable: SymbolTable,
|
||||
irModuleFragment: IrModuleFragment,
|
||||
val additionalExportedDeclarations: Set<FqName>,
|
||||
override val configuration: CompilerConfiguration,
|
||||
override val configuration: CompilerConfiguration, // TODO: remove configuration from backend context
|
||||
override val scriptMode: Boolean = false
|
||||
) : CommonBackendContext {
|
||||
override val transformedFunction = mutableMapOf<IrFunctionSymbol, IrSimpleFunctionSymbol>()
|
||||
|
||||
@@ -86,7 +86,7 @@ fun compile(
|
||||
return transformer.generateModule(moduleFragment)
|
||||
}
|
||||
|
||||
fun compileForRepl(
|
||||
fun generateJsCode(
|
||||
context: JsIrBackendContext,
|
||||
moduleFragment: IrModuleFragment,
|
||||
nameTables: NameTables
|
||||
|
||||
+10
-12
@@ -21,8 +21,7 @@ import org.jetbrains.kotlin.scripting.compiler.plugin.ScriptingCompilerConfigura
|
||||
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.JsReplEvaluator
|
||||
import org.jetbrains.kotlin.scripting.repl.js.ReplMessageCollector
|
||||
import org.jetbrains.kotlin.scripting.repl.js.*
|
||||
import java.io.Closeable
|
||||
import kotlin.script.experimental.api.ScriptCompilationConfiguration
|
||||
import kotlin.script.experimental.api.baseClass
|
||||
@@ -31,22 +30,24 @@ import kotlin.script.experimental.host.ScriptingHostConfiguration
|
||||
import kotlin.script.experimental.jvm.JsDependency
|
||||
|
||||
abstract class AbstractJsReplTest : Closeable {
|
||||
abstract fun createCompiler(): ReplCompiler
|
||||
abstract fun preprocessEvaluation()
|
||||
protected lateinit var compilationState: JsReplCompilationState
|
||||
protected lateinit var evaluationState: JsEvaluationState
|
||||
|
||||
protected abstract fun createCompilationState(): JsReplCompilationState
|
||||
protected abstract fun createEvaluationState(): JsEvaluationState
|
||||
|
||||
fun compile(codeLine: ReplCodeLine): ReplCompileResult {
|
||||
return compiler.compile(compiler.createState(), codeLine)
|
||||
return JsReplCompiler(environment).compile(compilationState, codeLine)
|
||||
}
|
||||
|
||||
fun evaluate(compileResult: ReplCompileResult.CompiledClasses): ReplEvalResult {
|
||||
return jsEvaluator.eval(jsEvaluator.createState(), compileResult)
|
||||
return JsReplEvaluator().eval(evaluationState, compileResult)
|
||||
}
|
||||
|
||||
fun reset() {
|
||||
collector.clear()
|
||||
compiler = createCompiler()
|
||||
jsEvaluator = JsReplEvaluator()
|
||||
preprocessEvaluation()
|
||||
compilationState = createCompilationState()
|
||||
evaluationState = createEvaluationState()
|
||||
}
|
||||
|
||||
private val collector: MessageCollector = ReplMessageCollector()
|
||||
@@ -55,9 +56,6 @@ abstract class AbstractJsReplTest : Closeable {
|
||||
disposable, loadConfiguration(), EnvironmentConfigFiles.JS_CONFIG_FILES
|
||||
)
|
||||
|
||||
lateinit var compiler: ReplCompiler
|
||||
lateinit var jsEvaluator: JsReplEvaluator
|
||||
|
||||
private var snippetId: Int = 1 //index 0 for klib
|
||||
fun newSnippetId(): Int = snippetId++
|
||||
|
||||
|
||||
+18
-17
@@ -5,37 +5,38 @@
|
||||
|
||||
package org.jetbrains.kotlin.scripting.repl.js.test
|
||||
|
||||
import org.jetbrains.kotlin.cli.common.repl.ReplCompiler
|
||||
import org.jetbrains.kotlin.ir.backend.js.utils.NameTables
|
||||
import org.jetbrains.kotlin.ir.util.SymbolTable
|
||||
import org.jetbrains.kotlin.js.engine.ScriptEngineNashorn
|
||||
import org.jetbrains.kotlin.scripting.compiler.plugin.repl.ReplCodeAnalyzer
|
||||
import org.jetbrains.kotlin.scripting.repl.js.*
|
||||
import java.util.concurrent.locks.ReentrantReadWriteLock
|
||||
|
||||
// 1. Compile dependencies
|
||||
// 2. Save them as a binary dependency (name table and js string)
|
||||
// 3. For each new state load dependency's table and js code
|
||||
class JsReplTestAgainstBinaries : AbstractJsReplTest() {
|
||||
private val dependencyLoader = DependencyLoader()
|
||||
|
||||
private val runtimeBinary: String
|
||||
private val nameTable: NameTables
|
||||
private val dependencies = readLibrariesFromConfiguration(environment.configuration)
|
||||
|
||||
init {
|
||||
val dependencies = readLibrariesFromConfiguration(environment.configuration)
|
||||
val compiler = ScriptDependencyCompiler(environment)
|
||||
|
||||
val result = compiler.compile(dependencies)
|
||||
runtimeBinary = result.first
|
||||
nameTable = result.second
|
||||
val nameTable = NameTables(emptyList())
|
||||
val compiler = JsScriptDependencyCompiler(environment.configuration, nameTable, SymbolTable())
|
||||
val runtimeBinary = compiler.compile(dependencies)
|
||||
|
||||
dependencyLoader.saveScriptDependencyBinary(runtimeBinary)
|
||||
dependencyLoader.saveNames(nameTable)
|
||||
}
|
||||
|
||||
override fun createCompiler(): ReplCompiler {
|
||||
return JsDebuggerCompiler(environment, dependencyLoader.loadNames())
|
||||
override fun createCompilationState(): JsReplCompilationState {
|
||||
val replState = ReplCodeAnalyzer.ResettableAnalyzerState()
|
||||
return JsReplCompilationState(ReentrantReadWriteLock(), dependencyLoader.loadNames(), dependencies, replState, SymbolTable())
|
||||
}
|
||||
|
||||
override fun preprocessEvaluation() {
|
||||
jsEvaluator.eval(
|
||||
jsEvaluator.createState(),
|
||||
createCompileResult(dependencyLoader.loadScriptDependencyBinary())
|
||||
)
|
||||
override fun createEvaluationState(): JsEvaluationState {
|
||||
val state = JsEvaluationState(ReentrantReadWriteLock(), ScriptEngineNashorn())
|
||||
JsReplEvaluator().eval(state, createCompileResult(dependencyLoader.loadScriptDependencyBinary()))
|
||||
return state
|
||||
}
|
||||
|
||||
override fun close() {
|
||||
|
||||
+29
-7
@@ -6,21 +6,43 @@
|
||||
package org.jetbrains.kotlin.scripting.repl.js.test
|
||||
|
||||
import com.intellij.openapi.util.Disposer
|
||||
import org.jetbrains.kotlin.cli.common.repl.ReplCompiler
|
||||
import org.jetbrains.kotlin.ir.backend.js.utils.NameTables
|
||||
import org.jetbrains.kotlin.ir.util.SymbolTable
|
||||
import org.jetbrains.kotlin.js.engine.ScriptEngineNashorn
|
||||
import org.jetbrains.kotlin.scripting.compiler.plugin.repl.ReplCodeAnalyzer
|
||||
import org.jetbrains.kotlin.scripting.repl.js.*
|
||||
import java.util.concurrent.locks.ReentrantReadWriteLock
|
||||
|
||||
class JsReplTestAgainstKlib : AbstractJsReplTest() {
|
||||
override fun createCompiler(): ReplCompiler = JsReplCompiler(environment)
|
||||
|
||||
override fun preprocessEvaluation() {
|
||||
val scriptDependencyBinary = (compiler as JsReplCompiler).scriptDependencyBinary
|
||||
private var dependencyCode: String? = null
|
||||
|
||||
jsEvaluator.eval(
|
||||
jsEvaluator.createState(),
|
||||
createCompileResult(scriptDependencyBinary)
|
||||
override fun createCompilationState(): JsReplCompilationState {
|
||||
val nameTables = NameTables(emptyList())
|
||||
val symbolTable = SymbolTable()
|
||||
val dependencyCompiler = JsScriptDependencyCompiler(environment.configuration, nameTables, symbolTable)
|
||||
val dependencies = readLibrariesFromConfiguration(environment.configuration)
|
||||
dependencyCode = dependencyCompiler.compile(dependencies)
|
||||
|
||||
return JsReplCompilationState(
|
||||
ReentrantReadWriteLock(),
|
||||
nameTables,
|
||||
dependencies,
|
||||
ReplCodeAnalyzer.ResettableAnalyzerState(),
|
||||
symbolTable
|
||||
)
|
||||
}
|
||||
|
||||
override fun createEvaluationState(): JsEvaluationState {
|
||||
val state = JsEvaluationState(ReentrantReadWriteLock(), ScriptEngineNashorn())
|
||||
|
||||
JsReplEvaluator().eval(state, createCompileResult(dependencyCode ?: error("Dependencies has to be compiled first")))
|
||||
|
||||
dependencyCode = null
|
||||
|
||||
return state
|
||||
}
|
||||
|
||||
override fun close() {
|
||||
Disposer.dispose(disposable)
|
||||
}
|
||||
|
||||
@@ -7,9 +7,9 @@ jvmTarget = "1.6"
|
||||
|
||||
dependencies {
|
||||
compile(project(":kotlin-scripting-common"))
|
||||
compile(project(":compiler:cli-common"))
|
||||
compile(project(":js:js.engines"))
|
||||
compile(intellijCoreDep()) { includeJars("intellij-core") }
|
||||
compileOnly(project(":compiler:backend.js"))
|
||||
compileOnly(project(":compiler:cli-common"))
|
||||
compileOnly(project(":js:js.engines"))
|
||||
}
|
||||
|
||||
sourceSets {
|
||||
|
||||
+3
-4
@@ -11,9 +11,7 @@ import java.util.concurrent.locks.ReentrantReadWriteLock
|
||||
|
||||
class JsReplEvaluator : ReplEvaluator {
|
||||
//TODO: support println()
|
||||
private val engine = ScriptEngineNashorn()
|
||||
|
||||
override fun createState(lock: ReentrantReadWriteLock): IReplStageState<*> = JsState(lock)
|
||||
override fun createState(lock: ReentrantReadWriteLock): IReplStageState<*> = JsEvaluationState(lock, ScriptEngineNashorn())
|
||||
|
||||
override fun eval(
|
||||
state: IReplStageState<*>,
|
||||
@@ -22,7 +20,8 @@ class JsReplEvaluator : ReplEvaluator {
|
||||
invokeWrapper: InvokeWrapper?
|
||||
): ReplEvalResult {
|
||||
return try {
|
||||
val evalResult = engine.eval<Any?>(compileResult.data as String)
|
||||
val evaluationState = state.asState(JsEvaluationState::class.java)
|
||||
val evalResult = evaluationState.engine.eval<Any?>(compileResult.data as String)
|
||||
ReplEvalResult.ValueResult("result", evalResult, "Any?")
|
||||
} catch (e: Exception) {
|
||||
ReplEvalResult.Error.Runtime("Error while evaluating", e)
|
||||
|
||||
@@ -6,7 +6,10 @@
|
||||
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.js.engine.ScriptEngine
|
||||
import java.util.concurrent.locks.ReentrantReadWriteLock
|
||||
import kotlin.reflect.KClass
|
||||
import kotlin.script.experimental.api.CompiledScript
|
||||
@@ -14,7 +17,7 @@ import kotlin.script.experimental.api.ResultWithDiagnostics
|
||||
import kotlin.script.experimental.api.ScriptCompilationConfiguration
|
||||
import kotlin.script.experimental.api.ScriptEvaluationConfiguration
|
||||
|
||||
class JsState(override val lock: ReentrantReadWriteLock) : IReplStageState<ScriptDescriptor> {
|
||||
abstract class JsState(override val lock: ReentrantReadWriteLock) : IReplStageState<ScriptDescriptor> {
|
||||
override val history: IReplStageHistory<ScriptDescriptor>
|
||||
get() = TODO("not implemented")
|
||||
|
||||
@@ -23,7 +26,18 @@ class JsState(override val lock: ReentrantReadWriteLock) : IReplStageState<Scrip
|
||||
|
||||
}
|
||||
|
||||
class CompiledToJsScript(
|
||||
abstract class JsCompilationState(
|
||||
lock: ReentrantReadWriteLock,
|
||||
val nameTables: NameTables,
|
||||
val dependencies: List<ModuleDescriptor>) : JsState(lock)
|
||||
|
||||
class JsEvaluationState(lock: ReentrantReadWriteLock, val engine: ScriptEngine) : JsState(lock) {
|
||||
override fun dispose() {
|
||||
engine.release()
|
||||
}
|
||||
}
|
||||
|
||||
class JsCompiledScript(
|
||||
val jsCode: String,
|
||||
override val compilationConfiguration: ScriptCompilationConfiguration
|
||||
) : CompiledScript<Any> {
|
||||
|
||||
+1
-1
@@ -17,7 +17,7 @@ class JsScriptEvaluator : ScriptEvaluator {
|
||||
scriptEvaluationConfiguration: ScriptEvaluationConfiguration
|
||||
): ResultWithDiagnostics<EvaluationResult> {
|
||||
return try {
|
||||
val evalResult = engine.eval<Any?>((compiledScript as CompiledToJsScript).jsCode)
|
||||
val evalResult = engine.eval<Any?>((compiledScript as JsCompiledScript).jsCode)
|
||||
ResultWithDiagnostics.Success(
|
||||
EvaluationResult(
|
||||
ResultValue.Value(
|
||||
|
||||
+3
-3
@@ -7,7 +7,7 @@
|
||||
|
||||
package kotlin.script.experimental.jvmhost
|
||||
|
||||
import org.jetbrains.kotlin.scripting.compiler.plugin.ScriptJvmCompilerProxy
|
||||
import org.jetbrains.kotlin.scripting.compiler.plugin.ScriptCompilerProxy
|
||||
import org.jetbrains.kotlin.scripting.compiler.plugin.impl.ScriptJvmCompilerIsolated
|
||||
import kotlin.script.experimental.api.*
|
||||
import kotlin.script.experimental.host.ScriptingHostConfiguration
|
||||
@@ -16,12 +16,12 @@ import kotlin.script.experimental.jvm.defaultJvmScriptingHostConfiguration
|
||||
|
||||
open class JvmScriptCompiler(
|
||||
baseHostConfiguration: ScriptingHostConfiguration = defaultJvmScriptingHostConfiguration,
|
||||
compilerProxy: ScriptJvmCompilerProxy? = null
|
||||
compilerProxy: ScriptCompilerProxy? = null
|
||||
) : ScriptCompiler {
|
||||
|
||||
val hostConfiguration = baseHostConfiguration.withDefaultsFrom(defaultJvmScriptingHostConfiguration)
|
||||
|
||||
val compilerProxy: ScriptJvmCompilerProxy = compilerProxy ?: ScriptJvmCompilerIsolated(hostConfiguration)
|
||||
val compilerProxy: ScriptCompilerProxy = compilerProxy ?: ScriptJvmCompilerIsolated(hostConfiguration)
|
||||
|
||||
override suspend operator fun invoke(
|
||||
script: SourceCode,
|
||||
|
||||
+4
-14
@@ -31,12 +31,7 @@ abstract class AbstractScriptEvaluationExtension : ScriptEvaluationExtension {
|
||||
): KotlinCoreEnvironment
|
||||
|
||||
abstract fun createScriptEvaluator(): ScriptEvaluator
|
||||
|
||||
abstract suspend fun compilerInvoke(
|
||||
environment: KotlinCoreEnvironment,
|
||||
script: SourceCode,
|
||||
scriptCompilationConfiguration: ScriptCompilationConfiguration
|
||||
): ResultWithDiagnostics<CompiledScript<*>>
|
||||
abstract fun createScriptCompiler(environment: KotlinCoreEnvironment): ScriptCompilerProxy
|
||||
|
||||
protected abstract fun ScriptEvaluationConfiguration.Builder.platformEvaluationConfiguration()
|
||||
|
||||
@@ -82,22 +77,17 @@ abstract class AbstractScriptEvaluationExtension : ScriptEvaluationExtension {
|
||||
|
||||
}
|
||||
val scriptCompilationConfiguration = definition.compilationConfiguration
|
||||
|
||||
val scriptEvaluator = createScriptEvaluator()
|
||||
val scriptCompiler = createScriptCompiler(environment)
|
||||
|
||||
return runBlocking {
|
||||
val compiledScript = compilerInvoke(
|
||||
environment,
|
||||
script,
|
||||
scriptCompilationConfiguration
|
||||
).valueOr {
|
||||
val compiledScript = scriptCompiler.compile(script, scriptCompilationConfiguration).valueOr {
|
||||
for (report in it.reports) {
|
||||
messageCollector.report(report.severity.toCompilerMessageSeverity(), report.render(withSeverity = false))
|
||||
}
|
||||
return@runBlocking ExitCode.COMPILATION_ERROR
|
||||
}
|
||||
|
||||
val evalResult = scriptEvaluator.invoke(compiledScript, evaluationConfiguration).valueOr {
|
||||
val evalResult = createScriptEvaluator().invoke(compiledScript, evaluationConfiguration).valueOr {
|
||||
for (report in it.reports) {
|
||||
messageCollector.report(report.severity.toCompilerMessageSeverity(), report.render(withSeverity = false))
|
||||
}
|
||||
|
||||
+15
-33
@@ -6,22 +6,28 @@
|
||||
package org.jetbrains.kotlin.scripting.compiler.plugin
|
||||
|
||||
import com.intellij.core.JavaCoreProjectEnvironment
|
||||
import org.jetbrains.kotlin.cli.common.CLIConfigurationKeys
|
||||
import org.jetbrains.kotlin.cli.common.arguments.CommonCompilerArguments
|
||||
import org.jetbrains.kotlin.cli.common.arguments.K2JSCompilerArguments
|
||||
import org.jetbrains.kotlin.cli.common.repl.ReplCompileResult
|
||||
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.descriptors.ModuleDescriptor
|
||||
import org.jetbrains.kotlin.ir.backend.js.utils.NameTables
|
||||
import org.jetbrains.kotlin.ir.util.SymbolTable
|
||||
import org.jetbrains.kotlin.scripting.compiler.plugin.impl.JsScriptCompilerWithDependenciesProxy
|
||||
import org.jetbrains.kotlin.scripting.compiler.plugin.impl.withMessageCollector
|
||||
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.CompiledToJsScript
|
||||
import org.jetbrains.kotlin.scripting.repl.js.JsScriptCompiler
|
||||
import org.jetbrains.kotlin.scripting.repl.js.JsScriptDependencyCompiler
|
||||
import org.jetbrains.kotlin.scripting.repl.js.JsScriptEvaluator
|
||||
import org.jetbrains.kotlin.scripting.repl.js.*
|
||||
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")
|
||||
@@ -55,37 +61,13 @@ class JsScriptEvaluationExtension : AbstractScriptEvaluationExtension() {
|
||||
return JsScriptEvaluator()
|
||||
}
|
||||
|
||||
private var environment: KotlinCoreEnvironment? = null
|
||||
private var dependencyJsCode: String? = null
|
||||
private val scriptCompiler: JsScriptCompiler by lazy {
|
||||
val env = environment ?: error("Expected environment is initialized prior to compiler instantiation")
|
||||
JsScriptCompiler(env).apply {
|
||||
dependencyJsCode = JsScriptDependencyCompiler(env.configuration, nameTables, symbolTable).compile(dependencies)
|
||||
}
|
||||
private var scriptCompilerProxy: ScriptCompilerProxy? = null
|
||||
|
||||
override fun createScriptCompiler(environment: KotlinCoreEnvironment): ScriptCompilerProxy {
|
||||
return scriptCompilerProxy ?: JsScriptCompilerWithDependenciesProxy(environment).also { scriptCompilerProxy = it }
|
||||
}
|
||||
|
||||
override suspend fun compilerInvoke(
|
||||
environment: KotlinCoreEnvironment,
|
||||
script: SourceCode,
|
||||
scriptCompilationConfiguration: ScriptCompilationConfiguration
|
||||
): ResultWithDiagnostics<CompiledScript<*>> {
|
||||
|
||||
this.environment = environment
|
||||
|
||||
return scriptCompiler.invoke(script, scriptCompilationConfiguration).onSuccess {
|
||||
val compiledResult = it as CompiledToJsScript
|
||||
val actualResult = dependencyJsCode?.let { d ->
|
||||
dependencyJsCode = null
|
||||
CompiledToJsScript(d + "\n" + compiledResult.jsCode, compiledResult.compilationConfiguration)
|
||||
} ?: compiledResult
|
||||
|
||||
ResultWithDiagnostics.Success(actualResult)
|
||||
}
|
||||
}
|
||||
|
||||
override fun ScriptEvaluationConfiguration.Builder.platformEvaluationConfiguration() {
|
||||
|
||||
}
|
||||
override fun ScriptEvaluationConfiguration.Builder.platformEvaluationConfiguration() {}
|
||||
|
||||
override fun isAccepted(arguments: CommonCompilerArguments): Boolean {
|
||||
return arguments is K2JSCompilerArguments
|
||||
|
||||
+2
-12
@@ -43,18 +43,8 @@ class JvmCliScriptEvaluationExtension : AbstractScriptEvaluationExtension() {
|
||||
return BasicJvmScriptEvaluator()
|
||||
}
|
||||
|
||||
private var environment: KotlinCoreEnvironment? = null
|
||||
private val scriptCompiler: ScriptJvmCompilerFromEnvironment by lazy {
|
||||
ScriptJvmCompilerFromEnvironment(environment!!)
|
||||
}
|
||||
|
||||
override suspend fun compilerInvoke(
|
||||
environment: KotlinCoreEnvironment,
|
||||
script: SourceCode,
|
||||
scriptCompilationConfiguration: ScriptCompilationConfiguration
|
||||
): ResultWithDiagnostics<CompiledScript<*>> {
|
||||
this.environment = environment
|
||||
return scriptCompiler.compile(script, scriptCompilationConfiguration)
|
||||
override fun createScriptCompiler(environment: KotlinCoreEnvironment): ScriptCompilerProxy {
|
||||
return ScriptJvmCompilerFromEnvironment(environment)
|
||||
}
|
||||
|
||||
override fun isAccepted(arguments: CommonCompilerArguments): Boolean =
|
||||
|
||||
+1
-1
@@ -10,7 +10,7 @@ import kotlin.script.experimental.api.ResultWithDiagnostics
|
||||
import kotlin.script.experimental.api.ScriptCompilationConfiguration
|
||||
import kotlin.script.experimental.api.SourceCode
|
||||
|
||||
interface ScriptJvmCompilerProxy {
|
||||
interface ScriptCompilerProxy {
|
||||
fun compile(
|
||||
script: SourceCode,
|
||||
scriptCompilationConfiguration: ScriptCompilationConfiguration
|
||||
+79
@@ -0,0 +1,79 @@
|
||||
/*
|
||||
* 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.compiler.plugin.impl
|
||||
|
||||
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.ExpectActualTracker
|
||||
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.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 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,
|
||||
additionalPackages
|
||||
)
|
||||
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)
|
||||
}
|
||||
}
|
||||
+61
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
* 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.compiler.plugin.impl
|
||||
|
||||
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.utils.NameTables
|
||||
import org.jetbrains.kotlin.ir.util.SymbolTable
|
||||
import org.jetbrains.kotlin.scripting.compiler.plugin.ScriptCompilerProxy
|
||||
import org.jetbrains.kotlin.scripting.repl.js.JsCompiledScript
|
||||
import org.jetbrains.kotlin.scripting.repl.js.JsCoreScriptingCompiler
|
||||
import org.jetbrains.kotlin.scripting.repl.js.JsScriptDependencyCompiler
|
||||
import org.jetbrains.kotlin.scripting.repl.js.readLibrariesFromConfiguration
|
||||
import kotlin.script.experimental.api.*
|
||||
|
||||
class JsScriptCompilerWithDependenciesProxy(private val environment: KotlinCoreEnvironment) : ScriptCompilerProxy {
|
||||
private val nameTables = NameTables(emptyList())
|
||||
private val symbolTable = SymbolTable()
|
||||
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(org.jetbrains.kotlin.scripting.repl.js.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("Incomplete code")
|
||||
)
|
||||
is ReplCompileResult.Error -> ResultWithDiagnostics.Failure(
|
||||
ScriptDiagnostic(
|
||||
message = compileResult.message,
|
||||
severity = ScriptDiagnostic.Severity.ERROR
|
||||
)
|
||||
)
|
||||
}
|
||||
} finally {
|
||||
if (parentMessageCollector != null)
|
||||
environment.configuration.put(CLIConfigurationKeys.MESSAGE_COLLECTOR_KEY, parentMessageCollector)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+3
-3
@@ -19,7 +19,7 @@ import org.jetbrains.kotlin.config.CompilerConfiguration
|
||||
import org.jetbrains.kotlin.config.languageVersionSettings
|
||||
import org.jetbrains.kotlin.psi.KtFile
|
||||
import org.jetbrains.kotlin.resolve.jvm.extensions.PackageFragmentProviderExtension
|
||||
import org.jetbrains.kotlin.scripting.compiler.plugin.ScriptJvmCompilerProxy
|
||||
import org.jetbrains.kotlin.scripting.compiler.plugin.ScriptCompilerProxy
|
||||
import org.jetbrains.kotlin.scripting.compiler.plugin.dependencies.ScriptsCompilationDependencies
|
||||
import org.jetbrains.kotlin.scripting.definitions.ScriptDependenciesProvider
|
||||
import kotlin.script.experimental.api.*
|
||||
@@ -30,7 +30,7 @@ import kotlin.script.experimental.jvm.compilationCache
|
||||
import kotlin.script.experimental.jvm.impl.KJvmCompiledScript
|
||||
import kotlin.script.experimental.jvm.jvm
|
||||
|
||||
class ScriptJvmCompilerIsolated(val hostConfiguration: ScriptingHostConfiguration) : ScriptJvmCompilerProxy {
|
||||
class ScriptJvmCompilerIsolated(val hostConfiguration: ScriptingHostConfiguration) : ScriptCompilerProxy {
|
||||
|
||||
override fun compile(
|
||||
script: SourceCode,
|
||||
@@ -50,7 +50,7 @@ class ScriptJvmCompilerIsolated(val hostConfiguration: ScriptingHostConfiguratio
|
||||
}
|
||||
}
|
||||
|
||||
class ScriptJvmCompilerFromEnvironment(val environment: KotlinCoreEnvironment) : ScriptJvmCompilerProxy {
|
||||
class ScriptJvmCompilerFromEnvironment(val environment: KotlinCoreEnvironment) : ScriptCompilerProxy {
|
||||
|
||||
override fun compile(
|
||||
script: SourceCode,
|
||||
|
||||
+22
-49
@@ -9,40 +9,36 @@ 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.*
|
||||
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.*
|
||||
import org.jetbrains.kotlin.ir.backend.js.JsIrBackendContext
|
||||
import org.jetbrains.kotlin.ir.backend.js.generateJsCode
|
||||
import org.jetbrains.kotlin.ir.backend.js.generateModuleFragment
|
||||
import org.jetbrains.kotlin.ir.backend.js.utils.NameTables
|
||||
import org.jetbrains.kotlin.ir.declarations.IrModuleFragment
|
||||
import org.jetbrains.kotlin.ir.descriptors.IrBuiltIns
|
||||
import org.jetbrains.kotlin.ir.util.ExternalDependenciesGenerator
|
||||
import org.jetbrains.kotlin.ir.util.IrDeserializer
|
||||
import org.jetbrains.kotlin.ir.util.SymbolTable
|
||||
import org.jetbrains.kotlin.js.config.JSConfigurationKeys
|
||||
import org.jetbrains.kotlin.psi2ir.Psi2IrTranslator
|
||||
import org.jetbrains.kotlin.scripting.compiler.plugin.repl.ReplCodeAnalyzer
|
||||
import org.jetbrains.kotlin.serialization.js.ModuleKind
|
||||
import kotlin.script.experimental.api.valueOr
|
||||
import kotlin.script.experimental.host.StringScriptSource
|
||||
|
||||
class DeserializerWithDependencies(val deserializer: IrDeserializer, val dependencies: List<IrModuleFragment>)
|
||||
|
||||
class CoreScriptingJsCompiler(
|
||||
class JsCoreScriptingCompiler(
|
||||
private val environment: KotlinCoreEnvironment,
|
||||
private val nameTables: NameTables,
|
||||
private val symbolTable: SymbolTable,
|
||||
private val dependencyDescriptors: List<ModuleDescriptor>,
|
||||
private val createDeserializer: (ModuleDescriptor, SymbolTable, IrBuiltIns) -> DeserializerWithDependencies? = { _, _, _ -> null }
|
||||
private val replState: ReplCodeAnalyzer.ResettableAnalyzerState = ReplCodeAnalyzer.ResettableAnalyzerState()
|
||||
) {
|
||||
private val analyzerEngine: JsReplCodeAnalyzer = JsReplCodeAnalyzer(environment.project, dependencyDescriptors)
|
||||
private val symbolTable: SymbolTable = SymbolTable()
|
||||
|
||||
fun compile(codeLine: ReplCodeLine): ReplCompileResult {
|
||||
val snippet = codeLine.code
|
||||
val snippetId = codeLine.no
|
||||
|
||||
val messageCollector = environment.configuration[CLIConfigurationKeys.MESSAGE_COLLECTOR_KEY] as MessageCollector
|
||||
|
||||
setIdeaIoUseFallback()
|
||||
|
||||
val sourceCode = StringScriptSource(snippet, "line-$snippetId.kts")
|
||||
@@ -52,28 +48,20 @@ class CoreScriptingJsCompiler(
|
||||
environment.project
|
||||
).valueOr { return ReplCompileResult.Error(it.reports.joinToString { r -> r.message }) }
|
||||
|
||||
analyzerEngine.analyzeReplLine(snippetKtFile, codeLine).also {
|
||||
AnalyzerWithCompilerReport.reportDiagnostics(it, messageCollector)
|
||||
val messageCollector = environment.configuration[CLIConfigurationKeys.MESSAGE_COLLECTOR_KEY] as MessageCollector
|
||||
val analyzerEngine = JsReplCodeAnalyzer(environment, dependencyDescriptors, replState)
|
||||
val analysisResult = analyzerEngine.analyzeReplLine(snippetKtFile, codeLine).also {
|
||||
AnalyzerWithCompilerReport.reportDiagnostics(it.bindingContext.diagnostics, messageCollector)
|
||||
if (messageCollector.hasErrors()) return ReplCompileResult.Error("Error while analysis")
|
||||
}
|
||||
|
||||
val module = analysisResult.moduleDescriptor
|
||||
val bindingContext = analysisResult.bindingContext
|
||||
|
||||
val psi2ir = Psi2IrTranslator(environment.configuration.languageVersionSettings)
|
||||
val psi2irContext = psi2ir.createGeneratorContext(
|
||||
analyzerEngine.context.module,
|
||||
analyzerEngine.trace.bindingContext,
|
||||
symbolTable
|
||||
)
|
||||
|
||||
val deserializerWithDependencies = createDeserializer(psi2irContext.moduleDescriptor, symbolTable, psi2irContext.irBuiltIns)
|
||||
|
||||
val irModuleFragment = psi2irContext.generateModuleFragment(listOf(snippetKtFile), deserializerWithDependencies?.deserializer)
|
||||
|
||||
val deserializedFragments = deserializerWithDependencies?.dependencies ?: emptyList()
|
||||
|
||||
val irFiles = sortDependencies(deserializedFragments).flatMap { it.files } + irModuleFragment.files
|
||||
irModuleFragment.files.clear()
|
||||
irModuleFragment.files += irFiles
|
||||
val psi2irContext = psi2ir.createGeneratorContext(module, bindingContext, symbolTable)
|
||||
|
||||
val irModuleFragment = psi2irContext.generateModuleFragment(listOf(snippetKtFile))
|
||||
|
||||
val context = JsIrBackendContext(
|
||||
irModuleFragment.descriptor,
|
||||
@@ -88,28 +76,13 @@ class CoreScriptingJsCompiler(
|
||||
ExternalDependenciesGenerator(
|
||||
irModuleFragment.descriptor,
|
||||
psi2irContext.symbolTable,
|
||||
psi2irContext.irBuiltIns,
|
||||
deserializer = deserializerWithDependencies?.deserializer
|
||||
psi2irContext.irBuiltIns
|
||||
).generateUnboundSymbolsAsDependencies()
|
||||
|
||||
with(context.implicitDeclarationFile) {
|
||||
if (!irModuleFragment.files.contains(this)) {
|
||||
irModuleFragment.files += this
|
||||
}
|
||||
}
|
||||
context.implicitDeclarationFile.declarations.clear()
|
||||
|
||||
environment.configuration.put(JSConfigurationKeys.MODULE_KIND, ModuleKind.PLAIN)
|
||||
|
||||
val code = compileForRepl(
|
||||
context,
|
||||
irModuleFragment,
|
||||
nameTables
|
||||
)
|
||||
val code = generateJsCode(context, irModuleFragment, nameTables)
|
||||
|
||||
return createCompileResult(
|
||||
LineId(codeLine),
|
||||
code
|
||||
)
|
||||
return createCompileResult(LineId(codeLine), code)
|
||||
}
|
||||
}
|
||||
-35
@@ -1,35 +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.repl.js
|
||||
|
||||
import org.jetbrains.kotlin.cli.common.repl.*
|
||||
import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment
|
||||
import org.jetbrains.kotlin.ir.backend.js.utils.NameTables
|
||||
import java.util.concurrent.locks.ReentrantReadWriteLock
|
||||
|
||||
class JsDebuggerCompiler(
|
||||
environment: KotlinCoreEnvironment,
|
||||
loadNames: NameTables
|
||||
) : ReplCompiler {
|
||||
// TODO: configure dependencies
|
||||
private val compiler = CoreScriptingJsCompiler(
|
||||
environment,
|
||||
loadNames,
|
||||
readLibrariesFromConfiguration(environment.configuration)
|
||||
)
|
||||
|
||||
override fun createState(lock: ReentrantReadWriteLock): IReplStageState<*> {
|
||||
return JsState(lock)
|
||||
}
|
||||
|
||||
override fun check(state: IReplStageState<*>, codeLine: ReplCodeLine): ReplCheckResult {
|
||||
return ReplCheckResult.Ok()
|
||||
}
|
||||
|
||||
override fun compile(state: IReplStageState<*>, codeLine: ReplCodeLine): ReplCompileResult {
|
||||
return compiler.compile(codeLine)
|
||||
}
|
||||
}
|
||||
+15
-64
@@ -5,82 +5,33 @@
|
||||
|
||||
package org.jetbrains.kotlin.scripting.repl.js
|
||||
|
||||
import com.intellij.openapi.project.Project
|
||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||
import org.jetbrains.kotlin.analyzer.AnalysisResult
|
||||
import org.jetbrains.kotlin.cli.common.repl.ReplCodeLine
|
||||
import org.jetbrains.kotlin.cli.jvm.compiler.NoScopeRecordCliBindingTrace
|
||||
import org.jetbrains.kotlin.config.LanguageVersionSettingsImpl
|
||||
import org.jetbrains.kotlin.context.ContextForNewModule
|
||||
import org.jetbrains.kotlin.context.MutableModuleContext
|
||||
import org.jetbrains.kotlin.context.ProjectContext
|
||||
import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment
|
||||
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.ExpectActualTracker
|
||||
import org.jetbrains.kotlin.incremental.components.LookupTracker
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.psi.KtFile
|
||||
import org.jetbrains.kotlin.resolve.BindingTraceContext
|
||||
import org.jetbrains.kotlin.resolve.LazyTopDownAnalyzer
|
||||
import org.jetbrains.kotlin.resolve.TopDownAnalysisMode
|
||||
import org.jetbrains.kotlin.resolve.diagnostics.Diagnostics
|
||||
import org.jetbrains.kotlin.resolve.lazy.declarations.FileBasedDeclarationProviderFactory
|
||||
import org.jetbrains.kotlin.scripting.compiler.plugin.impl.AbstractJsScriptlikeCodeAnalyser
|
||||
import org.jetbrains.kotlin.scripting.compiler.plugin.repl.ReplCodeAnalyzer
|
||||
import org.jetbrains.kotlin.scripting.definitions.ScriptPriorities
|
||||
|
||||
class JsReplCodeAnalyzer(private val project: Project, private val dependencies: List<ModuleDescriptor>) {
|
||||
|
||||
private val replState = ReplCodeAnalyzer.ResettableAnalyzerState()
|
||||
val trace: BindingTraceContext = NoScopeRecordCliBindingTrace()
|
||||
|
||||
private val builtIns: KotlinBuiltIns = dependencies.single { it.allDependencyModules.isEmpty() }.builtIns
|
||||
lateinit var context: MutableModuleContext
|
||||
private fun createTopDownAnalyzerJS(files: Collection<KtFile>): LazyTopDownAnalyzer {
|
||||
context = ContextForNewModule(
|
||||
ProjectContext(project, "TopDownAnalyzer for JS"),
|
||||
Name.special("<script>"),
|
||||
builtIns,
|
||||
platform = null
|
||||
)
|
||||
|
||||
val languageVersionSettings = LanguageVersionSettingsImpl.DEFAULT
|
||||
val lookupTracker = LookupTracker.DO_NOTHING
|
||||
val expectActualTracker = ExpectActualTracker.DoNothing
|
||||
val additionalPackages = mutableListOf<PackageFragmentProvider>()
|
||||
|
||||
context.module.setDependencies(dependencies.map { it as ModuleDescriptorImpl } + context.module)
|
||||
|
||||
return createTopDownAnalyzerForJs(
|
||||
context, trace,
|
||||
FileBasedDeclarationProviderFactory(context.storageManager, files),
|
||||
languageVersionSettings,
|
||||
lookupTracker,
|
||||
expectActualTracker,
|
||||
additionalPackages
|
||||
)
|
||||
}
|
||||
|
||||
fun analyzeReplLine(linePsi: KtFile, codeLine: ReplCodeLine): Diagnostics {
|
||||
trace.clearDiagnostics()
|
||||
class JsReplCodeAnalyzer(
|
||||
environment: KotlinCoreEnvironment,
|
||||
dependencies: List<ModuleDescriptor>,
|
||||
private val replState: ReplCodeAnalyzer.ResettableAnalyzerState
|
||||
) : AbstractJsScriptlikeCodeAnalyser(environment, dependencies) {
|
||||
|
||||
fun analyzeReplLine(linePsi: KtFile, codeLine: ReplCodeLine): AnalysisResult {
|
||||
linePsi.script!!.putUserData(ScriptPriorities.PRIORITY_KEY, codeLine.no)
|
||||
|
||||
replState.submitLine(linePsi, codeLine)
|
||||
|
||||
val analyzer = createTopDownAnalyzerJS(listOf(linePsi))
|
||||
val context = analyzer.analyzeDeclarations(TopDownAnalysisMode.TopLevelDeclarations, listOf(linePsi))
|
||||
val result = analysisImpl(linePsi)
|
||||
|
||||
val diagnostics = trace.bindingContext.diagnostics
|
||||
val hasErrors = diagnostics.any { it.severity == Severity.ERROR }
|
||||
|
||||
if (hasErrors) {
|
||||
replState.lineFailure(linePsi, codeLine)
|
||||
return if (result.isSuccess) {
|
||||
replState.lineSuccess(linePsi, codeLine, result.script)
|
||||
AnalysisResult.success(result.bindingContext, result.moduleDescriptor)
|
||||
} else {
|
||||
val scriptDescriptor = context.scripts[linePsi.script]!!
|
||||
replState.lineSuccess(linePsi, codeLine, scriptDescriptor)
|
||||
replState.lineFailure(linePsi, codeLine)
|
||||
AnalysisResult.compilationError(result.bindingContext)
|
||||
}
|
||||
return diagnostics
|
||||
}
|
||||
}
|
||||
|
||||
+19
-11
@@ -7,21 +7,22 @@ package org.jetbrains.kotlin.scripting.repl.js
|
||||
|
||||
import org.jetbrains.kotlin.cli.common.repl.*
|
||||
import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment
|
||||
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
|
||||
import org.jetbrains.kotlin.ir.backend.js.utils.NameTables
|
||||
import org.jetbrains.kotlin.ir.util.SymbolTable
|
||||
import org.jetbrains.kotlin.scripting.compiler.plugin.repl.ReplCodeAnalyzer
|
||||
import java.util.concurrent.locks.ReentrantReadWriteLock
|
||||
|
||||
class JsReplCompiler(
|
||||
environment: KotlinCoreEnvironment
|
||||
) : ReplCompiler {
|
||||
private val nameTables: NameTables = NameTables(emptyList())
|
||||
private val dependencies: List<ModuleDescriptor> = readLibrariesFromConfiguration(environment.configuration)
|
||||
|
||||
val scriptDependencyBinary = ScriptDependencyCompiler(environment, nameTables).compile(dependencies).first
|
||||
private val compiler = CoreScriptingJsCompiler(environment, nameTables, dependencies)
|
||||
// Used to compile REPL code lines
|
||||
class JsReplCompiler(private val environment: KotlinCoreEnvironment) : ReplCompiler {
|
||||
|
||||
override fun createState(lock: ReentrantReadWriteLock): IReplStageState<*> {
|
||||
return JsState(lock)
|
||||
return JsReplCompilationState(
|
||||
lock,
|
||||
NameTables(emptyList()),
|
||||
readLibrariesFromConfiguration(environment.configuration),
|
||||
ReplCodeAnalyzer.ResettableAnalyzerState(),
|
||||
SymbolTable()
|
||||
)
|
||||
}
|
||||
|
||||
override fun check(state: IReplStageState<*>, codeLine: ReplCodeLine): ReplCheckResult {
|
||||
@@ -29,6 +30,13 @@ class JsReplCompiler(
|
||||
}
|
||||
|
||||
override fun compile(state: IReplStageState<*>, codeLine: ReplCodeLine): ReplCompileResult {
|
||||
return compiler.compile(codeLine)
|
||||
val compilationState = state.asState(JsReplCompilationState::class.java)
|
||||
return JsCoreScriptingCompiler(
|
||||
environment,
|
||||
compilationState.nameTables,
|
||||
compilationState.symbolTable,
|
||||
compilationState.dependencies,
|
||||
compilationState.replState
|
||||
).compile(codeLine)
|
||||
}
|
||||
}
|
||||
|
||||
+12
@@ -18,13 +18,16 @@ import org.jetbrains.kotlin.idea.KotlinLanguage
|
||||
import org.jetbrains.kotlin.ir.backend.js.loadKlib
|
||||
import org.jetbrains.kotlin.ir.backend.js.getModuleDescriptorByLibrary
|
||||
import org.jetbrains.kotlin.ir.backend.js.utils.NameTables
|
||||
import org.jetbrains.kotlin.ir.util.SymbolTable
|
||||
import org.jetbrains.kotlin.psi.KtFile
|
||||
import org.jetbrains.kotlin.psi.KtScript
|
||||
import org.jetbrains.kotlin.scripting.compiler.plugin.repl.ReplCodeAnalyzer
|
||||
import org.jetbrains.kotlin.scripting.configuration.ScriptingConfigurationKeys
|
||||
import org.jetbrains.kotlin.scripting.resolve.ScriptLightVirtualFile
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstanceOrNull
|
||||
import java.io.*
|
||||
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
|
||||
@@ -180,3 +183,12 @@ class DependencyLoader {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class JsReplCompilationState(
|
||||
lock: ReentrantReadWriteLock,
|
||||
nameTables: NameTables,
|
||||
dependencies: List<ModuleDescriptor>,
|
||||
val replState: ReplCodeAnalyzer.ResettableAnalyzerState,
|
||||
val symbolTable: SymbolTable
|
||||
) : JsCompilationState(lock, nameTables, dependencies)
|
||||
|
||||
|
||||
-43
@@ -1,43 +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.repl.js
|
||||
|
||||
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.utils.NameTables
|
||||
import kotlin.script.experimental.api.*
|
||||
|
||||
class JsScriptCompiler(
|
||||
environment: KotlinCoreEnvironment
|
||||
) : ScriptCompiler {
|
||||
private val nameTables = NameTables(emptyList())
|
||||
private val dependencies: List<ModuleDescriptor> = readLibrariesFromConfiguration(environment.configuration)
|
||||
private val compiler = CoreScriptingJsCompiler(environment, nameTables, dependencies)
|
||||
|
||||
val scriptDependencyBinary = ScriptDependencyCompiler(environment, nameTables).compile(dependencies).first
|
||||
|
||||
override suspend fun invoke(
|
||||
script: SourceCode,
|
||||
scriptCompilationConfiguration: ScriptCompilationConfiguration
|
||||
): ResultWithDiagnostics<CompiledScript<*>> {
|
||||
val compileResult = compiler.compile(makeReplCodeLine(0, script.text))
|
||||
return when (compileResult) {
|
||||
is CompiledClasses -> ResultWithDiagnostics.Success(
|
||||
CompiledToJsScript(compileResult.data as String, scriptCompilationConfiguration)
|
||||
)
|
||||
is Incomplete -> ResultWithDiagnostics.Failure(
|
||||
ScriptDiagnostic("Incomplete code")
|
||||
)
|
||||
is Error -> ResultWithDiagnostics.Failure(
|
||||
ScriptDiagnostic(
|
||||
message = compileResult.message,
|
||||
severity = ScriptDiagnostic.Severity.ERROR
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
+86
@@ -0,0 +1,86 @@
|
||||
/*
|
||||
* 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.repl.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.ir.backend.js.JsIrBackendContext
|
||||
import org.jetbrains.kotlin.ir.backend.js.generateJsCode
|
||||
import org.jetbrains.kotlin.ir.backend.js.emptyLoggingContext
|
||||
import org.jetbrains.kotlin.ir.backend.js.lower.serialization.ir.JsIrLinker
|
||||
import org.jetbrains.kotlin.ir.backend.js.lower.serialization.ir.JsMangler
|
||||
import org.jetbrains.kotlin.ir.backend.js.utils.NameTables
|
||||
import org.jetbrains.kotlin.ir.declarations.impl.IrModuleFragmentImpl
|
||||
import org.jetbrains.kotlin.ir.descriptors.IrBuiltIns
|
||||
import org.jetbrains.kotlin.ir.util.*
|
||||
import org.jetbrains.kotlin.js.config.JSConfigurationKeys
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.serialization.js.ModuleKind
|
||||
import org.jetbrains.kotlin.storage.LockBasedStorageManager
|
||||
|
||||
// Transforms klib into js code in script-friendly way
|
||||
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 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 = TypeTranslator(symbolTable, languageVersionSettings, moduleDescriptor.builtIns).also {
|
||||
it.constantValueGenerator = ConstantValueGenerator(moduleDescriptor, symbolTable)
|
||||
}
|
||||
|
||||
val irBuiltIns = IrBuiltIns(builtIns, typeTranslator, symbolTable)
|
||||
val jsLinker = JsIrLinker(moduleDescriptor, JsMangler, emptyLoggingContext, irBuiltIns, symbolTable)
|
||||
|
||||
val moduleFragment = IrModuleFragmentImpl(moduleDescriptor, irBuiltIns)
|
||||
val irDependencies = dependencies.map { jsLinker.deserializeFullModule(it) }
|
||||
|
||||
ExternalDependenciesGenerator(
|
||||
moduleDescriptor = moduleDescriptor,
|
||||
symbolTable = symbolTable,
|
||||
irBuiltIns = irBuiltIns,
|
||||
deserializer = jsLinker
|
||||
).generateUnboundSymbolsAsDependencies()
|
||||
moduleFragment.patchDeclarationParents()
|
||||
|
||||
val backendContext = JsIrBackendContext(
|
||||
moduleDescriptor,
|
||||
irBuiltIns,
|
||||
symbolTable,
|
||||
moduleFragment,
|
||||
emptySet(),
|
||||
configuration,
|
||||
true
|
||||
)
|
||||
|
||||
ExternalDependenciesGenerator(
|
||||
moduleDescriptor = moduleDescriptor,
|
||||
symbolTable = symbolTable,
|
||||
irBuiltIns = irBuiltIns,
|
||||
deserializer = jsLinker
|
||||
).generateUnboundSymbolsAsDependencies()
|
||||
moduleFragment.patchDeclarationParents()
|
||||
|
||||
moduleFragment.files += irDependencies.flatMap { it.files }
|
||||
|
||||
configuration.put(JSConfigurationKeys.MODULE_KIND, ModuleKind.PLAIN)
|
||||
|
||||
return generateJsCode(backendContext, moduleFragment, nameTables)
|
||||
}
|
||||
}
|
||||
-41
@@ -1,41 +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.repl.js
|
||||
|
||||
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.emptyLoggingContext
|
||||
import org.jetbrains.kotlin.ir.backend.js.lower.serialization.ir.JsIrLinker
|
||||
import org.jetbrains.kotlin.ir.backend.js.lower.serialization.ir.JsMangler
|
||||
import org.jetbrains.kotlin.ir.backend.js.utils.NameTables
|
||||
import org.jetbrains.kotlin.ir.descriptors.IrBuiltIns
|
||||
import org.jetbrains.kotlin.ir.util.SymbolTable
|
||||
|
||||
class ScriptDependencyCompiler(
|
||||
val environment: KotlinCoreEnvironment,
|
||||
private val nameTables: NameTables = NameTables(emptyList())
|
||||
) {
|
||||
fun compile(dependencies: List<ModuleDescriptor>): Pair<String, NameTables> {
|
||||
val compiler = CoreScriptingJsCompiler(
|
||||
environment,
|
||||
nameTables,
|
||||
dependencies,
|
||||
::createDeserializer
|
||||
)
|
||||
val compileResult = compiler.compile(makeReplCodeLine(0, ""))
|
||||
return (compileResult as ReplCompileResult.CompiledClasses).data as String to nameTables
|
||||
}
|
||||
|
||||
private fun createDeserializer(m: ModuleDescriptor, symbolTable: SymbolTable, irBuiltIns: IrBuiltIns): DeserializerWithDependencies {
|
||||
val deserializer = JsIrLinker(m, JsMangler, emptyLoggingContext, irBuiltIns, symbolTable)
|
||||
val deserializedModuleFragments = m.allDependencyModules.map {
|
||||
deserializer.deserializeFullModule(it)
|
||||
}
|
||||
|
||||
return DeserializerWithDependencies(deserializer, deserializedModuleFragments)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user