[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:
Roman Artemev
2019-09-25 20:50:23 +03:00
committed by romanart
parent f59e393e37
commit c0f279811e
25 changed files with 404 additions and 357 deletions
@@ -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++
@@ -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() {
@@ -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)
}
+3 -3
View File
@@ -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 {
@@ -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> {
@@ -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(
@@ -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,