Implement JSR223 host in the main-kts jar

also improve diagnostics on configuration instantiation
This commit is contained in:
Ilya Chernikov
2019-07-11 17:33:43 +02:00
parent 0108a76e99
commit a13d452cd8
6 changed files with 108 additions and 2 deletions
@@ -124,6 +124,6 @@ private fun <T : Any> KClass<T>.createInstance(): T {
private fun <T : PropertiesCollection> scriptConfigInstance(kclass: KClass<out T>): T = try { private fun <T : PropertiesCollection> scriptConfigInstance(kclass: KClass<out T>): T = try {
kclass.objectInstance ?: kclass.createInstance() kclass.objectInstance ?: kclass.createInstance()
} catch (e: Throwable) { } catch (e: Throwable) {
throw IllegalArgumentException("$ILLEGAL_CONFIG_ANN_ARG: ${e.message}", e) throw IllegalArgumentException("$ILLEGAL_CONFIG_ANN_ARG: ${e.message + if (e.cause != null) " (${e.cause})" else ""}", e)
} }
@@ -0,0 +1,26 @@
import org.jetbrains.kotlin.cli.common.environment.setIdeaIoUseFallback
import org.junit.Assert
import org.junit.Test
import javax.script.ScriptEngineManager
/*
* 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.
*/
class MainKtsJsr223Test {
init {
setIdeaIoUseFallback()
}
@Test
fun testSimpleEval() {
val engine = ScriptEngineManager().getEngineByExtension("main.kts")!!
val res1 = engine.eval("val x = 3")
Assert.assertNull(res1)
val res2 = engine.eval("x + 2")
Assert.assertEquals(5, res2)
}
}
@@ -15,6 +15,7 @@ val proguardLibraryJars by configurations.creating
val projectsDependencies = listOf( val projectsDependencies = listOf(
":kotlin-scripting-common", ":kotlin-scripting-common",
":kotlin-scripting-jvm", ":kotlin-scripting-jvm",
":kotlin-scripting-jvm-host",
":kotlin-script-util", ":kotlin-script-util",
":kotlin-script-runtime" ":kotlin-script-runtime"
) )
@@ -26,8 +27,10 @@ dependencies {
testCompile(project(it)) testCompile(project(it))
} }
compileOnly("org.apache.ivy:ivy:2.4.0") compileOnly("org.apache.ivy:ivy:2.4.0")
compileOnly(project(":compiler:cli-common"))
runtime(project(":kotlin-compiler-embeddable")) runtime(project(":kotlin-compiler-embeddable"))
runtime(project(":kotlin-scripting-compiler-embeddable")) runtime(project(":kotlin-scripting-compiler-embeddable"))
runtime(project(":kotlin-scripting-jvm-host-embeddable"))
runtime(project(":kotlin-reflect")) runtime(project(":kotlin-reflect"))
embedded("org.apache.ivy:ivy:2.4.0") embedded("org.apache.ivy:ivy:2.4.0")
embedded(commonDep("org.jetbrains.kotlinx", "kotlinx-coroutines-core")) { isTransitive = false } embedded(commonDep("org.jetbrains.kotlinx", "kotlinx-coroutines-core")) { isTransitive = false }
@@ -36,6 +39,7 @@ dependencies {
toolsJar())) toolsJar()))
proguardLibraryJars(kotlinStdlib()) proguardLibraryJars(kotlinStdlib())
proguardLibraryJars(project(":kotlin-reflect")) proguardLibraryJars(project(":kotlin-reflect"))
proguardLibraryJars(project(":kotlin-compiler"))
} }
sourceSets { sourceSets {
@@ -0,0 +1,2 @@
org.jetbrains.kotlin.mainKts.jsr223.KotlinJsr223MainKtsScriptEngineFactory
@@ -0,0 +1,60 @@
/*
* 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.mainKts.jsr223
import org.jetbrains.kotlin.cli.common.repl.KotlinJsr223JvmScriptEngineFactoryBase
import org.jetbrains.kotlin.cli.common.repl.ScriptArgsWithTypes
import org.jetbrains.kotlin.mainKts.MainKtsScript
import java.io.File
import javax.script.ScriptEngine
import kotlin.script.experimental.api.ScriptCompilationConfiguration
import kotlin.script.experimental.api.fileExtension
import kotlin.script.experimental.jvm.JvmScriptCompilationConfigurationBuilder
import kotlin.script.experimental.jvm.dependenciesFromCurrentContext
import kotlin.script.experimental.jvm.jvm
import kotlin.script.experimental.jvm.updateClasspath
import kotlin.script.experimental.jvm.util.scriptCompilationClasspathFromContext
import kotlin.script.experimental.jvmhost.createJvmCompilationConfigurationFromTemplate
import kotlin.script.experimental.jvmhost.createJvmEvaluationConfigurationFromTemplate
import kotlin.script.experimental.jvmhost.jsr223.KotlinJsr223ScriptEngineImpl
class KotlinJsr223MainKtsScriptEngineFactory : KotlinJsr223JvmScriptEngineFactoryBase() {
private val compilationConfiguration = createJvmCompilationConfigurationFromTemplate<MainKtsScript>()
private val evaluationConfiguration = createJvmEvaluationConfigurationFromTemplate<MainKtsScript>()
private var lastClassLoader: ClassLoader? = null
private var lastClassPath: List<File>? = null
override fun getExtensions(): List<String> = listOf(compilationConfiguration[ScriptCompilationConfiguration.fileExtension]!!)
@Synchronized
protected fun JvmScriptCompilationConfigurationBuilder.dependenciesFromCurrentContext() {
val currentClassLoader = Thread.currentThread().contextClassLoader
val classPath = if (lastClassLoader == null || lastClassLoader != currentClassLoader) {
scriptCompilationClasspathFromContext(
classLoader = currentClassLoader,
wholeClasspath = true,
unpackJarCollections = true
).also {
lastClassLoader = currentClassLoader
lastClassPath = it
}
} else lastClassPath!!
updateClasspath(classPath)
}
override fun getScriptEngine(): ScriptEngine =
KotlinJsr223ScriptEngineImpl(
this,
ScriptCompilationConfiguration(compilationConfiguration) {
jvm {
dependenciesFromCurrentContext()
}
},
evaluationConfiguration
) { ScriptArgsWithTypes(arrayOf(emptyArray<String>()), arrayOf(Array<String>::class)) }
}
@@ -21,6 +21,9 @@ import kotlin.script.experimental.jvm.compat.mapLegacyScriptPosition
import kotlin.script.experimental.jvm.dependenciesFromClassContext import kotlin.script.experimental.jvm.dependenciesFromClassContext
import kotlin.script.experimental.jvm.jvm import kotlin.script.experimental.jvm.jvm
import kotlin.script.experimental.jvm.updateClasspath import kotlin.script.experimental.jvm.updateClasspath
import kotlin.script.experimental.jvmhost.jsr223.configureProvidedPropertiesFromJsr223Context
import kotlin.script.experimental.jvmhost.jsr223.importAllBindings
import kotlin.script.experimental.jvmhost.jsr223.jsr223
@Suppress("unused") @Suppress("unused")
@KotlinScript( @KotlinScript(
@@ -42,18 +45,29 @@ object MainKtsScriptDefinition : ScriptCompilationConfiguration(
ide { ide {
acceptedLocations(ScriptAcceptedLocation.Everywhere) acceptedLocations(ScriptAcceptedLocation.Everywhere)
} }
jsr223 {
importAllBindings(true)
}
}) })
object MainKtsEvaluationConfiguration : ScriptEvaluationConfiguration( object MainKtsEvaluationConfiguration : ScriptEvaluationConfiguration(
{ {
scriptsInstancesSharing(true) scriptsInstancesSharing(true)
refineConfigurationBeforeEvaluate(::configureProvidedPropertiesFromJsr223Context)
} }
) )
class MainKtsConfigurator : RefineScriptCompilationConfigurationHandler { class MainKtsConfigurator : RefineScriptCompilationConfigurationHandler {
private val resolver = FilesAndIvyResolver() private val resolver = FilesAndIvyResolver()
override operator fun invoke(context: ScriptConfigurationRefinementContext): ResultWithDiagnostics<ScriptCompilationConfiguration> { override operator fun invoke(context: ScriptConfigurationRefinementContext): ResultWithDiagnostics<ScriptCompilationConfiguration> =
processAnnotations(context).onSuccess { updatedConfiguration ->
configureProvidedPropertiesFromJsr223Context(
ScriptConfigurationRefinementContext(context.script, updatedConfiguration, context.collectedData)
)
}
fun processAnnotations(context: ScriptConfigurationRefinementContext): ResultWithDiagnostics<ScriptCompilationConfiguration> {
val diagnostics = arrayListOf<ScriptDiagnostic>() val diagnostics = arrayListOf<ScriptDiagnostic>()
fun report(severity: ScriptDependenciesResolver.ReportSeverity, message: String, position: ScriptContents.Position?) { fun report(severity: ScriptDependenciesResolver.ReportSeverity, message: String, position: ScriptContents.Position?) {