[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:
Alexander Korepanov
2022-11-03 14:26:11 +01:00
committed by Space Team
parent d75bbc49e7
commit d5e9e87538
41 changed files with 14 additions and 1860 deletions
@@ -1,35 +0,0 @@
plugins {
kotlin("jvm")
}
val embeddableTestRuntime by configurations.creating
dependencies {
testApi(commonDependency("junit"))
testApi(project(":kotlin-scripting-js"))
testApi(project(":compiler:plugin-api"))
testApi(project(":kotlin-scripting-compiler-js"))
testApi(project(":compiler:cli"))
testApi(project(":compiler:backend.js"))
testApi(project(":compiler:ir.tree"))
testApi(project(":js:js.engines"))
testApi(intellijCore())
testRuntimeOnly(commonDependency("org.jetbrains.intellij.deps.fastutil:intellij-deps-fastutil"))
testRuntimeOnly(commonDependency("org.jetbrains.intellij.deps:jdom"))
testRuntimeOnly(commonDependency("org.jetbrains.intellij.deps:trove4j"))
}
optInToExperimentalCompilerApi()
sourceSets {
"main" {}
"test" { projectDefault() }
}
projectTest(parallel = true) {
dependsOn(":kotlin-stdlib-js-ir:compileKotlinJs")
systemProperty("kotlin.js.full.stdlib.path", "libraries/stdlib/js-ir/build/classes/kotlin/js/main")
workingDir = rootDir
}
@@ -1,85 +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.
*/
@file:Suppress("DEPRECATION")
package org.jetbrains.kotlin.scripting.repl.js.test
import com.intellij.openapi.util.Disposer
import org.jetbrains.kotlin.cli.common.CLIConfigurationKeys
import org.jetbrains.kotlin.cli.common.messages.MessageCollector
import org.jetbrains.kotlin.cli.common.repl.ReplCodeLine
import org.jetbrains.kotlin.cli.common.repl.ReplCompileResult
import org.jetbrains.kotlin.cli.common.repl.ReplEvalResult
import org.jetbrains.kotlin.cli.jvm.compiler.EnvironmentConfigFiles
import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment
import org.jetbrains.kotlin.compiler.plugin.ComponentRegistrar
import org.jetbrains.kotlin.config.CommonConfigurationKeys
import org.jetbrains.kotlin.config.CompilerConfiguration
import org.jetbrains.kotlin.js.config.JSConfigurationKeys
import org.jetbrains.kotlin.scripting.compiler.plugin.ScriptingCompilerConfigurationComponentRegistrar
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.js.JsReplCompiler
import org.jetbrains.kotlin.scripting.js.JsReplCompilerState
import org.jetbrains.kotlin.scripting.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
import kotlin.script.experimental.api.dependencies
import kotlin.script.experimental.host.ScriptingHostConfiguration
import kotlin.script.experimental.jvm.JsDependency
abstract class AbstractJsReplTest : Closeable {
protected lateinit var compilerState: JsReplCompilerState
protected lateinit var evaluationState: JsEvaluationState
protected abstract fun createCompilationState(): JsReplCompilerState
protected abstract fun createEvaluationState(): JsEvaluationState
fun compile(codeLine: ReplCodeLine): ReplCompileResult {
return JsReplCompiler(environment).compile(compilerState, codeLine)
}
fun evaluate(compileResult: ReplCompileResult.CompiledClasses): ReplEvalResult {
return JsReplEvaluator().eval(evaluationState, compileResult)
}
fun reset() {
collector.clear()
compilerState = createCompilationState()
evaluationState = createEvaluationState()
}
private val collector: MessageCollector = ReplMessageCollector()
protected val disposable = Disposer.newDisposable()
protected val environment = KotlinCoreEnvironment.createForProduction(
disposable, loadConfiguration(), EnvironmentConfigFiles.JS_CONFIG_FILES
)
private var snippetId: Int = 1 //index 0 for klib
fun newSnippetId(): Int = snippetId++
private fun loadConfiguration(): CompilerConfiguration {
val configuration = CompilerConfiguration()
configuration.add(ComponentRegistrar.PLUGIN_COMPONENT_REGISTRARS, ScriptingCompilerConfigurationComponentRegistrar())
configuration.put(CLIConfigurationKeys.MESSAGE_COLLECTOR_KEY, collector)
configuration.put(CommonConfigurationKeys.MODULE_NAME, "repl.kts")
configuration.put(JSConfigurationKeys.GENERATE_POLYFILLS, true)
val stdlibPath = System.getProperty("kotlin.js.full.stdlib.path")
val scriptConfiguration = ScriptCompilationConfiguration {
baseClass("kotlin.Any")
dependencies.append(JsDependency(stdlibPath))
platform.put("JS")
}
configuration.add(
ScriptingConfigurationKeys.SCRIPT_DEFINITIONS,
ScriptDefinition.FromConfigurations(ScriptingHostConfiguration(), scriptConfiguration, null)
)
return configuration
}
}
@@ -1,53 +0,0 @@
/*
* Copyright 2010-2020 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.test
import org.jetbrains.kotlin.backend.common.serialization.signature.IdSignatureDescriptor
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.js.engine.ScriptEngineNashorn
import org.jetbrains.kotlin.scripting.compiler.plugin.repl.ReplCodeAnalyzerBase
import org.jetbrains.kotlin.scripting.js.*
import org.jetbrains.kotlin.scripting.repl.js.JsEvaluationState
import org.jetbrains.kotlin.scripting.repl.js.JsReplEvaluator
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 dependencies = readLibrariesFromConfiguration(environment.configuration)
init {
val nameTable = NameTables(emptyList(), mappedNames = mutableMapOf())
val compiler = JsScriptDependencyCompiler(environment.configuration, nameTable, createSymbolTable())
val runtimeBinary = compiler.compile(dependencies)
dependencyLoader.saveScriptDependencyBinary(runtimeBinary)
dependencyLoader.saveNames(nameTable)
}
override fun createCompilationState(): JsReplCompilerState {
val replState = ReplCodeAnalyzerBase.ResettableAnalyzerState()
return JsReplCompilerState(ReentrantReadWriteLock(), dependencyLoader.loadNames(), dependencies, replState, createSymbolTable())
}
private fun createSymbolTable(): SymbolTable =
SymbolTable(IdSignatureDescriptor(JsManglerDesc), IrFactoryImpl)
override fun createEvaluationState(): JsEvaluationState {
val state = JsEvaluationState(ReentrantReadWriteLock(), ScriptEngineNashorn())
JsReplEvaluator().eval(state, createCompileResult(dependencyLoader.loadScriptDependencyBinary()))
return state
}
override fun close() {
//do nothing
}
}
@@ -1,56 +0,0 @@
/*
* Copyright 2010-2020 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.test
import com.intellij.openapi.util.Disposer
import org.jetbrains.kotlin.backend.common.serialization.signature.IdSignatureDescriptor
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.js.engine.ScriptEngineNashorn
import org.jetbrains.kotlin.scripting.compiler.plugin.repl.ReplCodeAnalyzerBase
import org.jetbrains.kotlin.scripting.js.JsReplCompilerState
import org.jetbrains.kotlin.scripting.js.JsScriptDependencyCompiler
import org.jetbrains.kotlin.scripting.js.createCompileResult
import org.jetbrains.kotlin.scripting.js.readLibrariesFromConfiguration
import org.jetbrains.kotlin.scripting.repl.js.*
import java.util.concurrent.locks.ReentrantReadWriteLock
class JsReplTestAgainstKlib : AbstractJsReplTest() {
private var dependencyCode: String? = null
override fun createCompilationState(): JsReplCompilerState {
val nameTables = NameTables(emptyList(), mappedNames = mutableMapOf())
val symbolTable = SymbolTable(IdSignatureDescriptor(JsManglerDesc), IrFactoryImpl)
val dependencyCompiler = JsScriptDependencyCompiler(environment.configuration, nameTables, symbolTable)
val dependencies = readLibrariesFromConfiguration(environment.configuration)
dependencyCode = dependencyCompiler.compile(dependencies)
return JsReplCompilerState(
ReentrantReadWriteLock(),
nameTables,
dependencies,
ReplCodeAnalyzerBase.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)
}
}
@@ -1,287 +0,0 @@
/*
* Copyright 2010-2020 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.test
import junit.framework.TestCase
import org.jetbrains.kotlin.cli.common.repl.ReplCompileResult
import org.junit.Assert
import org.junit.Test
import org.jetbrains.kotlin.cli.common.repl.ReplEvalResult
import org.jetbrains.kotlin.scripting.js.makeReplCodeLine
abstract class AbstractReplTestRunner : TestCase() {
abstract fun getTester(): AbstractJsReplTest
@Test
fun testIndependentLines() {
val lines = listOf(
"var x = 38",
"var y = 99",
"4 + 1"
)
Assert.assertEquals(5, compileAndEval(lines))
}
@Test
fun testDependentLines() {
val lines = listOf(
"var x = 7",
"var y = 32",
"x + y"
)
Assert.assertEquals(39, compileAndEval(lines))
}
@Test
fun testFunctionCall() {
val lines = listOf(
"var x = 2",
"var y = 3",
"fun foo(x: Int, unused: Int) = x + y",
"foo(x, x) * foo(y, y)"
)
Assert.assertEquals(30, compileAndEval(lines))
}
@Test
fun testList() {
val lines = listOf(
"var a = 4",
"var b = 6",
"listOf(a, 5, b).last()"
)
Assert.assertEquals(6, compileAndEval(lines))
}
@Test
fun testMatchingNames() {
val lines = listOf(
"fun foo(i: Int) = i + 2",
"fun foo(s: String) = s",
"class C {fun foo(s: String) = s + s}",
"foo(\"x\") + foo(2) + C().foo(\"class\")"
)
Assert.assertEquals("x4classclass", compileAndEval(lines))
}
@Test
fun testInline() {
val lines = listOf(
"inline fun foo(i : Int) = if (i % 2 == 0) {} else i",
"""
fun box(): String {
val a = foo(1)
if (a != 1) return "fail1: ${'$'}a"
val b = foo(2)
if (b != Unit) return "fail2: ${'$'}b"
return "OK"
}
""",
"box()"
)
Assert.assertEquals("OK", compileAndEval(lines))
}
@Test
fun testAnonymous() {
val lines = listOf(
"""
inline fun foo(f: () -> String): () -> String {
val result = f()
return { result }
}
""",
"fun bar(f: () -> String) = foo(f)()",
"fun box(): String = bar { \"OK\" }",
"box()"
)
Assert.assertEquals("OK", compileAndEval(lines))
}
@Test
fun testNoneLocalReturn() {
val lines = listOf(
"""
inline fun f(ignored: () -> Any): Any {
return ignored()
}
""",
"""
fun test(): String {
f { return "OK" };
return "error"
}
""",
"test()"
)
Assert.assertEquals("OK", compileAndEval(lines))
}
/* Ignore annotation doesn't work, so comment it
@Ignore("we use Object.assign inside type checks and nashorn does not support it")
@Test
fun testInstanceOf() {
val lines = listOf(
"""
val list = listOf(1, 2, 3)
val f: Boolean = list is List<Int>
""",
"val s = list is List<Int>",
"f.toString() + s.toString()"
)
Assert.assertEquals("truetrue", compileAndEval(lines))
}
*/
@Test
fun testScopes() {
val lines = listOf(
"""
fun foo(): Int {
var t = 2 * 2
class A(val value: Int = 5) {
fun bar(): Int {
class B(val value: Int = 4) {
fun baz(): Int = value
}
var q = B().baz()
var w = 1
return q + w
}
}
return A().bar() * 2
}
foo()
"""
)
Assert.assertEquals(10, compileAndEval(lines))
}
@Test
fun testEvaluateFunctionName() {
val lines = listOf(
"fun evaluateScript() = 5",
"fun foo(i: Int) = i + evaluateScript()",
"foo(5)"
)
Assert.assertEquals(10, compileAndEval(lines))
}
@Test
fun testMemberDeclarations() {
val lines = listOf(
"""
val a = listOf(1, 2, 3, 4, 5)
val str = "" + kotlin.math.PI
str + a.subList(2, 3).toString() + a.lastIndexOf(4)
"""
)
Assert.assertEquals("3.141592653589793[3]3", compileAndEval(lines))
}
@Test
fun testInitializeScriptFunction() {
val lines = listOf(
"""
var result = ""
class Class(val x: Int = 10)
result += Class().x
fun function() = "#$@"
result += function()
val field = 123456
result += field
val sq: (x: Int) -> Int = { x -> x * x }
result += "_" + sq(9)
result += if (sq(5) % 2 == 0) {
class I(val x: Int = 100)
I().x
} else {
class I(val x: String = "goo")
I().x
}
result
"""
)
Assert.assertEquals("10#$@123456_81goo", compileAndEval(lines))
}
@Test
fun testFunctionReference() {
val lines = listOf(
"""
fun foo(k: String) = "O" + k
val f = ::foo
f("K")
"""
)
Assert.assertEquals("OK", compileAndEval(lines))
}
@Test
fun testPropertyReference() {
val lines = listOf(
"""
var r = ""
val o = "O"
val ro = ::o
r += ro.get()
r += ro()
var k = "k"
var rk = ::k
r += rk.get()
rk.set("y")
r += rk()
r
"""
)
Assert.assertEquals("OOky", compileAndEval(lines))
}
private fun compileAndEval(lines: List<String>): Any? {
var result: Any? = null
getTester().use { tester ->
tester.reset()
lines.forEach { line ->
val compileResult = tester.compile(makeReplCodeLine(tester.newSnippetId(), line))
if (compileResult !is ReplCompileResult.CompiledClasses) return compileResult.toString()
val evalResult = tester.evaluate(compileResult)
when (evalResult) {
is ReplEvalResult.Error.Runtime -> return evalResult.cause.toString()
!is ReplEvalResult.ValueResult -> return evalResult.toString()
else -> result = evalResult.value
}
}
}
return result
}
}
class ReplTestRunnerAgainstKLib : AbstractReplTestRunner() {
override fun getTester(): AbstractJsReplTest = JsReplTestAgainstKlib()
}
class ReplTestRunnerAgainstBinaries : AbstractReplTestRunner() {
override fun getTester(): AbstractJsReplTest = tester
companion object {
private val tester = JsReplTestAgainstBinaries()
}
}
-21
View File
@@ -1,21 +0,0 @@
plugins {
kotlin("jvm")
id("jps-compatible")
}
dependencies {
api(project(":kotlin-scripting-common"))
compileOnly(project(":compiler:backend.js"))
compileOnly(project(":compiler:cli-common"))
compileOnly(project(":js:js.engines"))
}
sourceSets {
"main" { projectDefault() }
"test" { }
}
publish()
standardPublicJars()
@@ -1,30 +0,0 @@
/*
* Copyright 2010-2020 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.js.engine.ScriptEngineNashorn
import java.util.concurrent.locks.ReentrantReadWriteLock
class JsReplEvaluator : ReplEvaluator {
//TODO: support println()
override fun createState(lock: ReentrantReadWriteLock): IReplStageState<*> = JsEvaluationState(lock, ScriptEngineNashorn())
override fun eval(
state: IReplStageState<*>,
compileResult: ReplCompileResult.CompiledClasses,
scriptArgs: ScriptArgsWithTypes?,
invokeWrapper: InvokeWrapper?
): ReplEvalResult {
return try {
val evaluationState = state.asState(JsEvaluationState::class.java)
val evalResult = evaluationState.engine.evalWithTypedResult<Any?>(compileResult.data as String)
ReplEvalResult.ValueResult("result", evalResult, "Any?")
} catch (e: Exception) {
ReplEvalResult.Error.Runtime("Error while evaluating", e)
}
}
}
@@ -1,38 +0,0 @@
/*
* Copyright 2010-2020 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.IReplStageHistory
import org.jetbrains.kotlin.cli.common.repl.IReplStageState
import org.jetbrains.kotlin.js.engine.ScriptEngineWithTypedResult
import java.util.concurrent.locks.ReentrantReadWriteLock
import kotlin.reflect.KClass
import kotlin.script.experimental.api.CompiledScript
import kotlin.script.experimental.api.ResultWithDiagnostics
import kotlin.script.experimental.api.ScriptCompilationConfiguration
import kotlin.script.experimental.api.ScriptEvaluationConfiguration
// NOTE: the state management machinery is not implemented here, since it is unused at the moment in the JS REPL (see JvmReplEvaluatorState for complete implementation, if needed)
class JsEvaluationState(override val lock: ReentrantReadWriteLock, val engine: ScriptEngineWithTypedResult) : IReplStageState<Nothing> {
override fun dispose() {
engine.reset()
}
override val history: IReplStageHistory<Nothing>
get() = TODO("not implemented")
override val currentGeneration: Int
get() = TODO("not implemented")
}
class JsCompiledScript(
val jsCode: String,
override val compilationConfiguration: ScriptCompilationConfiguration
) : CompiledScript {
override suspend fun getClass(scriptEvaluationConfiguration: ScriptEvaluationConfiguration?): ResultWithDiagnostics<KClass<*>> {
throw IllegalStateException("Class is not available for JS implementation")
}
}
@@ -1,44 +0,0 @@
/*
* Copyright 2010-2020 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.js.engine.ScriptEngineNashorn
import kotlin.script.experimental.api.*
class JsScriptEvaluator : ScriptEvaluator {
//TODO: support println()
private val engine = ScriptEngineNashorn()
override suspend fun invoke(
compiledScript: CompiledScript,
scriptEvaluationConfiguration: ScriptEvaluationConfiguration
): ResultWithDiagnostics<EvaluationResult> {
return try {
val evalResult = engine.evalWithTypedResult<Any?>((compiledScript as JsCompiledScript).jsCode)
ResultWithDiagnostics.Success(
EvaluationResult(
ResultValue.Value(
name = "result",
value = evalResult,
type = "Any?",
scriptClass = null,
scriptInstance = null
),
scriptEvaluationConfiguration
)
)
} catch (e: Exception) {
ResultWithDiagnostics.Failure(
ScriptDiagnostic(
ScriptDiagnostic.unspecifiedError,
message = e.localizedMessage,
severity = ScriptDiagnostic.Severity.ERROR,
exception = e
)
)
}
}
}