From 74f8a541c099ccbbb4fcd9edef978290682bf531 Mon Sep 17 00:00:00 2001 From: Ilya Chernikov Date: Mon, 30 Jul 2018 17:55:13 +0200 Subject: [PATCH] Grand refactoring of the scripting DSL + many minor usability refactorings around it --- compiler/build.gradle.kts | 1 - .../jetbrains/kotlin/cli/jvm/K2JVMCompiler.kt | 6 +- .../AbstractCustomScriptCodegenTest.kt | 36 ++- .../kotlin/codegen/CustomScriptCodegenTest.kt | 3 +- .../org/jetbrains/kotlin/utils/PathUtil.kt | 1 - .../core/script/ScriptDefinitionsManager.kt | 10 +- .../examples/jvm/resolve/maven/host/host.kt | 6 +- .../jvm-maven-deps/script/build.gradle.kts | 1 - .../examples/jvm/resolve/maven/scriptDef.kt | 49 ++-- .../jvm-simple-script/host/build.gradle.kts | 1 - .../script/examples/jvm/simple/host/host.kt | 19 +- .../annotations/scriptAnnotations.kt | 13 +- .../script/experimental/api/errorHandling.kt | 11 +- .../script/experimental/api/propertiesDsl.kt | 212 ------------------ .../experimental/api/scriptCompilation.kt | 5 +- .../experimental/api/scriptConfiguration.kt | 50 +++-- .../experimental/api/scriptDefinition.kt | 112 ++++----- .../experimental/api/scriptEvaluation.kt | 27 ++- .../experimental/api/scriptingEnvironment.kt | 35 +-- .../definitions/definitionFromAnnotation.kt | 47 ++-- .../experimental/host/BasicScriptingHost.kt | 4 +- .../experimental/host/scriptHostUtil.kt | 10 +- .../experimental/repl/replEvaluation.kt | 13 +- .../script/experimental/repl/replHost.kt | 16 +- .../experimental/util/propertiesCollection.kt | 208 +++++++++++++++++ .../script/experimental/util/propertyBag.kt | 55 ----- .../jvmhost/impl/KJVMCompilerImpl.kt | 62 ++--- .../experimental/jvmhost/impl/jvmHostUtil.kt | 35 +++ .../jvmhost/jvmScriptCompilation.kt | 38 ++-- .../jvmhost/jvmScriptEvaluation.kt | 16 +- .../jvm/impl/BridgeDependenciesResolver.kt | 33 ++- .../jvm/jvmScriptConfiguration.kt | 15 +- ...Dependencies.kt => jvmScriptDefinition.kt} | 23 +- .../experimental/jvm/jvmScriptEnvironment.kt | 26 ++- .../script/experimental/misc/propertiesDsl.kt | 28 +-- .../scripting/scripting-cli/build.gradle.kts | 1 - ...KotlinScriptDefinitionAdapterFromNewAPI.kt | 28 +-- ...LazyScriptDefinitionFromDiscoveredClass.kt | 13 +- .../plugin/ScriptingCompilerPluginTest.kt | 2 +- .../scripting-embeddable/build.gradle.kts | 1 - settings.gradle | 2 - 41 files changed, 655 insertions(+), 619 deletions(-) delete mode 100644 libraries/scripting/common/src/kotlin/script/experimental/api/propertiesDsl.kt create mode 100644 libraries/scripting/common/src/kotlin/script/experimental/util/propertiesCollection.kt delete mode 100644 libraries/scripting/common/src/kotlin/script/experimental/util/propertyBag.kt create mode 100644 libraries/scripting/jvm-host/src/kotlin/script/experimental/jvmhost/impl/jvmHostUtil.kt rename libraries/scripting/jvm/src/kotlin/script/experimental/jvm/{jvmDependencies.kt => jvmScriptDefinition.kt} (56%) diff --git a/compiler/build.gradle.kts b/compiler/build.gradle.kts index dcec1b4dffb..6336f65447c 100644 --- a/compiler/build.gradle.kts +++ b/compiler/build.gradle.kts @@ -75,7 +75,6 @@ dependencies { testCompile(project(":compiler:ir.ir2cfg")) testCompile(project(":compiler:ir.tree")) // used for deepCopyWithSymbols call that is removed by proguard from the compiler TODO: make it more straightforward testCompile(project(":kotlin-scripting-compiler")) - testCompile(project(":kotlin-scripting-misc")) testCompile(project(":kotlin-script-util")) testCompileOnly(projectRuntimeJar(":kotlin-daemon-client")) testCompileOnly(project(":kotlin-reflect-api")) diff --git a/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/K2JVMCompiler.kt b/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/K2JVMCompiler.kt index f6fae341598..b071b1dd39a 100644 --- a/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/K2JVMCompiler.kt +++ b/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/K2JVMCompiler.kt @@ -244,9 +244,9 @@ class K2JVMCompiler : CLICompiler() { with(PathUtil) { val jars = arrayOf( KOTLIN_SCRIPTING_COMPILER_PLUGIN_JAR, KOTLIN_SCRIPTING_COMMON_JAR, - KOTLIN_SCRIPTING_JVM_JAR, KOTLIN_SCRIPTING_MISC_JAR - ).mapNotNull { File(libPath, it).takeIf(File::exists)?.canonicalPath } - if (jars.size == 4) { + KOTLIN_SCRIPTING_JVM_JAR + ).mapNotNull { File(libPath, it).takeIf { it.exists() }?.canonicalPath } + if (jars.size == 3) { pluginClasspaths = jars + pluginClasspaths } } diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/AbstractCustomScriptCodegenTest.kt b/compiler/tests/org/jetbrains/kotlin/codegen/AbstractCustomScriptCodegenTest.kt index 7ae5326e20b..7a7af14f1a5 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/AbstractCustomScriptCodegenTest.kt +++ b/compiler/tests/org/jetbrains/kotlin/codegen/AbstractCustomScriptCodegenTest.kt @@ -17,14 +17,12 @@ import org.jetbrains.kotlin.utils.PathUtil import org.jetbrains.kotlin.utils.PathUtil.KOTLIN_SCRIPTING_COMMON_JAR import org.jetbrains.kotlin.utils.PathUtil.KOTLIN_SCRIPTING_COMPILER_PLUGIN_JAR import org.jetbrains.kotlin.utils.PathUtil.KOTLIN_SCRIPTING_JVM_JAR -import org.jetbrains.kotlin.utils.PathUtil.KOTLIN_SCRIPTING_MISC_JAR import org.junit.Assert import java.io.File import kotlin.script.experimental.annotations.KotlinScript -import kotlin.script.experimental.annotations.KotlinScriptPropertiesFromList -import kotlin.script.experimental.api.KotlinType -import kotlin.script.experimental.api.ScriptDefinitionProperties -import kotlin.script.experimental.util.TypedKey +import kotlin.script.experimental.api.ScriptDefinition +import kotlin.script.experimental.api.contextVariables +import kotlin.script.experimental.api.scriptImplicitReceivers abstract class AbstractCustomScriptCodegenTest : CodegenTestCase() { private lateinit var scriptDefinitions: List @@ -59,7 +57,7 @@ abstract class AbstractCustomScriptCodegenTest : CodegenTestCase() { with(PathUtil.kotlinPathsForDistDirectory) { arrayOf( KOTLIN_SCRIPTING_COMPILER_PLUGIN_JAR, KOTLIN_SCRIPTING_COMMON_JAR, - KOTLIN_SCRIPTING_JVM_JAR, KOTLIN_SCRIPTING_MISC_JAR + KOTLIN_SCRIPTING_JVM_JAR ).mapNotNull { File(libPath, it).takeIf { it.exists() } } } } @@ -123,24 +121,22 @@ abstract class AbstractCustomScriptCodegenTest : CodegenTestCase() { } } -object TestScriptWithReceiversConfiguration : ArrayList, Any?>>( - listOf( - ScriptDefinitionProperties.scriptImplicitReceivers to listOf(KotlinType(String::class)) - ) -) +object TestScriptWithReceiversConfiguration : ScriptDefinition { + override val properties = properties { + scriptImplicitReceivers() + } +} @Suppress("unused") -@KotlinScript -@KotlinScriptPropertiesFromList(TestScriptWithReceiversConfiguration::class) +@KotlinScript(definition = TestScriptWithReceiversConfiguration::class) abstract class TestScriptWithReceivers -object TestScriptWithSimpleEnvVarsConfiguration : ArrayList, Any?>>( - listOf( - ScriptDefinitionProperties.contextVariables to mapOf("stringVar1" to KotlinType(String::class)) - ) -) +object TestScriptWithSimpleEnvVarsConfiguration : ScriptDefinition { + override val properties = properties { + contextVariables("stringVar1" to String::class) + } +} @Suppress("unused") -@KotlinScript -@KotlinScriptPropertiesFromList(TestScriptWithSimpleEnvVarsConfiguration::class) +@KotlinScript(definition = TestScriptWithSimpleEnvVarsConfiguration::class) abstract class TestScriptWithSimpleEnvVars diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/CustomScriptCodegenTest.kt b/compiler/tests/org/jetbrains/kotlin/codegen/CustomScriptCodegenTest.kt index e29e4807936..92708068f02 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/CustomScriptCodegenTest.kt +++ b/compiler/tests/org/jetbrains/kotlin/codegen/CustomScriptCodegenTest.kt @@ -16,7 +16,6 @@ import org.jetbrains.kotlin.utils.PathUtil import org.jetbrains.kotlin.utils.PathUtil.KOTLIN_SCRIPTING_COMMON_JAR import org.jetbrains.kotlin.utils.PathUtil.KOTLIN_SCRIPTING_COMPILER_PLUGIN_JAR import org.jetbrains.kotlin.utils.PathUtil.KOTLIN_SCRIPTING_JVM_JAR -import org.jetbrains.kotlin.utils.PathUtil.KOTLIN_SCRIPTING_MISC_JAR import java.io.File import kotlin.reflect.KClass import kotlin.script.experimental.annotations.KotlinScript @@ -50,7 +49,7 @@ class CustomScriptCodegenTest : CodegenTestCase() { with(PathUtil.kotlinPathsForDistDirectory) { arrayOf( KOTLIN_SCRIPTING_COMPILER_PLUGIN_JAR, KOTLIN_SCRIPTING_COMMON_JAR, - KOTLIN_SCRIPTING_JVM_JAR, KOTLIN_SCRIPTING_MISC_JAR + KOTLIN_SCRIPTING_JVM_JAR ).mapNotNull { File(libPath, it).also { assertTrue("$it not found", it.exists()) } } } diff --git a/compiler/util/src/org/jetbrains/kotlin/utils/PathUtil.kt b/compiler/util/src/org/jetbrains/kotlin/utils/PathUtil.kt index 0575a7ce061..83171bd2873 100644 --- a/compiler/util/src/org/jetbrains/kotlin/utils/PathUtil.kt +++ b/compiler/util/src/org/jetbrains/kotlin/utils/PathUtil.kt @@ -59,7 +59,6 @@ object PathUtil { const val KOTLIN_JAVA_SCRIPT_RUNTIME_JAR = "kotlin-script-runtime.jar" const val KOTLIN_SCRIPTING_COMMON_JAR = "kotlin-scripting-common.jar" const val KOTLIN_SCRIPTING_JVM_JAR = "kotlin-scripting-jvm.jar" - const val KOTLIN_SCRIPTING_MISC_JAR = "kotlin-scripting-misc.jar" const val KOTLIN_SCRIPTING_COMPILER_PLUGIN_NAME = "kotlin-scripting-compiler" const val KOTLIN_SCRIPTING_COMPILER_PLUGIN_JAR = "$KOTLIN_SCRIPTING_COMPILER_PLUGIN_NAME.jar" diff --git a/idea/idea-core/src/org/jetbrains/kotlin/idea/core/script/ScriptDefinitionsManager.kt b/idea/idea-core/src/org/jetbrains/kotlin/idea/core/script/ScriptDefinitionsManager.kt index 651b59a4afd..f34d2bc532a 100644 --- a/idea/idea-core/src/org/jetbrains/kotlin/idea/core/script/ScriptDefinitionsManager.kt +++ b/idea/idea-core/src/org/jetbrains/kotlin/idea/core/script/ScriptDefinitionsManager.kt @@ -50,7 +50,7 @@ import kotlin.script.dependencies.Environment import kotlin.script.dependencies.ScriptContents import kotlin.script.experimental.api.KotlinType import kotlin.script.experimental.api.ScriptingEnvironment -import kotlin.script.experimental.api.ScriptingEnvironmentProperties +import kotlin.script.experimental.api.configurationDependencies import kotlin.script.experimental.definitions.createScriptDefinitionFromAnnotatedBaseClass import kotlin.script.experimental.dependencies.DependenciesResolver import kotlin.script.experimental.dependencies.ScriptDependencies @@ -208,10 +208,10 @@ fun loadDefinitionsFromTemplates( ) } template.annotations.firstIsInstanceOrNull() != null -> { - val hostEnvironment = ScriptingEnvironment( - defaultJvmScriptingEnvironment, - ScriptingEnvironmentProperties.configurationDependencies to listOf(JvmDependency(classpath)) - ) + val hostEnvironment = ScriptingEnvironment.create { + include(defaultJvmScriptingEnvironment) + configurationDependencies(JvmDependency(classpath)) + } KotlinScriptDefinitionAdapterFromNewAPI( createScriptDefinitionFromAnnotatedBaseClass(KotlinType(template), hostEnvironment, KotlinScriptDefinition::class), hostEnvironment diff --git a/libraries/examples/scripting/jvm-maven-deps/host/src/org/jetbrains/kotlin/script/examples/jvm/resolve/maven/host/host.kt b/libraries/examples/scripting/jvm-maven-deps/host/src/org/jetbrains/kotlin/script/examples/jvm/resolve/maven/host/host.kt index 5394dbd950b..20a78d9ecd2 100644 --- a/libraries/examples/scripting/jvm-maven-deps/host/src/org/jetbrains/kotlin/script/examples/jvm/resolve/maven/host/host.kt +++ b/libraries/examples/scripting/jvm-maven-deps/host/src/org/jetbrains/kotlin/script/examples/jvm/resolve/maven/host/host.kt @@ -9,17 +9,13 @@ import org.jetbrains.kotlin.script.examples.jvm.resolve.maven.MyScriptWithMavenD import java.io.File import kotlin.script.experimental.api.EvaluationResult import kotlin.script.experimental.api.ResultWithDiagnostics -import kotlin.script.experimental.api.ScriptCompileConfiguration -import kotlin.script.experimental.api.ScriptEvaluationEnvironment import kotlin.script.experimental.host.toScriptSource import kotlin.script.experimental.jvmhost.makeBasicHostFromAnnotatedScriptBaseClass fun evalFile(scriptFile: File): ResultWithDiagnostics { val host = makeBasicHostFromAnnotatedScriptBaseClass() - return host.eval( - scriptFile.toScriptSource(), ScriptCompileConfiguration(), ScriptEvaluationEnvironment() - ) + return host.eval(scriptFile.toScriptSource(), null, null) } fun main(vararg args: String) { diff --git a/libraries/examples/scripting/jvm-maven-deps/script/build.gradle.kts b/libraries/examples/scripting/jvm-maven-deps/script/build.gradle.kts index f226fe22664..dd7f9f20e69 100644 --- a/libraries/examples/scripting/jvm-maven-deps/script/build.gradle.kts +++ b/libraries/examples/scripting/jvm-maven-deps/script/build.gradle.kts @@ -5,7 +5,6 @@ plugins { dependencies { compile(project(":kotlin-scripting-jvm")) - compile(project(":kotlin-scripting-misc")) compile(project(":kotlin-script-util")) runtime("com.jcabi:jcabi-aether:0.10.1") runtime("org.sonatype.aether:aether-api:1.13.1") diff --git a/libraries/examples/scripting/jvm-maven-deps/script/src/org/jetbrains/kotlin/script/examples/jvm/resolve/maven/scriptDef.kt b/libraries/examples/scripting/jvm-maven-deps/script/src/org/jetbrains/kotlin/script/examples/jvm/resolve/maven/scriptDef.kt index 94240cf3c93..a29328e34c9 100644 --- a/libraries/examples/scripting/jvm-maven-deps/script/src/org/jetbrains/kotlin/script/examples/jvm/resolve/maven/scriptDef.kt +++ b/libraries/examples/scripting/jvm-maven-deps/script/src/org/jetbrains/kotlin/script/examples/jvm/resolve/maven/scriptDef.kt @@ -16,34 +16,35 @@ import kotlin.script.experimental.api.* import kotlin.script.experimental.jvm.JvmDependency import kotlin.script.experimental.jvm.compat.mapLegacyDiagnosticSeverity import kotlin.script.experimental.jvm.compat.mapLegacyScriptPosition -import kotlin.script.experimental.jvm.jvmDependenciesFromCurrentContext -import kotlin.script.experimental.misc.invoke +import kotlin.script.experimental.jvm.dependenciesFromCurrentContext +import kotlin.script.experimental.jvm.jvm +import kotlin.script.experimental.util.getOrNull @KotlinScript( extension = "scriptwithdeps.kts", - properties = MyScriptProperties::class + definition = MyScriptDefinition::class ) abstract class MyScriptWithMavenDeps { // abstract fun body(vararg args: String): Int } -class MyScriptProperties : ScriptingProperties() { - override fun setup() { - scriptDefinition { - defaultImports() - defaultImports(Repository::class) - jvmDependenciesFromCurrentContext( +object MyScriptDefinition : ScriptDefinition { + override val properties = properties { + defaultImports() + defaultImports(Repository::class) + jvm { + dependenciesFromCurrentContext( "scripting-jvm-maven-deps", // script library jar name "kotlin-script-util" // DependsOn annotation is taken from script-util ) - // variant: dependencies(collectDependenciesFromCurrentContext(... - refineConfiguration { + } + // variant: dependencies(collectDependenciesFromCurrentContext(... + refineConfiguration { // variant ^: dynamicConfiguration - handler(MyConfigurator()) - triggerOnAnnotations(DependsOn::class, Repository::class) - // variants: onAnnotations, refineOnAnnotations (esp. for dynamicConfiguration), updateOnAnnotations - // other triggers: beforeParsing, onSections - } + handler(MyConfigurator()) + triggerOnAnnotations(DependsOn::class, Repository::class) + // variants: onAnnotations, refineOnAnnotations (esp. for dynamicConfiguration), updateOnAnnotations + // other triggers: beforeParsing, onSections } } } @@ -54,10 +55,11 @@ class MyConfigurator : RefineScriptCompilationConfigurationHandler { override suspend operator fun invoke( scriptSource: ScriptSource, - configuration: ScriptCompileConfiguration, - processedScriptData: ProcessedScriptData - ): ResultWithDiagnostics { - val annotations = processedScriptData.getOrNull(ProcessedScriptDataProperties.foundAnnotations)?.takeIf { it.isNotEmpty() } + scriptDefinition: ScriptDefinition, + configuration: ScriptCompileConfiguration?, + processedScriptData: ProcessedScriptData? + ): ResultWithDiagnostics { + val annotations = processedScriptData?.getOrNull(ProcessedScriptData.foundAnnotations)?.takeIf { it.isNotEmpty() } ?: return configuration.asSuccess() val scriptContents = object : ScriptContents { override val annotations: Iterable = annotations @@ -73,10 +75,9 @@ class MyConfigurator : RefineScriptCompilationConfigurationHandler { ?: return configuration.asSuccess(diagnostics) val resolvedClasspath = newDepsFromResolver.classpath.toList().takeIf { it.isNotEmpty() } ?: return configuration.asSuccess(diagnostics) - val newDependency = JvmDependency(resolvedClasspath) - val updatedDeps = - configuration.getOrNull(ScriptDefinitionProperties.dependencies)?.plus(newDependency) ?: listOf(newDependency) - ScriptCompileConfiguration(configuration, ScriptDefinitionProperties.dependencies(updatedDeps)).asSuccess(diagnostics) + ScriptCompileConfiguration.create { + dependencies(JvmDependency(resolvedClasspath)) + }.asSuccess(diagnostics) } catch (e: Throwable) { ResultWithDiagnostics.Failure(*diagnostics.toTypedArray(), e.asDiagnostics()) } diff --git a/libraries/examples/scripting/jvm-simple-script/host/build.gradle.kts b/libraries/examples/scripting/jvm-simple-script/host/build.gradle.kts index 5bce82c817d..021de688e86 100644 --- a/libraries/examples/scripting/jvm-simple-script/host/build.gradle.kts +++ b/libraries/examples/scripting/jvm-simple-script/host/build.gradle.kts @@ -7,7 +7,6 @@ plugins { dependencies { compile(project(":examples:scripting-jvm-simple-script")) compile(project(":kotlin-scripting-jvm-host")) - compile(project(":kotlin-scripting-misc")) compile(project(":kotlin-script-util")) runtime(projectRuntimeJar(":kotlin-compiler")) testCompile(commonDep("junit")) diff --git a/libraries/examples/scripting/jvm-simple-script/host/src/org/jetbrains/kotlin/script/examples/jvm/simple/host/host.kt b/libraries/examples/scripting/jvm-simple-script/host/src/org/jetbrains/kotlin/script/examples/jvm/simple/host/host.kt index 001ee20a6c4..d37a93f5227 100644 --- a/libraries/examples/scripting/jvm-simple-script/host/src/org/jetbrains/kotlin/script/examples/jvm/simple/host/host.kt +++ b/libraries/examples/scripting/jvm-simple-script/host/src/org/jetbrains/kotlin/script/examples/jvm/simple/host/host.kt @@ -9,24 +9,25 @@ import org.jetbrains.kotlin.script.examples.jvm.simple.MyScript import java.io.File import kotlin.script.experimental.api.EvaluationResult import kotlin.script.experimental.api.ResultWithDiagnostics +import kotlin.script.experimental.api.ScriptCompileConfiguration import kotlin.script.experimental.api.ScriptEvaluationEnvironment -import kotlin.script.experimental.api.buildScriptingProperties import kotlin.script.experimental.host.toScriptSource -import kotlin.script.experimental.jvm.jvmDependenciesFromCurrentContext +import kotlin.script.experimental.jvm.dependenciesFromCurrentContext +import kotlin.script.experimental.jvm.jvm import kotlin.script.experimental.jvmhost.makeBasicHostFromAnnotatedScriptBaseClass fun evalFile(scriptFile: File): ResultWithDiagnostics { - val additionalCompilationProperties = buildScriptingProperties { - jvmDependenciesFromCurrentContext( - "scripting-jvm-simple-script" /* script library jar name */ - ) + val additionalCompilationProperties = ScriptCompileConfiguration.create { + jvm { + dependenciesFromCurrentContext( + "scripting-jvm-simple-script" /* script library jar name */ + ) + } } val host = makeBasicHostFromAnnotatedScriptBaseClass() - return host.eval( - scriptFile.toScriptSource(), additionalCompilationProperties, ScriptEvaluationEnvironment() - ) + return host.eval(scriptFile.toScriptSource(), additionalCompilationProperties, null) } fun main(vararg args: String) { diff --git a/libraries/scripting/common/src/kotlin/script/experimental/annotations/scriptAnnotations.kt b/libraries/scripting/common/src/kotlin/script/experimental/annotations/scriptAnnotations.kt index 44499d16d2b..502afa53260 100644 --- a/libraries/scripting/common/src/kotlin/script/experimental/annotations/scriptAnnotations.kt +++ b/libraries/scripting/common/src/kotlin/script/experimental/annotations/scriptAnnotations.kt @@ -13,14 +13,14 @@ package kotlin.script.experimental.annotations import kotlin.reflect.KClass -import kotlin.script.experimental.api.ScriptingProperties +import kotlin.script.experimental.api.ScriptDefinition @Target(AnnotationTarget.CLASS) @Retention(AnnotationRetention.RUNTIME) annotation class KotlinScript( val name: String = "Kotlin script", val extension: String = "kts", - val properties: KClass = ScriptingProperties::class // object or class filled in 0-ary constructor + val definition: KClass = ScriptDefinition.Default::class // object or class filled in 0-ary constructor ) @Target(AnnotationTarget.CLASS) @@ -29,15 +29,8 @@ annotation class KotlinScriptFileExtension( val extension: String ) -@Target(AnnotationTarget.CLASS) -@Retention(AnnotationRetention.RUNTIME) -@Deprecated("Use KotlinScriptProperties", replaceWith = ReplaceWith("KotlinScriptProperties")) -annotation class KotlinScriptPropertiesFromList( - val definitionProperties: KClass> // object or class filled in 0-ary constructor -) - @Target(AnnotationTarget.CLASS) @Retention(AnnotationRetention.RUNTIME) annotation class KotlinScriptProperties( - val definitionProperties: KClass // object or class filled in 0-ary constructor + val definition: KClass // object or class filled in 0-ary constructor ) diff --git a/libraries/scripting/common/src/kotlin/script/experimental/api/errorHandling.kt b/libraries/scripting/common/src/kotlin/script/experimental/api/errorHandling.kt index e90363d4d7c..904af5e5604 100644 --- a/libraries/scripting/common/src/kotlin/script/experimental/api/errorHandling.kt +++ b/libraries/scripting/common/src/kotlin/script/experimental/api/errorHandling.kt @@ -33,10 +33,11 @@ sealed class ResultWithDiagnostics { // call chaining -suspend fun ResultWithDiagnostics.onSuccess(body: suspend (R1) -> ResultWithDiagnostics): ResultWithDiagnostics = when (this) { - is ResultWithDiagnostics.Success -> this.reports + body(this.value) - is ResultWithDiagnostics.Failure -> this -} +suspend fun ResultWithDiagnostics.onSuccess(body: suspend (R1) -> ResultWithDiagnostics): ResultWithDiagnostics = + when (this) { + is ResultWithDiagnostics.Success -> this.reports + body(this.value) + is ResultWithDiagnostics.Failure -> this + } suspend fun ResultWithDiagnostics.onFailure(body: suspend (ResultWithDiagnostics) -> Unit): ResultWithDiagnostics { if (this is ResultWithDiagnostics.Failure) { @@ -52,7 +53,7 @@ operator fun List.plus(res: ResultWithDiagnostics): Res // results creation -fun R.asSuccess(reports: List = listOf()): ResultWithDiagnostics.Success = +fun R.asSuccess(reports: List = listOf()): ResultWithDiagnostics.Success = ResultWithDiagnostics.Success(this, reports) fun Throwable.asDiagnostics(customMessage: String? = null, location: ScriptSource.Location? = null): ScriptDiagnostic = diff --git a/libraries/scripting/common/src/kotlin/script/experimental/api/propertiesDsl.kt b/libraries/scripting/common/src/kotlin/script/experimental/api/propertiesDsl.kt deleted file mode 100644 index 0c32d9cdfeb..00000000000 --- a/libraries/scripting/common/src/kotlin/script/experimental/api/propertiesDsl.kt +++ /dev/null @@ -1,212 +0,0 @@ -/* - * Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license - * that can be found in the license/LICENSE.txt file. - */ - -package kotlin.script.experimental.api - -import kotlin.reflect.KClass -import kotlin.reflect.KProperty -import kotlin.reflect.KType -import kotlin.script.experimental.util.ChainedPropertyBag -import kotlin.script.experimental.util.TypedKey - -interface PropertiesGroup - - -open class PropertiesBuilder(val props: ScriptingProperties) - -class PropertiesBuilderDelegate(val kclass: KClass) { - operator fun getValue(thisRef: Any?, property: KProperty<*>): KClass = kclass -} - -inline fun propertiesBuilder() = PropertiesBuilderDelegate(T::class) - -fun buildScriptingProperties(body: ScriptingProperties.() -> Unit): ChainedPropertyBag = - ScriptingProperties(body).build() - -open class ScriptingProperties(body: ScriptingProperties.() -> Unit = {}) { - - var parentPropertiesBag: ChainedPropertyBag? = null - var parentPropertiesBuilder: ScriptingProperties? = null - val data = HashMap, Any?>() - - init { - body() - setupOnce() // TODO: does it work? - } - - private var isSetUp = false - fun setupOnce() { - if (!isSetUp) setup() - } - - open fun setup() {} - - fun build(): ChainedPropertyBag = - ChainedPropertyBag.createOptimized(parentPropertiesBag ?: parentPropertiesBuilder?.build(), data) - - // -------------------------- - // DSL: - - // generic invoke for properties groups, allowing to use syntax: - // PropertiesGroup { - // ... - // } - - inline operator fun T.invoke(body: T.() -> Unit) = body() - - // generic invoke for properties builder - for extending dsl with complex builders - - inline operator fun KClass.invoke(body: T.() -> Unit) { - constructors.first().call(this@ScriptingProperties).body() - } - - // chaining: - - private fun chain(propsBag: ChainedPropertyBag?, propsBuilder: ScriptingProperties?, replaceParent: Boolean) { - assert(propsBag == null || propsBuilder == null) - if (!replaceParent && parentPropertiesBag != null || parentPropertiesBuilder != null) - throw RuntimeException("Parent already defined for properties being build: ${parentPropertiesBag ?: parentPropertiesBuilder}") - parentPropertiesBag = propsBag - parentPropertiesBuilder = propsBuilder - } - - fun chain(props: ScriptingProperties, replaceParent: Boolean = false) { - chain(null, props, replaceParent) - } - - fun chain(props: ChainedPropertyBag, replaceParent: Boolean = false) { - chain(props, null, replaceParent) - } - - // inclusion: - - fun include(props: ScriptingProperties) { - props.setupOnce() - data.putAll(props.data) - } - - fun include(props: ChainedPropertyBag) { - data.putAll(props.data) - } - - // builders for known property types, allowing to use syntax - // propertyKey(value...) - // or - // propertyKey() - - // generic: - - inline operator fun TypedKey.invoke(v: T) { - data[this] = v - } - - // for KotlinType: - - inline operator fun TypedKey.invoke() { - data[this] = KotlinType(K::class) - } - - operator fun TypedKey.invoke(kclass: KClass<*>) { - data[this] = KotlinType(kclass) - } - - operator fun TypedKey.invoke(ktype: KType) { - data[this] = KotlinType(ktype) - } - - operator fun TypedKey.invoke(fqname: String) { - data[this] = KotlinType(fqname) - } - - // for list of KotlinTypes - - @JvmName("invoke_kotlintype_list_from_generic") - inline operator fun TypedKey>.invoke() { - data.addToListProperty(this, KotlinType(K::class)) - } - - operator fun TypedKey>.invoke(vararg classes: KClass<*>) { - data.addToListProperty(this, classes.map { KotlinType(it) }) - } - - operator fun TypedKey>.invoke(vararg types: KType) { - data.addToListProperty(this, types.map { KotlinType(it) }) - } - - operator fun TypedKey>.invoke(vararg fqnames: String) { - data.addToListProperty(this, fqnames.map { KotlinType(it) }) - } - - // generic for list - - inline operator fun TypedKey>.invoke(vararg vs: E) { - data.addToListProperty(this, vs.toList()) - } - - // for map of generic keys to KotlinTypes: - - @JvmName("invoke_kotlintype_map_from_kclass") - inline operator fun TypedKey>.invoke(vararg classes: Pair>) { - data.addToMapProperty(this, classes.map { (k, v) -> k to KotlinType(v) }) - } - - @JvmName("invoke_kotlintype_map_from_ktype") - inline operator fun TypedKey>.invoke(vararg types: Pair) { - data.addToMapProperty(this, types.map { (k, v) -> k to KotlinType(v) }) - } - - @JvmName("invoke_kotlintype_map_from_fqname") - inline operator fun TypedKey>.invoke(vararg fqnames: Pair) { - data.addToMapProperty(this, fqnames.map { (k, v) -> k to KotlinType(v) }) - } - - // generic for maps: - - inline operator fun TypedKey>.invoke(vararg vs: Pair) { - data.addToMapProperty(this, vs.asIterable()) - } - - // for strings and list of strings that could be converted from other types - - @JvmName("invoke_string_fqn_from_generic") - inline operator fun TypedKey.invoke() { - data[this] = K::class.qualifiedName!! - } - - @JvmName("invoke_string_fqn_from_reflected_class") - operator fun TypedKey.invoke(kclass: KClass<*>) { - data[this] = kclass.qualifiedName!! - } - - @JvmName("invoke_string_list_fqn_from_generic") - inline operator fun TypedKey>.invoke() { - data.addToListProperty(this, K::class.qualifiedName!!) - } - - @JvmName("invoke_string_list_fqn_from_reflected_class") - operator fun TypedKey>.invoke(vararg kclasses: KClass<*>) { - data.addToListProperty(this, kclasses.map { it.qualifiedName!! }) - } -} - -fun HashMap, Any?>.addToListProperty(key: TypedKey>, values: Iterable) { - val newValues = get(key)?.let { (it as List) + values } ?: values.toList() - put(key, newValues) -} - -fun HashMap, Any?>.addToListProperty(key: TypedKey>, vararg values: V) { - val newValues = get(key)?.let { (it as List) + values } ?: values.toList() - put(key, newValues) -} - -fun HashMap, Any?>.addToMapProperty(key: TypedKey>, values: Map) { - val newValues = get(key)?.let { (it as Map) + values } ?: values - put(key, newValues) -} - -fun HashMap, Any?>.addToMapProperty(key: TypedKey>, values: Iterable>) { - val newValues = get(key)?.let { (it as Map) + values } ?: values - put(key, newValues) -} diff --git a/libraries/scripting/common/src/kotlin/script/experimental/api/scriptCompilation.kt b/libraries/scripting/common/src/kotlin/script/experimental/api/scriptCompilation.kt index adc9ddb15fe..8db11211a79 100644 --- a/libraries/scripting/common/src/kotlin/script/experimental/api/scriptCompilation.kt +++ b/libraries/scripting/common/src/kotlin/script/experimental/api/scriptCompilation.kt @@ -17,7 +17,8 @@ interface ScriptCompiler { interface CompiledScript { - val configuration: ScriptCompileConfiguration + val definition: ScriptDefinition + val additionalConfiguration: ScriptCompileConfiguration? - suspend fun instantiate(scriptEvaluationEnvironment: ScriptEvaluationEnvironment): ResultWithDiagnostics + suspend fun instantiate(scriptEvaluationEnvironment: ScriptEvaluationEnvironment?): ResultWithDiagnostics } diff --git a/libraries/scripting/common/src/kotlin/script/experimental/api/scriptConfiguration.kt b/libraries/scripting/common/src/kotlin/script/experimental/api/scriptConfiguration.kt index d26cad682ef..5f1716c46e1 100644 --- a/libraries/scripting/common/src/kotlin/script/experimental/api/scriptConfiguration.kt +++ b/libraries/scripting/common/src/kotlin/script/experimental/api/scriptConfiguration.kt @@ -7,30 +7,54 @@ package kotlin.script.experimental.api -import kotlin.script.experimental.util.ChainedPropertyBag -import kotlin.script.experimental.util.typedKey +import kotlin.script.experimental.util.PropertiesCollection -typealias ScriptCompileConfiguration = ChainedPropertyBag +interface ScriptCompileConfiguration : PropertiesCollection { + + companion object : ScriptCompileConfiguration { -object ScriptCompileConfigurationProperties : PropertiesGroup { + class Builder internal constructor() : PropertiesCollection.Builder(), ScriptCompileConfiguration { + override val properties = data + } - val sourceFragments by typedKey>() + fun create(body: Builder.() -> Unit): ScriptCompileConfiguration = Builder().apply(body) + } } -val ScriptingProperties.compilationConfiguration get() = ScriptCompileConfigurationProperties +val ScriptCompileConfiguration.sourceFragments by PropertiesCollection.key>() -typealias ProcessedScriptData = ChainedPropertyBag +val ScriptCompileConfiguration.scriptBodyTarget by PropertiesCollection.keyCopy(ScriptDefinition.scriptBodyTarget) -object ProcessedScriptDataProperties : PropertiesGroup { - val foundAnnotations by typedKey>() +val ScriptCompileConfiguration.scriptImplicitReceivers by PropertiesCollection.keyCopy(ScriptDefinition.scriptImplicitReceivers) - val foundFragments by typedKey>() +val ScriptCompileConfiguration.contextVariables by PropertiesCollection.keyCopy(ScriptDefinition.contextVariables) + +val ScriptCompileConfiguration.defaultImports by PropertiesCollection.keyCopy(ScriptDefinition.defaultImports) + +val ScriptCompileConfiguration.restrictions by PropertiesCollection.keyCopy(ScriptDefinition.restrictions) + +val ScriptCompileConfiguration.importedScripts by PropertiesCollection.keyCopy(ScriptDefinition.importedScripts) + +val ScriptCompileConfiguration.dependencies by PropertiesCollection.keyCopy(ScriptDefinition.dependencies) + +val ScriptCompileConfiguration.compilerOptions by PropertiesCollection.keyCopy(ScriptDefinition.compilerOptions) + + +interface ProcessedScriptData : PropertiesCollection { + + companion object : ProcessedScriptData } +val ProcessedScriptData.foundAnnotations by PropertiesCollection.key>() + +val ProcessedScriptData.foundFragments by PropertiesCollection.key>() + + interface RefineScriptCompilationConfigurationHandler { suspend operator fun invoke( scriptSource: ScriptSource, - configuration: ScriptCompileConfiguration, - processedScriptData: ProcessedScriptData = ProcessedScriptData() - ): ResultWithDiagnostics + scriptDefinition: ScriptDefinition, + configuration: ScriptCompileConfiguration?, + processedScriptData: ProcessedScriptData? = null + ): ResultWithDiagnostics } diff --git a/libraries/scripting/common/src/kotlin/script/experimental/api/scriptDefinition.kt b/libraries/scripting/common/src/kotlin/script/experimental/api/scriptDefinition.kt index 82b8d48eb41..a1bffd70185 100644 --- a/libraries/scripting/common/src/kotlin/script/experimental/api/scriptDefinition.kt +++ b/libraries/scripting/common/src/kotlin/script/experimental/api/scriptDefinition.kt @@ -8,73 +8,73 @@ package kotlin.script.experimental.api import kotlin.reflect.KClass -import kotlin.script.experimental.util.ChainedPropertyBag -import kotlin.script.experimental.util.typedKey +import kotlin.script.experimental.util.PropertiesCollection -typealias ScriptDefinition = ChainedPropertyBag +interface ScriptDefinition : PropertiesCollection { -object ScriptDefinitionProperties : PropertiesGroup { + companion object : ScriptDefinition { - val name by typedKey() // Name of the script type, by default "Kotlin script" + class Builder internal constructor() : PropertiesCollection.Builder(), ScriptDefinition { + override val properties = data + } - val fileExtension by typedKey() // default: "kts" - - val baseClass by typedKey() // script base class - - val scriptBodyTarget by typedKey() - - val scriptImplicitReceivers by typedKey>() // in the order from outer to inner scope - - val contextVariables by typedKey>() // external variables - - val defaultImports by typedKey>() - - val restrictions by typedKey>() - - val importedScripts by typedKey>() - - val dependencies by typedKey>() - - val generatedClassAnnotations by typedKey>() - - val generatedMethodAnnotations by typedKey>() - - val compilerOptions by typedKey>() // Q: CommonCompilerOptions instead? - - val refineConfigurationHandler by typedKey() // dynamic configurator - - val refineConfigurationBeforeParsing by typedKey() // default: false - - val refineConfigurationOnAnnotations by typedKey>() - - val refineConfigurationOnSections by typedKey>() - - // DSL: - - val refineConfiguration by propertiesBuilder() -} - -// DSL -------------------- - -val ScriptingProperties.scriptDefinition get() = ScriptDefinitionProperties - -@Suppress("MemberVisibilityCanBePrivate") -class RefineConfigurationBuilder(props: ScriptingProperties) : PropertiesBuilder(props) { - - inline operator fun invoke(body: RefineConfigurationBuilder.() -> Unit) { - body() + fun create(body: Builder.() -> Unit): ScriptDefinition = Builder().apply(body) } + object Default : ScriptDefinition +} + +val ScriptDefinition.name by PropertiesCollection.key("Kotlin script") // Name of the script type + +val ScriptDefinition.fileExtension by PropertiesCollection.key("kts") // file extension + +val ScriptDefinition.baseClass by PropertiesCollection.key() // script base class + +val ScriptDefinition.scriptBodyTarget by PropertiesCollection.key(ScriptBodyTarget.Constructor) + +val ScriptDefinition.scriptImplicitReceivers by PropertiesCollection.key>() // in the order from outer to inner scope + +val ScriptDefinition.contextVariables by PropertiesCollection.key>() // external variables + +val ScriptDefinition.defaultImports by PropertiesCollection.key>() + +val ScriptDefinition.restrictions by PropertiesCollection.key>() + +val ScriptDefinition.importedScripts by PropertiesCollection.key>() + +val ScriptDefinition.dependencies by PropertiesCollection.key>() + +val ScriptDefinition.generatedClassAnnotations by PropertiesCollection.key>() + +val ScriptDefinition.generatedMethodAnnotations by PropertiesCollection.key>() + +val ScriptDefinition.compilerOptions by PropertiesCollection.key>() // Q: CommonCompilerOptions instead? + +val ScriptDefinition.refineConfigurationHandler by PropertiesCollection.key() // dynamic configurator + +val ScriptDefinition.refineConfigurationBeforeParsing by PropertiesCollection.key() // default: false + +val ScriptDefinition.refineConfigurationOnAnnotations by PropertiesCollection.key>() + +val ScriptDefinition.refineConfigurationOnSections by PropertiesCollection.key>() + +// DSL: + +val ScriptDefinition.refineConfiguration get() = RefineConfigurationBuilder() + + +class RefineConfigurationBuilder : PropertiesCollection.Builder() { + fun handler(fn: RefineScriptCompilationConfigurationHandler) { - props.data[ScriptDefinitionProperties.refineConfigurationHandler] = fn + set(ScriptDefinition.refineConfigurationHandler, fn) } fun triggerBeforeParsing(value: Boolean = true) { - props.data[ScriptDefinitionProperties.refineConfigurationBeforeParsing] = value + set(ScriptDefinition.refineConfigurationBeforeParsing, value) } fun triggerOnAnnotations(annotations: Iterable) { - props.data.addToListProperty(ScriptDefinitionProperties.refineConfigurationOnAnnotations, annotations) + ScriptDefinition.refineConfigurationOnAnnotations.append(annotations) } fun triggerOnAnnotations(vararg annotations: KotlinType) { @@ -90,11 +90,11 @@ class RefineConfigurationBuilder(props: ScriptingProperties) : PropertiesBuilder } fun triggerOnSections(sections: Iterable) { - props.data.addToListProperty(ScriptDefinitionProperties.refineConfigurationOnSections, sections) + ScriptDefinition.refineConfigurationOnSections.append(sections) } fun triggerOnSections(vararg sections: String) { - props.data.addToListProperty(ScriptDefinitionProperties.refineConfigurationOnSections, *sections) + ScriptDefinition.refineConfigurationOnSections.append(*sections) } } diff --git a/libraries/scripting/common/src/kotlin/script/experimental/api/scriptEvaluation.kt b/libraries/scripting/common/src/kotlin/script/experimental/api/scriptEvaluation.kt index af768633099..99d539244d7 100644 --- a/libraries/scripting/common/src/kotlin/script/experimental/api/scriptEvaluation.kt +++ b/libraries/scripting/common/src/kotlin/script/experimental/api/scriptEvaluation.kt @@ -7,20 +7,27 @@ package kotlin.script.experimental.api -import kotlin.script.experimental.util.ChainedPropertyBag -import kotlin.script.experimental.util.typedKey +import kotlin.script.experimental.util.PropertiesCollection -object ScriptEvaluationEnvironmentParams { - val implicitReceivers by typedKey>() +interface ScriptEvaluationEnvironment : PropertiesCollection { - val contextVariables by typedKey>() // external variables + companion object : ScriptEvaluationEnvironment { - val constructorArgs by typedKey>() + class Builder internal constructor() : PropertiesCollection.Builder(), ScriptEvaluationEnvironment { + override val properties = data + } - val runArgs by typedKey>() + fun create(body: Builder.() -> Unit): ScriptEvaluationEnvironment = Builder().apply(body) + } } -typealias ScriptEvaluationEnvironment = ChainedPropertyBag +val ScriptEvaluationEnvironment.implicitReceivers by PropertiesCollection.key>() + +val ScriptEvaluationEnvironment.contextVariables by PropertiesCollection.key>() // external variables + +val ScriptEvaluationEnvironment.constructorArgs by PropertiesCollection.key>() + +val ScriptEvaluationEnvironment.runArgs by PropertiesCollection.key>() sealed class ResultValue { class Value(val name: String, val value: Any?, val type: String) : ResultValue() { @@ -30,12 +37,12 @@ sealed class ResultValue { object Unit : ResultValue() } -data class EvaluationResult(val returnValue: ResultValue, val environment: ScriptEvaluationEnvironment) +data class EvaluationResult(val returnValue: ResultValue, val environment: ScriptEvaluationEnvironment?) interface ScriptEvaluator { suspend operator fun invoke( compiledScript: CompiledScript<*>, - scriptEvaluationEnvironment: ScriptEvaluationEnvironment + scriptEvaluationEnvironment: ScriptEvaluationEnvironment? ): ResultWithDiagnostics } diff --git a/libraries/scripting/common/src/kotlin/script/experimental/api/scriptingEnvironment.kt b/libraries/scripting/common/src/kotlin/script/experimental/api/scriptingEnvironment.kt index cb4ba40923a..52f66510d23 100644 --- a/libraries/scripting/common/src/kotlin/script/experimental/api/scriptingEnvironment.kt +++ b/libraries/scripting/common/src/kotlin/script/experimental/api/scriptingEnvironment.kt @@ -6,33 +6,38 @@ package kotlin.script.experimental.api import kotlin.reflect.KClass -import kotlin.script.experimental.util.ChainedPropertyBag -import kotlin.script.experimental.util.typedKey +import kotlin.script.experimental.util.PropertiesCollection +import kotlin.script.experimental.util.getOrNull -typealias ScriptingEnvironment = ChainedPropertyBag +interface ScriptingEnvironment : PropertiesCollection { -object ScriptingEnvironmentProperties : PropertiesGroup { + companion object : ScriptingEnvironment { - // should contain all dependencies needed for baseClass and compilationConfigurator - val configurationDependencies by typedKey>() + class Builder internal constructor() : PropertiesCollection.Builder(), ScriptingEnvironment { + override val properties = data + } - // do not use configurationDependencies as script dependencies, so only the dependencies defined by compilationConfigurator will be used - // (NOTE: in this case they should include the dependencies for the base class anyway, since this class is needed for script - // compilation and instantiation, but compilationConfigurator could be excluded) - val isolatedDependencies by typedKey(false) - - // a "class loader" for KotlinTypes - val getScriptingClass by typedKey() + fun create(body: Builder.() -> Unit): ScriptingEnvironment = Builder().apply(body) + } } -val ScriptingProperties.scriptingEnvironment get() = ScriptDefinitionProperties +// should contain all dependencies needed for baseClass and compilationConfigurator +val ScriptingEnvironment.configurationDependencies by PropertiesCollection.key>() + +// do not use configurationDependencies as script dependencies, so only the dependencies defined by compilationConfigurator will be used +// (NOTE: in this case they should include the dependencies for the base class anyway, since this class is needed for script +// compilation and instantiation, but compilationConfigurator could be excluded) +val ScriptingEnvironment.isolatedDependencies by PropertiesCollection.key(false) + +// a "class loader" for KotlinTypes +val ScriptingEnvironment.getScriptingClass by PropertiesCollection.key() interface GetScriptingClass { operator fun invoke(classType: KotlinType, contextClass: KClass<*>, environment: ScriptingEnvironment): KClass<*> } fun ScriptingEnvironment.getScriptingClass(type: KotlinType, contextClass: KClass<*>): KClass<*> { - val getClass = getOrNull(ScriptingEnvironmentProperties.getScriptingClass) + val getClass = getOrNull(ScriptingEnvironment.getScriptingClass) ?: throw IllegalArgumentException("Expecting 'getScriptingClass' property in the scripting environment: unable to load scripting class $type") return getClass(type, contextClass, this) } diff --git a/libraries/scripting/common/src/kotlin/script/experimental/definitions/definitionFromAnnotation.kt b/libraries/scripting/common/src/kotlin/script/experimental/definitions/definitionFromAnnotation.kt index 5a58b8c3899..16d1d0936e5 100644 --- a/libraries/scripting/common/src/kotlin/script/experimental/definitions/definitionFromAnnotation.kt +++ b/libraries/scripting/common/src/kotlin/script/experimental/definitions/definitionFromAnnotation.kt @@ -11,9 +11,8 @@ import kotlin.reflect.full.findAnnotation import kotlin.script.experimental.annotations.KotlinScript import kotlin.script.experimental.annotations.KotlinScriptFileExtension import kotlin.script.experimental.annotations.KotlinScriptProperties -import kotlin.script.experimental.annotations.KotlinScriptPropertiesFromList import kotlin.script.experimental.api.* -import kotlin.script.experimental.util.TypedKey +import kotlin.script.experimental.util.getOrNull private const val ERROR_MSG_PREFIX = "Unable to construct script definition: " @@ -26,7 +25,7 @@ fun createScriptDefinitionFromAnnotatedBaseClass( contextClass: KClass<*> = ScriptDefinition::class ): ScriptDefinition { - val getScriptingClass = environment.getOrNull(ScriptingEnvironmentProperties.getScriptingClass) + val getScriptingClass = environment.getOrNull(ScriptingEnvironment.getScriptingClass) ?: throw IllegalArgumentException("${ERROR_MSG_PREFIX}Expecting 'getScriptingClass' parameter in the scripting environment") val baseClass: KClass<*> = @@ -39,38 +38,24 @@ fun createScriptDefinitionFromAnnotatedBaseClass( val mainAnnotation = baseClass.findAnnotation() ?: throw IllegalArgumentException("${ERROR_MSG_PREFIX}Expecting KotlinScript annotation on the $baseClass") - val propertiesData = hashMapOf, Any?>(ScriptDefinitionProperties.baseClass to baseClassType) - - propertiesData[ScriptDefinitionProperties.fileExtension] = - baseClass.findAnnotation()?.let { it.extension } - ?: mainAnnotation.extension - propertiesData += ScriptDefinitionProperties.name to mainAnnotation.name - baseClass.annotations.filterIsInstance(KotlinScriptPropertiesFromList::class.java).forEach { ann -> - val params = try { - ann.definitionProperties.objectInstance ?: ann.definitionProperties.createInstance() - } catch (e: Throwable) { - throw IllegalArgumentException(ILLEGAL_CONFIG_ANN_ARG, e) - } - params.forEach { param -> - if (param !is Pair<*, *> || param.first !is TypedKey<*>) - throw IllegalArgumentException("$ILLEGAL_CONFIG_ANN_ARG: invalid parameter $param") - (param as Pair, Any?>).let { (k, v) -> - propertiesData[k] = v - } - } - } - - fun scriptingPropsInstance(kclass: KClass): ScriptingProperties = try { - kclass.objectInstance ?: kclass.createInstance().also { it.setupOnce() } + fun scriptingPropsInstance(kclass: KClass): ScriptDefinition = try { + kclass.objectInstance ?: kclass.createInstance() } catch (e: Throwable) { throw IllegalArgumentException(ILLEGAL_CONFIG_ANN_ARG, e) } - baseClass.annotations.filterIsInstance(KotlinScriptProperties::class.java).forEach { ann -> - propertiesData.putAll(scriptingPropsInstance(ann.definitionProperties).data) + return object : ScriptDefinition { + override val properties = properties { + baseClass(baseClassType) + fileExtension(baseClass.findAnnotation()?.extension ?: mainAnnotation.extension) + name(mainAnnotation.name) + + include(scriptingPropsInstance(mainAnnotation.definition)) + + baseClass.annotations.filterIsInstance(KotlinScriptProperties::class.java).forEach { ann -> + include(scriptingPropsInstance(ann.definition)) + } + } } - // TODO: chaining is lost here and above, fix it - propertiesData.putAll(scriptingPropsInstance(mainAnnotation.properties).data) - return ScriptingEnvironment.createOptimized(null, propertiesData) } diff --git a/libraries/scripting/common/src/kotlin/script/experimental/host/BasicScriptingHost.kt b/libraries/scripting/common/src/kotlin/script/experimental/host/BasicScriptingHost.kt index 1e42dfdceb0..08d286efb1d 100644 --- a/libraries/scripting/common/src/kotlin/script/experimental/host/BasicScriptingHost.kt +++ b/libraries/scripting/common/src/kotlin/script/experimental/host/BasicScriptingHost.kt @@ -31,8 +31,8 @@ abstract class BasicScriptingHost( open fun eval( script: ScriptSource, - compileConfiguration: ScriptCompileConfiguration, - environment: ScriptEvaluationEnvironment + compileConfiguration: ScriptCompileConfiguration?, + environment: ScriptEvaluationEnvironment? ): ResultWithDiagnostics = runInCoroutineContext { compiler(script, scriptDefinition, compileConfiguration).onSuccess { diff --git a/libraries/scripting/common/src/kotlin/script/experimental/host/scriptHostUtil.kt b/libraries/scripting/common/src/kotlin/script/experimental/host/scriptHostUtil.kt index 01190d4f575..a5117d9cde7 100644 --- a/libraries/scripting/common/src/kotlin/script/experimental/host/scriptHostUtil.kt +++ b/libraries/scripting/common/src/kotlin/script/experimental/host/scriptHostUtil.kt @@ -7,7 +7,11 @@ package kotlin.script.experimental.host import java.io.File import java.net.URL -import kotlin.script.experimental.api.* +import kotlin.script.experimental.api.ScriptCompileConfiguration +import kotlin.script.experimental.api.ScriptSource +import kotlin.script.experimental.api.ScriptSourceNamedFragment +import kotlin.script.experimental.api.sourceFragments +import kotlin.script.experimental.util.getOrNull fun ScriptSource.getScriptText(): String = when { text != null -> text!! @@ -16,9 +20,9 @@ fun ScriptSource.getScriptText(): String = when { else -> throw RuntimeException("unable to get text from null script") } -fun getMergedScriptText(script: ScriptSource, configuration: ScriptCompileConfiguration): String { +fun getMergedScriptText(script: ScriptSource, configuration: ScriptCompileConfiguration?): String { val originalScriptText = script.getScriptText() - val sourceFragments = configuration.getOrNull(ScriptCompileConfigurationProperties.sourceFragments) + val sourceFragments = configuration?.getOrNull(ScriptCompileConfiguration.sourceFragments) return if (sourceFragments == null || sourceFragments.isEmpty()) { originalScriptText } else { diff --git a/libraries/scripting/common/src/kotlin/script/experimental/repl/replEvaluation.kt b/libraries/scripting/common/src/kotlin/script/experimental/repl/replEvaluation.kt index 6c1c9bb3e5a..30e2471ff0e 100644 --- a/libraries/scripting/common/src/kotlin/script/experimental/repl/replEvaluation.kt +++ b/libraries/scripting/common/src/kotlin/script/experimental/repl/replEvaluation.kt @@ -7,15 +7,20 @@ package kotlin.script.experimental.repl import kotlin.script.experimental.api.EvaluationResult import kotlin.script.experimental.api.ResultWithDiagnostics -import kotlin.script.experimental.util.ChainedPropertyBag +import kotlin.script.experimental.util.PropertiesCollection +interface ReplEvaluationEnvironment : PropertiesCollection { -object ReplEvaluationEnvironmentParams { + companion object : ReplEvaluationEnvironment { + class Builder internal constructor() : PropertiesCollection.Builder(), ReplEvaluationEnvironment { + override val properties = data + } + + fun create(body: Builder.() -> Unit): ReplEvaluationEnvironment = Builder().apply(body) + } } -typealias ReplEvaluationEnvironment = ChainedPropertyBag - interface ReplSnippetEvaluator { suspend operator fun invoke( diff --git a/libraries/scripting/common/src/kotlin/script/experimental/repl/replHost.kt b/libraries/scripting/common/src/kotlin/script/experimental/repl/replHost.kt index 4c4b3b94628..40411324f5c 100644 --- a/libraries/scripting/common/src/kotlin/script/experimental/repl/replHost.kt +++ b/libraries/scripting/common/src/kotlin/script/experimental/repl/replHost.kt @@ -11,8 +11,7 @@ import kotlin.script.experimental.api.EvaluationResult import kotlin.script.experimental.api.ResultWithDiagnostics import kotlin.script.experimental.api.ScriptCompileConfiguration import kotlin.script.experimental.api.ScriptDefinition -import kotlin.script.experimental.util.ChainedPropertyBag -import kotlin.script.experimental.util.typedKey +import kotlin.script.experimental.util.PropertiesCollection interface ReplCommandProcessor { suspend operator fun invoke( @@ -23,12 +22,19 @@ interface ReplCommandProcessor { data class ReplCommand(val commandName: String, val processor: ReplCommandProcessor) -object ReplHostEnvironmentParams { +interface ReplHostEnvironment : PropertiesCollection { - val replCommands by typedKey>() + companion object : ReplHostEnvironment { + + class Builder internal constructor() : PropertiesCollection.Builder(), ReplHostEnvironment { + override val properties = data + } + + fun create(body: Builder.() -> Unit): ReplHostEnvironment = Builder().apply(body) + } } -typealias ReplHostEnvironment = ChainedPropertyBag +val ReplHostEnvironment.replCommands by PropertiesCollection.key>() abstract class ReplHost( val environment: ReplHostEnvironment, diff --git a/libraries/scripting/common/src/kotlin/script/experimental/util/propertiesCollection.kt b/libraries/scripting/common/src/kotlin/script/experimental/util/propertiesCollection.kt new file mode 100644 index 00000000000..21387306246 --- /dev/null +++ b/libraries/scripting/common/src/kotlin/script/experimental/util/propertiesCollection.kt @@ -0,0 +1,208 @@ +/* + * Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license + * that can be found in the license/LICENSE.txt file. + */ + +package kotlin.script.experimental.util + +import kotlin.reflect.KClass +import kotlin.reflect.KProperty +import kotlin.reflect.KType +import kotlin.script.experimental.api.KotlinType + +interface PropertiesCollection { + + val properties: Map, Any> get() = emptyMap() + + data class Key(val name: String, val defaultValue: T? = null) + + class PropertyKeyDelegate(private val defaultValue: T? = null) { + operator fun getValue(thisRef: Any?, property: KProperty<*>): Key = + Key(property.name, defaultValue) + } + + class PropertyKeyCopyDelegate(val source: Key) { + operator fun getValue(thisRef: Any?, property: KProperty<*>): Key = source + } + + companion object { + fun key(defaultValue: T? = null) = PropertyKeyDelegate(defaultValue) + fun keyCopy(source: Key) = PropertyKeyCopyDelegate(source) + } + + fun properties(body: Builder.() -> Unit): Map, Any> = Builder().apply(body).data + + // properties builder base class (DSL for building properties collection) + + open class Builder { + + val data: MutableMap, Any> = LinkedHashMap() + + // generic builder for all properties + operator fun PropertiesCollection.Key.invoke(v: T) { + set(this, v) + } + + // generic for lists + + operator fun PropertiesCollection.Key>.invoke(vararg vals: T) { + append(vals.asIterable()) + } + + // generic for maps: + + operator fun PropertiesCollection.Key>.invoke(vararg vs: Pair) { + append(vs.asIterable()) + } + + // for strings and list of strings that could be converted from other types + + @JvmName("invoke_string_fqn_from_generic") + inline operator fun PropertiesCollection.Key.invoke() { + set(this, K::class.qualifiedName!!) + } + + @JvmName("invoke_string_fqn_from_reflected_class") + operator fun PropertiesCollection.Key.invoke(kclass: KClass<*>) { + set(this, kclass.qualifiedName!!) + } + + @JvmName("invoke_string_list_fqn_from_generic") + inline operator fun PropertiesCollection.Key>.invoke() { + append(K::class.qualifiedName!!) + } + + @JvmName("invoke_string_list_fqn_from_reflected_class") + operator fun PropertiesCollection.Key>.invoke(vararg kclasses: KClass<*>) { + append(kclasses.map { it.qualifiedName!! }) + } + + // for KotlinType: + + inline operator fun PropertiesCollection.Key.invoke() { + set(this, KotlinType(K::class)) + } + + operator fun PropertiesCollection.Key.invoke(kclass: KClass<*>) { + data[this] = KotlinType(kclass) + } + + operator fun PropertiesCollection.Key.invoke(ktype: KType) { + data[this] = KotlinType(ktype) + } + + operator fun PropertiesCollection.Key.invoke(fqname: String) { + data[this] = KotlinType(fqname) + } + + // for list of KotlinTypes + + @JvmName("invoke_kotlintype_list_from_generic") + inline operator fun PropertiesCollection.Key>.invoke() { + append(KotlinType(K::class)) + } + + operator fun PropertiesCollection.Key>.invoke(vararg classes: KClass<*>) { + append(classes.map { KotlinType(it) }) + } + + operator fun PropertiesCollection.Key>.invoke(vararg types: KType) { + append(types.map { KotlinType(it) }) + } + + operator fun PropertiesCollection.Key>.invoke(vararg fqnames: String) { + append(fqnames.map { KotlinType(it) }) + } + + // for map of generic keys to KotlinTypes: + + @JvmName("invoke_kotlintype_map_from_kclass") + operator fun PropertiesCollection.Key>.invoke(vararg classes: Pair>) { + append(classes.map { (k, v) -> k to KotlinType(v) }) + } + + @JvmName("invoke_kotlintype_map_from_ktype") + operator fun PropertiesCollection.Key>.invoke(vararg types: Pair) { + append(types.map { (k, v) -> k to KotlinType(v) }) + } + + @JvmName("invoke_kotlintype_map_from_fqname") + operator fun PropertiesCollection.Key>.invoke(vararg fqnames: Pair) { + append(fqnames.map { (k, v) -> k to KotlinType(v) }) + } + + // direct manipulation - public - for usage in inline dsl methods and for extending dsl + + operator fun set(key: PropertiesCollection.Key, value: T) { + data[key] = value + } + + @Suppress("UNCHECKED_CAST") + operator fun get(key: PropertiesCollection.Key): T? = data[key]?.let { it as T } + + // appenders to list and map properties + + @JvmName("appendToList") + fun PropertiesCollection.Key>.append(values: Iterable) { + val newValues = get(this)?.let { it + values } ?: values.toList() + data[this] = newValues + } + + fun PropertiesCollection.Key>.append(vararg values: V) { + val newValues = get(this)?.let { it + values } ?: values.toList() + data[this] = newValues + } + + fun PropertiesCollection.Key>.append(values: Map) { + val newValues = get(this)?.let { it + values } ?: values + data[this] = newValues + } + + @JvmName("appendToMap") + fun PropertiesCollection.Key>.append(values: Iterable>) { + val newValues = get(this)?.let { it + values } ?: values + data[this] = newValues + } + + // include other properties + fun include(other: PropertiesCollection?) { + other?.properties?.let { data.putAll(it) } + } + + // include another builder + operator fun T.invoke(body: T.() -> Unit) { + this.body() + this@Builder.data.putAll(this.data) + } + } +} + +@Suppress("UNCHECKED_CAST") +fun PropertiesCollection.getOrNull(key: PropertiesCollection.Key): T? = + properties[key]?.let { it as T } ?: key.defaultValue + +fun PropertiesCollection.getOrError(key: PropertiesCollection.Key): T = + getOrNull(key) ?: throw IllegalArgumentException("Unknown key $key") + +@Suppress("UNCHECKED_CAST") +fun getFirstFromChainOrNull(key: PropertiesCollection.Key, vararg propertyCollections: PropertiesCollection?): T? { + for (collection in propertyCollections) { + val value = collection?.properties?.get(key) + if (value != null) return value as T + } + return key.defaultValue +} + +@Suppress("UNCHECKED_CAST") +fun getMergedFromChainOrNull(key: PropertiesCollection.Key>, vararg propertyCollections: PropertiesCollection?): List? { + var found = false + val res = ArrayList() + for (collection in propertyCollections) { + val value = collection?.properties?.get(key) + if (value != null) { + found = true + res.addAll(value as List) + } + } + return if (found) res else key.defaultValue +} diff --git a/libraries/scripting/common/src/kotlin/script/experimental/util/propertyBag.kt b/libraries/scripting/common/src/kotlin/script/experimental/util/propertyBag.kt deleted file mode 100644 index 91de6a1ba51..00000000000 --- a/libraries/scripting/common/src/kotlin/script/experimental/util/propertyBag.kt +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright 2010-2018 JetBrains s.r.o. 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("unused") - -package kotlin.script.experimental.util - -import kotlin.reflect.KProperty - -data class TypedKey(val name: String, val defaultValue: T? = null) - -class TypedKeyDelegate(val defaultValue: T? = null) { - operator fun getValue(thisRef: Any?, property: KProperty<*>): TypedKey = TypedKey(property.name, defaultValue) -} - -fun typedKey(defaultValue: T? = null) = TypedKeyDelegate(defaultValue) - -open class ChainedPropertyBag internal constructor(private val parent: ChainedPropertyBag?, internal val data: Map, Any?>) { - constructor(parent: ChainedPropertyBag? = null, pairs: Iterable, Any?>>) : - this(parent, HashMap, Any?>().also { it.putAll(pairs) }) - - constructor(pairs: Iterable, Any?>>) : this(null, pairs) - constructor(parent: ChainedPropertyBag, vararg pairs: Pair, Any?>) : this(parent, pairs.asIterable()) - constructor(vararg pairs: Pair, Any?>) : this(null, pairs.asIterable()) - - fun cloneWithNewParent(newParent: ChainedPropertyBag?): ChainedPropertyBag = when { - this == newParent -> this - newParent == null -> this - parent == null -> createOptimized(newParent, data) - else -> createOptimized(parent.cloneWithNewParent(newParent), data) - } - - inline operator fun get(key: TypedKey): T = getRaw(key) as T - - fun getRaw(key: TypedKey): Any? = getOrNullRaw(key) ?: throw IllegalArgumentException("Unknown key $key") - - inline fun getOrNull(key: TypedKey): T? = getOrNullRaw(key)?.let { it as T } - - fun getOrNullRaw(key: TypedKey): Any? = data[key] ?: parent?.getOrNullRaw(key) ?: key.defaultValue - - companion object { - fun createOptimized(parent: ChainedPropertyBag?, data: Map, Any?>): ChainedPropertyBag = when { - parent != null && data.isEmpty() -> parent - parent != null && parent.data.isEmpty() -> createOptimized(parent.parent, data) - else -> ChainedPropertyBag(parent, data) - } - } -} - -fun chainPropertyBags(propertyBags: Iterable): ChainedPropertyBag = - propertyBags.fold(ChainedPropertyBag()) { res, next -> if (next == null) res else res.cloneWithNewParent(next) } - -fun chainPropertyBags(vararg propertyBags: ChainedPropertyBag?): ChainedPropertyBag = chainPropertyBags(propertyBags.asIterable()) diff --git a/libraries/scripting/jvm-host/src/kotlin/script/experimental/jvmhost/impl/KJVMCompilerImpl.kt b/libraries/scripting/jvm-host/src/kotlin/script/experimental/jvmhost/impl/KJVMCompilerImpl.kt index b9d814c2b2f..c4044c3d780 100644 --- a/libraries/scripting/jvm-host/src/kotlin/script/experimental/jvmhost/impl/KJVMCompilerImpl.kt +++ b/libraries/scripting/jvm-host/src/kotlin/script/experimental/jvmhost/impl/KJVMCompilerImpl.kt @@ -40,21 +40,28 @@ import kotlin.script.experimental.api.* import kotlin.script.experimental.dependencies.DependenciesResolver import kotlin.script.experimental.host.getMergedScriptText import kotlin.script.experimental.jvm.JvmDependency -import kotlin.script.experimental.jvm.JvmScriptCompileConfigurationProperties +import kotlin.script.experimental.jvm.JvmScriptCompilationConfiguration import kotlin.script.experimental.jvm.impl.BridgeDependenciesResolver -import kotlin.script.experimental.jvmhost.JvmScriptEvaluationEnvironmentProperties +import kotlin.script.experimental.jvm.javaHome +import kotlin.script.experimental.jvmhost.JvmScriptEvaluationEnvironment import kotlin.script.experimental.jvmhost.KJvmCompilerProxy -import kotlin.script.experimental.util.chainPropertyBags +import kotlin.script.experimental.jvmhost.baseClassLoader +import kotlin.script.experimental.util.getFirstFromChainOrNull +import kotlin.script.experimental.util.getMergedFromChainOrNull +import kotlin.script.experimental.util.getOrError +import kotlin.script.experimental.util.getOrNull class KJvmCompiledScript( - override val configuration: ScriptCompileConfiguration, - val generationState: GenerationState, - val scriptClassFQName: String + override val definition: ScriptDefinition, + override val additionalConfiguration: ScriptCompileConfiguration?, + private val generationState: GenerationState, + private val scriptClassFQName: String ) : CompiledScript { - override suspend fun instantiate(scriptEvaluationEnvironment: ScriptEvaluationEnvironment): ResultWithDiagnostics = try { - val baseClassLoader = scriptEvaluationEnvironment.getOrNull(JvmScriptEvaluationEnvironmentProperties.baseClassLoader) - val dependencies = configuration.getOrNull(ScriptDefinitionProperties.dependencies) + override suspend fun instantiate(scriptEvaluationEnvironment: ScriptEvaluationEnvironment?): ResultWithDiagnostics = try { + val baseClassLoader = scriptEvaluationEnvironment?.getOrNull(JvmScriptEvaluationEnvironment.baseClassLoader) + ?: Thread.currentThread().contextClassLoader + val dependencies = additionalConfiguration?.getOrNull(ScriptDefinition.dependencies) ?.flatMap { (it as? JvmDependency)?.classpath?.map { it.toURI().toURL() } ?: emptyList() } // TODO: previous dependencies and classloaders should be taken into account here val classLoaderWithDeps = @@ -75,7 +82,7 @@ class KJvmCompilerImpl(val hostEnvironment: ScriptingEnvironment) : KJvmCompiler override fun compile( script: ScriptSource, scriptDefinition: ScriptDefinition, - additionalConfiguration: ScriptCompileConfiguration + additionalConfiguration: ScriptCompileConfiguration? ): ResultWithDiagnostics> { val messageCollector = ScriptDiagnosticsMessageCollector() @@ -85,37 +92,35 @@ class KJvmCompilerImpl(val hostEnvironment: ScriptingEnvironment) : KJvmCompiler try { setIdeaIoUseFallback() - val scriptCompileConfiguration = chainPropertyBags(additionalConfiguration, scriptDefinition) var environment: KotlinCoreEnvironment? = null - var updatedScriptCompileConfiguration = scriptCompileConfiguration + var updatedScriptCompileConfiguration = additionalConfiguration fun updateClasspath(classpath: List) { environment!!.updateClasspath(classpath.map(::JvmClasspathRoot)) - val updatedDeps = updatedScriptCompileConfiguration.getOrNull(ScriptDefinitionProperties.dependencies)?.plus( - JvmDependency(classpath) - ) ?: listOf(JvmDependency(classpath)) - updatedScriptCompileConfiguration = ScriptCompileConfiguration( - updatedScriptCompileConfiguration, - ScriptDefinitionProperties.dependencies to updatedDeps - ) + if (classpath.isNotEmpty()) { + updatedScriptCompileConfiguration = ScriptCompileConfiguration.create { + include(updatedScriptCompileConfiguration) + dependencies.append(JvmDependency(classpath)) + } + } } val disposable = Disposer.newDisposable() val kotlinCompilerConfiguration = org.jetbrains.kotlin.config.CompilerConfiguration().apply { add( JVMConfigurationKeys.SCRIPT_DEFINITIONS, - BridgeScriptDefinition(scriptDefinition, scriptCompileConfiguration, hostEnvironment, ::updateClasspath) + BridgeScriptDefinition(scriptDefinition, additionalConfiguration, hostEnvironment, ::updateClasspath) ) put(CLIConfigurationKeys.MESSAGE_COLLECTOR_KEY, messageCollector) put(JVMConfigurationKeys.RETAIN_OUTPUT_IN_MEMORY, true) var isModularJava = false - scriptCompileConfiguration.getOrNull(JvmScriptCompileConfigurationProperties.javaHomeDir)?.let { + getFirstFromChainOrNull(JvmScriptCompilationConfiguration.javaHome, updatedScriptCompileConfiguration, hostEnvironment)?.let { put(JVMConfigurationKeys.JDK_HOME, it) isModularJava = CoreJrtFileSystem.isModularJdk(it) } - scriptCompileConfiguration.getOrNull(ScriptDefinitionProperties.dependencies)?.let { + getMergedFromChainOrNull(ScriptDefinition.dependencies, scriptDefinition, updatedScriptCompileConfiguration)?.let { addJvmClasspathRoots( it.flatMap { (it as JvmDependency).classpath @@ -147,7 +152,7 @@ class KJvmCompilerImpl(val hostEnvironment: ScriptingEnvironment) : KJvmCompiler val analyzerWithCompilerReport = AnalyzerWithCompilerReport(messageCollector, environment.configuration.languageVersionSettings) val psiFileFactory: PsiFileFactoryImpl = PsiFileFactory.getInstance(environment.project) as PsiFileFactoryImpl - val scriptText = getMergedScriptText(script, scriptCompileConfiguration) + val scriptText = getMergedScriptText(script, updatedScriptCompileConfiguration) val scriptFileName = "script" // TODO: extract from file/url if available val virtualFile = LightVirtualFile( "$scriptFileName${KotlinParserDefinition.STD_SCRIPT_EXT}", @@ -192,7 +197,7 @@ class KJvmCompilerImpl(val hostEnvironment: ScriptingEnvironment) : KJvmCompiler org.jetbrains.kotlin.codegen.CompilationErrorHandler.THROW_EXCEPTION ) - val res = KJvmCompiledScript(updatedScriptCompileConfiguration, generationState, scriptFileName.capitalize()) + val res = KJvmCompiledScript(scriptDefinition, updatedScriptCompileConfiguration, generationState, scriptFileName.capitalize()) return ResultWithDiagnostics.Success(res, messageCollector.diagnostics) } catch (ex: Throwable) { @@ -238,23 +243,22 @@ class ScriptDiagnosticsMessageCollector : MessageCollector { internal class BridgeScriptDefinition( scriptDefinition: ScriptDefinition, - calculatedScriptCompilerConfiguration: ScriptCompileConfiguration, + additionalCompilationConfiguration: ScriptCompileConfiguration?, hostEnvironment: ScriptingEnvironment, updateClasspath: (List) -> Unit ) : KotlinScriptDefinition( hostEnvironment.getScriptingClass( - scriptDefinition[ScriptDefinitionProperties.baseClass], + scriptDefinition.getOrError(ScriptDefinition.baseClass), BridgeScriptDefinition::class ) ) { override val acceptedAnnotations = run { val cl = this::class.java.classLoader - calculatedScriptCompilerConfiguration.getOrNull(ScriptDefinitionProperties.refineConfigurationOnAnnotations) + additionalCompilationConfiguration?.getOrNull(ScriptDefinition.refineConfigurationOnAnnotations) ?.map { (cl.loadClass(it.typeName) as Class).kotlin } ?: emptyList() } override val dependencyResolver: DependenciesResolver = - BridgeDependenciesResolver(scriptDefinition, calculatedScriptCompilerConfiguration, updateClasspath) + BridgeDependenciesResolver(scriptDefinition, additionalCompilationConfiguration, updateClasspath) } - diff --git a/libraries/scripting/jvm-host/src/kotlin/script/experimental/jvmhost/impl/jvmHostUtil.kt b/libraries/scripting/jvm-host/src/kotlin/script/experimental/jvmhost/impl/jvmHostUtil.kt new file mode 100644 index 00000000000..943df4772a8 --- /dev/null +++ b/libraries/scripting/jvm-host/src/kotlin/script/experimental/jvmhost/impl/jvmHostUtil.kt @@ -0,0 +1,35 @@ +/* + * Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license + * that can be found in the license/LICENSE.txt file. + */ + +package kotlin.script.experimental.jvmhost.impl + +import kotlin.script.experimental.api.ScriptCompileConfiguration +import kotlin.script.experimental.api.ScriptingEnvironment +import kotlin.script.experimental.jvm.defaultJvmScriptingEnvironment + +internal fun mergeConfigurations(vararg configurations: ScriptCompileConfiguration?): ScriptCompileConfiguration? { + val nonEmptyConfigurations = configurations.filter { it != null && it.properties.isNotEmpty() } + return when { + nonEmptyConfigurations.isEmpty() -> null + nonEmptyConfigurations.size == 1 -> nonEmptyConfigurations.first()!! + else -> ScriptCompileConfiguration.create { + for (configuration in nonEmptyConfigurations) { + include(configuration!!) + } + } + } +} + +fun ScriptingEnvironment.withDefaults(): ScriptingEnvironment = + if (this == defaultJvmScriptingEnvironment || defaultJvmScriptingEnvironment.properties.all { + this.properties.containsKey(it.key) + }) { + this + } else { + ScriptingEnvironment.create { + include(defaultJvmScriptingEnvironment) + include(this) + } + } diff --git a/libraries/scripting/jvm-host/src/kotlin/script/experimental/jvmhost/jvmScriptCompilation.kt b/libraries/scripting/jvm-host/src/kotlin/script/experimental/jvmhost/jvmScriptCompilation.kt index 7955d8db9d1..ae69f09236d 100644 --- a/libraries/scripting/jvm-host/src/kotlin/script/experimental/jvmhost/jvmScriptCompilation.kt +++ b/libraries/scripting/jvm-host/src/kotlin/script/experimental/jvmhost/jvmScriptCompilation.kt @@ -10,21 +10,29 @@ package kotlin.script.experimental.jvmhost import kotlin.script.experimental.api.* import kotlin.script.experimental.jvm.defaultJvmScriptingEnvironment import kotlin.script.experimental.jvmhost.impl.KJvmCompilerImpl -import kotlin.script.experimental.util.chainPropertyBags +import kotlin.script.experimental.jvmhost.impl.mergeConfigurations +import kotlin.script.experimental.jvmhost.impl.withDefaults +import kotlin.script.experimental.util.getOrNull interface CompiledJvmScriptsCache { - fun get(script: ScriptSource, configuration: ScriptCompileConfiguration): CompiledScript<*>? - fun store(compiledScript: CompiledScript<*>, configuration: ScriptCompileConfiguration) + fun get(script: ScriptSource, scriptDefinition: ScriptDefinition, configuration: ScriptCompileConfiguration?): CompiledScript<*>? + fun store(compiledScript: CompiledScript<*>, scriptDefinition: ScriptDefinition, configuration: ScriptCompileConfiguration?) object NoCache : CompiledJvmScriptsCache { - override fun get(script: ScriptSource, configuration: ScriptCompileConfiguration): CompiledScript<*>? = null - override fun store(compiledScript: CompiledScript<*>, configuration: ScriptCompileConfiguration) {} + override fun get( + script: ScriptSource, scriptDefinition: ScriptDefinition, configuration: ScriptCompileConfiguration? + ): CompiledScript<*>? = null + + override fun store( + compiledScript: CompiledScript<*>, scriptDefinition: ScriptDefinition, configuration: ScriptCompileConfiguration? + ) { + } } } open class JvmScriptCompiler( hostEnvironment: ScriptingEnvironment = defaultJvmScriptingEnvironment, - val compilerProxy: KJvmCompilerProxy = KJvmCompilerImpl(hostEnvironment.cloneWithNewParent(defaultJvmScriptingEnvironment)), + val compilerProxy: KJvmCompilerProxy = KJvmCompilerImpl(hostEnvironment.withDefaults()), val cache: CompiledJvmScriptsCache = CompiledJvmScriptsCache.NoCache ) : ScriptCompiler { @@ -33,29 +41,29 @@ open class JvmScriptCompiler( scriptDefinition: ScriptDefinition, additionalConfiguration: ScriptCompileConfiguration? ): ResultWithDiagnostics> { - val baseConfiguration = chainPropertyBags(additionalConfiguration, scriptDefinition) - val refineConfigurationFn = baseConfiguration.getOrNull(ScriptDefinitionProperties.refineConfigurationHandler) + val refineConfigurationFn = scriptDefinition.getOrNull(ScriptDefinition.refineConfigurationHandler) val refinedConfiguration = - if (baseConfiguration.getOrNull(ScriptDefinitionProperties.refineConfigurationBeforeParsing) == true) { + if (scriptDefinition.getOrNull(ScriptDefinition.refineConfigurationBeforeParsing) == true) { if (refineConfigurationFn == null) { return ResultWithDiagnostics.Failure("Non-null configurator expected".asErrorDiagnostics()) } - refineConfigurationFn(script, baseConfiguration).let { + refineConfigurationFn(script, scriptDefinition, additionalConfiguration).let { when (it) { is ResultWithDiagnostics.Failure -> return it is ResultWithDiagnostics.Success -> it.value } } } else { - baseConfiguration + null } - val cached = cache.get(script, refinedConfiguration) + val actualConfiguration = mergeConfigurations(additionalConfiguration, refinedConfiguration) + val cached = cache.get(script, scriptDefinition, actualConfiguration) if (cached != null) return cached.asSuccess() - return compilerProxy.compile(script, scriptDefinition, refinedConfiguration).also { + return compilerProxy.compile(script, scriptDefinition, actualConfiguration).also { if (it is ResultWithDiagnostics.Success) { - cache.store(it.value, refinedConfiguration) + cache.store(it.value, scriptDefinition, actualConfiguration) } } } @@ -65,7 +73,7 @@ interface KJvmCompilerProxy { fun compile( script: ScriptSource, scriptDefinition: ScriptDefinition, - additionalConfiguration: ScriptCompileConfiguration + additionalConfiguration: ScriptCompileConfiguration? ): ResultWithDiagnostics> } diff --git a/libraries/scripting/jvm-host/src/kotlin/script/experimental/jvmhost/jvmScriptEvaluation.kt b/libraries/scripting/jvm-host/src/kotlin/script/experimental/jvmhost/jvmScriptEvaluation.kt index 290ffcba1c6..90d47cea765 100644 --- a/libraries/scripting/jvm-host/src/kotlin/script/experimental/jvmhost/jvmScriptEvaluation.kt +++ b/libraries/scripting/jvm-host/src/kotlin/script/experimental/jvmhost/jvmScriptEvaluation.kt @@ -8,17 +8,23 @@ package kotlin.script.experimental.jvmhost import kotlin.script.experimental.api.* -import kotlin.script.experimental.util.typedKey +import kotlin.script.experimental.util.PropertiesCollection +import kotlin.script.experimental.util.getOrNull -object JvmScriptEvaluationEnvironmentProperties { - val baseClassLoader by typedKey(Thread.currentThread().contextClassLoader) +open class JvmScriptEvaluationEnvironment : PropertiesCollection.Builder() { + + companion object : JvmScriptEvaluationEnvironment() } +val JvmScriptEvaluationEnvironment.baseClassLoader by PropertiesCollection.key(Thread.currentThread().contextClassLoader) + +val ScriptEvaluationEnvironment.jvm get() = JvmScriptEvaluationEnvironment() + open class BasicJvmScriptEvaluator : ScriptEvaluator { override suspend operator fun invoke( compiledScript: CompiledScript<*>, - scriptEvaluationEnvironment: ScriptEvaluationEnvironment + scriptEvaluationEnvironment: ScriptEvaluationEnvironment? ): ResultWithDiagnostics = try { val obj = compiledScript.instantiate(scriptEvaluationEnvironment) @@ -32,7 +38,7 @@ open class BasicJvmScriptEvaluator : ScriptEvaluator { if (scriptObject !is Class<*>) ResultWithDiagnostics.Failure(ScriptDiagnostic("expecting class in this implementation, got ${scriptObject?.javaClass}")) else { - val receivers = scriptEvaluationEnvironment.getOrNull(ScriptEvaluationEnvironmentParams.implicitReceivers) + val receivers = scriptEvaluationEnvironment?.getOrNull(ScriptEvaluationEnvironment.implicitReceivers) val instance = if (receivers == null) { scriptObject.getConstructor().newInstance() } else { diff --git a/libraries/scripting/jvm/src/kotlin/script/experimental/jvm/impl/BridgeDependenciesResolver.kt b/libraries/scripting/jvm/src/kotlin/script/experimental/jvm/impl/BridgeDependenciesResolver.kt index d0167c00922..663a7aaf574 100644 --- a/libraries/scripting/jvm/src/kotlin/script/experimental/jvm/impl/BridgeDependenciesResolver.kt +++ b/libraries/scripting/jvm/src/kotlin/script/experimental/jvm/impl/BridgeDependenciesResolver.kt @@ -18,10 +18,12 @@ import kotlin.script.experimental.host.toScriptSource import kotlin.script.experimental.jvm.JvmDependency import kotlin.script.experimental.jvm.compat.mapToLegacyScriptReportPosition import kotlin.script.experimental.jvm.compat.mapToLegacyScriptReportSeverity +import kotlin.script.experimental.util.getFirstFromChainOrNull +import kotlin.script.experimental.util.getOrNull class BridgeDependenciesResolver( val scriptDefinition: ScriptDefinition, - val calculatedBaseScriptCompilerConfiguration: ScriptCompileConfiguration, + private val additionalConfiguration: ScriptCompileConfiguration?, val onClasspathUpdated: (List) -> Unit = {} ) : AsyncDependenciesResolver { @@ -34,14 +36,19 @@ class BridgeDependenciesResolver( return try { val diagnostics = arrayListOf() - val processedScriptData = - ProcessedScriptData(ProcessedScriptDataProperties.foundAnnotations to scriptContents.annotations) + val processedScriptData = object : ProcessedScriptData { + override val properties = properties { + foundAnnotations.append(scriptContents.annotations) + } + } - val refineFn = scriptDefinition.getOrNull(ScriptDefinitionProperties.refineConfigurationHandler) + val refineFn = scriptDefinition.getOrNull(ScriptDefinition.refineConfigurationHandler) val refinedConfiguration = - if (refineFn == null) calculatedBaseScriptCompilerConfiguration + if (refineFn == null) null else { - val res = refineFn(scriptContents.toScriptSource(), calculatedBaseScriptCompilerConfiguration, processedScriptData) + val res = refineFn( + scriptContents.toScriptSource(), scriptDefinition, additionalConfiguration, processedScriptData + ) when (res) { is ResultWithDiagnostics.Failure -> return@resolveAsync DependenciesResolver.ResolveResult.Failure(res.reports.mapScriptReportsToDiagnostics()) @@ -52,11 +59,12 @@ class BridgeDependenciesResolver( } } - val newClasspath = refinedConfiguration.getOrNull(ScriptDefinitionProperties.dependencies) + val newClasspath = refinedConfiguration?.getOrNull(ScriptDefinition.dependencies) ?.flatMap { (it as JvmDependency).classpath } ?: emptyList() - if (refinedConfiguration != calculatedBaseScriptCompilerConfiguration) { - val oldClasspath = calculatedBaseScriptCompilerConfiguration.getOrNull(ScriptDefinitionProperties.dependencies) - ?.flatMap { (it as JvmDependency).classpath } ?: emptyList() + if (newClasspath.isNotEmpty()) { + val oldClasspath = + getFirstFromChainOrNull(ScriptDefinition.dependencies, additionalConfiguration, scriptDefinition) + ?.flatMap { (it as JvmDependency).classpath } ?: emptyList() if (newClasspath != oldClasspath) { onClasspathUpdated(newClasspath) } @@ -64,8 +72,9 @@ class BridgeDependenciesResolver( DependenciesResolver.ResolveResult.Success( ScriptDependencies( classpath = newClasspath, // TODO: maybe it should return only increment from the initial config - imports = refinedConfiguration.getOrNull(ScriptDefinitionProperties.defaultImports)?.toList() - ?: emptyList() + imports = getFirstFromChainOrNull( + ScriptDefinition.defaultImports, refinedConfiguration, additionalConfiguration, scriptDefinition + )?.toList() ?: emptyList() ), diagnostics ) diff --git a/libraries/scripting/jvm/src/kotlin/script/experimental/jvm/jvmScriptConfiguration.kt b/libraries/scripting/jvm/src/kotlin/script/experimental/jvm/jvmScriptConfiguration.kt index e22548638e7..b126b63838f 100644 --- a/libraries/scripting/jvm/src/kotlin/script/experimental/jvm/jvmScriptConfiguration.kt +++ b/libraries/scripting/jvm/src/kotlin/script/experimental/jvm/jvmScriptConfiguration.kt @@ -7,13 +7,14 @@ package kotlin.script.experimental.jvm -import java.io.File -import kotlin.script.experimental.api.PropertiesGroup -import kotlin.script.experimental.api.ScriptingProperties -import kotlin.script.experimental.util.typedKey +import kotlin.script.experimental.api.ScriptCompileConfiguration +import kotlin.script.experimental.util.PropertiesCollection -object JvmScriptCompileConfigurationProperties : PropertiesGroup { - val javaHomeDir by typedKey(File(System.getProperty("java.home"))) +open class JvmScriptCompilationConfiguration : JvmScriptDefinition() { + + companion object : JvmScriptCompilationConfiguration() } -val ScriptingProperties.jvmCompileConfiguration get() = JvmScriptCompileConfigurationProperties +val JvmScriptCompilationConfiguration.javaHome by PropertiesCollection.keyCopy(JvmScriptingEnvironment.javaHome) + +val ScriptCompileConfiguration.jvm get() = JvmScriptCompilationConfiguration() diff --git a/libraries/scripting/jvm/src/kotlin/script/experimental/jvm/jvmDependencies.kt b/libraries/scripting/jvm/src/kotlin/script/experimental/jvm/jvmScriptDefinition.kt similarity index 56% rename from libraries/scripting/jvm/src/kotlin/script/experimental/jvm/jvmDependencies.kt rename to libraries/scripting/jvm/src/kotlin/script/experimental/jvm/jvmScriptDefinition.kt index e2faa0270c7..5900f50e723 100644 --- a/libraries/scripting/jvm/src/kotlin/script/experimental/jvm/jvmDependencies.kt +++ b/libraries/scripting/jvm/src/kotlin/script/experimental/jvm/jvmScriptDefinition.kt @@ -7,26 +7,33 @@ package kotlin.script.experimental.jvm import org.jetbrains.kotlin.script.util.scriptCompilationClasspathFromContext import java.io.File -import kotlin.script.experimental.api.ScriptDefinitionProperties +import kotlin.script.experimental.api.ScriptDefinition import kotlin.script.experimental.api.ScriptDependency -import kotlin.script.experimental.api.ScriptingProperties -import kotlin.script.experimental.api.addToListProperty +import kotlin.script.experimental.api.dependencies +import kotlin.script.experimental.util.PropertiesCollection + +open class JvmScriptDefinition : PropertiesCollection.Builder() { + + companion object : JvmScriptDefinition() +} + +val ScriptDefinition.jvm get() = JvmScriptDefinition() + class JvmDependency(val classpath: List) : ScriptDependency { constructor(vararg classpathEntries: File) : this(classpathEntries.asList()) } -fun ScriptingProperties.jvmDependenciesFromCurrentContext(vararg libraries: String, wholeClasspath: Boolean = false) { - jvmDependenciesFromClassloader(*libraries, wholeClasspath = wholeClasspath) +fun JvmScriptDefinition.dependenciesFromCurrentContext(vararg libraries: String, wholeClasspath: Boolean = false) { + dependenciesFromClassloader(*libraries, wholeClasspath = wholeClasspath) } -fun ScriptingProperties.jvmDependenciesFromClassloader( +fun JvmScriptDefinition.dependenciesFromClassloader( vararg libraries: String, classLoader: ClassLoader = Thread.currentThread().contextClassLoader, wholeClasspath: Boolean = false ) { - data.addToListProperty( - ScriptDefinitionProperties.dependencies, + ScriptDefinition.dependencies.append( JvmDependency(scriptCompilationClasspathFromContext(*libraries, classLoader = classLoader, wholeClasspath = wholeClasspath)) ) } diff --git a/libraries/scripting/jvm/src/kotlin/script/experimental/jvm/jvmScriptEnvironment.kt b/libraries/scripting/jvm/src/kotlin/script/experimental/jvm/jvmScriptEnvironment.kt index fb9734273e3..7b48e701b95 100644 --- a/libraries/scripting/jvm/src/kotlin/script/experimental/jvm/jvmScriptEnvironment.kt +++ b/libraries/scripting/jvm/src/kotlin/script/experimental/jvm/jvmScriptEnvironment.kt @@ -5,18 +5,24 @@ package kotlin.script.experimental.jvm +import java.io.File import java.net.URLClassLoader import kotlin.reflect.KClass import kotlin.script.experimental.api.* +import kotlin.script.experimental.util.PropertiesCollection +import kotlin.script.experimental.util.getOrNull -private object DefaultJvmScriptingEnvironmentPropertiesBuilder : ScriptingProperties() { - init { - ScriptingEnvironmentProperties.getScriptingClass(JvmGetScriptingClass()) - } +open class JvmScriptingEnvironment : PropertiesCollection.Builder() { + companion object : JvmScriptingEnvironment() } -val defaultJvmScriptingEnvironment = DefaultJvmScriptingEnvironmentPropertiesBuilder.build() +val JvmScriptingEnvironment.javaHome by PropertiesCollection.key(File(System.getProperty("java.home"))) +val ScriptingEnvironment.jvm get() = JvmScriptingEnvironment() + +val defaultJvmScriptingEnvironment = ScriptingEnvironment.create { + getScriptingClass(JvmGetScriptingClass()) +} class JvmGetScriptingClass : GetScriptingClass { @@ -37,7 +43,7 @@ class JvmGetScriptingClass : GetScriptingClass { if (actualClassLoadersChain.any { it == fromClass.java.classLoader }) return fromClass } - val newDeps = environment.getOrNull(ScriptingEnvironmentProperties.configurationDependencies) + val newDeps = environment.getOrNull(ScriptingEnvironment.configurationDependencies) if (dependencies == null) { dependencies = newDeps } else { @@ -55,10 +61,10 @@ class JvmGetScriptingClass : GetScriptingClass { // } if (classLoader == null) { - val classpath = dependencies?.flatMap { - when(it) { - is JvmDependency -> it.classpath.map { it.toURI().toURL() } - else -> throw IllegalArgumentException("unknown dependency type $it") + val classpath = dependencies?.flatMap { dependency -> + when(dependency) { + is JvmDependency -> dependency.classpath.map { it.toURI().toURL() } + else -> throw IllegalArgumentException("unknown dependency type $dependency") } } classLoader = diff --git a/libraries/scripting/misc/src/kotlin/script/experimental/misc/propertiesDsl.kt b/libraries/scripting/misc/src/kotlin/script/experimental/misc/propertiesDsl.kt index f28e2090747..fb0876af4e6 100644 --- a/libraries/scripting/misc/src/kotlin/script/experimental/misc/propertiesDsl.kt +++ b/libraries/scripting/misc/src/kotlin/script/experimental/misc/propertiesDsl.kt @@ -8,47 +8,47 @@ package kotlin.script.experimental.misc import kotlin.reflect.KClass import kotlin.reflect.KType import kotlin.script.experimental.api.KotlinType -import kotlin.script.experimental.util.TypedKey +import kotlin.script.experimental.util.PropertyKey -inline operator fun TypedKey.invoke(v: T): Pair, T> = this to v +inline operator fun PropertyKey.invoke(v: T): Pair, T> = this to v -inline operator fun TypedKey.invoke(): Pair, KotlinType> = +inline operator fun PropertyKey.invoke(): Pair, KotlinType> = this to KotlinType(K::class) -operator fun TypedKey.invoke(kclass: KClass<*>): Pair, KotlinType> = +operator fun PropertyKey.invoke(kclass: KClass<*>): Pair, KotlinType> = this to KotlinType(kclass) -operator fun TypedKey.invoke(ktype: KType): Pair, KotlinType> = +operator fun PropertyKey.invoke(ktype: KType): Pair, KotlinType> = this to KotlinType(ktype) -operator fun TypedKey.invoke(fqname: String): Pair, KotlinType> = +operator fun PropertyKey.invoke(fqname: String): Pair, KotlinType> = this to KotlinType(fqname) -operator fun TypedKey>.invoke(vararg classes: KClass<*>): Pair>, List> = +operator fun PropertyKey>.invoke(vararg classes: KClass<*>): Pair>, List> = this to classes.map { KotlinType(it) } -operator fun TypedKey>.invoke(vararg types: KType): Pair>, List> = +operator fun PropertyKey>.invoke(vararg types: KType): Pair>, List> = this to types.map { KotlinType(it) } -operator fun TypedKey>.invoke(vararg fqnames: String): Pair>, List> = +operator fun PropertyKey>.invoke(vararg fqnames: String): Pair>, List> = this to fqnames.map { KotlinType(it) } -inline operator fun TypedKey>.invoke(vararg vs: E): Pair>, List> = this to vs.toList() +inline operator fun PropertyKey>.invoke(vararg vs: E): Pair>, List> = this to vs.toList() @JvmName("invoke_kotlintype_map_from_kclass") -inline operator fun TypedKey>.invoke(vararg classes: Pair>): Pair>, Map> = +inline operator fun PropertyKey>.invoke(vararg classes: Pair>): Pair>, Map> = this to LinkedHashMap().also { it.putAll(classes.asSequence().map { (k, v) -> k to KotlinType(v) }) } @JvmName("invoke_kotlintype_map_from_ktype") -inline operator fun TypedKey>.invoke(vararg types: Pair): Pair>, Map> = +inline operator fun PropertyKey>.invoke(vararg types: Pair): Pair>, Map> = this to LinkedHashMap().also { it.putAll(types.asSequence().map { (k, v) -> k to KotlinType(v) }) } @JvmName("invoke_kotlintype_map_from_fqname") -inline operator fun TypedKey>.invoke(vararg fqnames: Pair): Pair>, Map> = +inline operator fun PropertyKey>.invoke(vararg fqnames: Pair): Pair>, Map> = this to LinkedHashMap().also { it.putAll(fqnames.asSequence().map { (k, v) -> k to KotlinType(v) }) } -inline operator fun TypedKey>.invoke(vararg vs: Pair): Pair>, Map> = +inline operator fun PropertyKey>.invoke(vararg vs: Pair): Pair>, Map> = this to mapOf(*vs) // TODO: make tests from examples below diff --git a/plugins/scripting/scripting-cli/build.gradle.kts b/plugins/scripting/scripting-cli/build.gradle.kts index fdd464eee6d..99edc23473f 100644 --- a/plugins/scripting/scripting-cli/build.gradle.kts +++ b/plugins/scripting/scripting-cli/build.gradle.kts @@ -14,7 +14,6 @@ dependencies { compileOnly(project(":compiler:cli")) compile(project(":kotlin-scripting-common")) compile(project(":kotlin-scripting-jvm")) - compile(project(":kotlin-scripting-misc")) compileOnly(project(":kotlin-reflect-api")) compileOnly(intellijCoreDep()) { includeJars("intellij-core") } compileOnly(intellijDep()) { includeJars("asm-all") } diff --git a/plugins/scripting/scripting-cli/src/org/jetbrains/kotlin/scripting/compiler/plugin/KotlinScriptDefinitionAdapterFromNewAPI.kt b/plugins/scripting/scripting-cli/src/org/jetbrains/kotlin/scripting/compiler/plugin/KotlinScriptDefinitionAdapterFromNewAPI.kt index 81643f2c431..c7d545354d8 100644 --- a/plugins/scripting/scripting-cli/src/org/jetbrains/kotlin/scripting/compiler/plugin/KotlinScriptDefinitionAdapterFromNewAPI.kt +++ b/plugins/scripting/scripting-cli/src/org/jetbrains/kotlin/scripting/compiler/plugin/KotlinScriptDefinitionAdapterFromNewAPI.kt @@ -18,6 +18,8 @@ import kotlin.script.experimental.api.* import kotlin.script.experimental.dependencies.DependenciesResolver import kotlin.script.experimental.jvm.impl.BridgeDependenciesResolver import kotlin.script.experimental.location.ScriptExpectedLocation +import kotlin.script.experimental.util.getOrError +import kotlin.script.experimental.util.getOrNull // temporary trick with passing Any as a template and overwriting it below, TODO: fix after introducing new script definitions hierarchy abstract class KotlinScriptDefinitionAdapterFromNewAPIBase : KotlinScriptDefinition(Any::class) { @@ -29,13 +31,13 @@ abstract class KotlinScriptDefinitionAdapterFromNewAPIBase : KotlinScriptDefinit abstract val scriptFileExtensionWithDot: String open val baseClass: KClass<*> by lazy(LazyThreadSafetyMode.PUBLICATION) { - getScriptingClass(scriptDefinition[ScriptDefinitionProperties.baseClass]) + getScriptingClass(scriptDefinition.getOrError(ScriptDefinition.baseClass)) } override val template: KClass<*> get() = baseClass override val name: String - get() = scriptDefinition.getOrNull(ScriptDefinitionProperties.name) ?: "Kotlin Script" + get() = scriptDefinition.getOrNull(ScriptDefinition.name) ?: "Kotlin Script" override val fileType: LanguageFileType = KotlinFileType.INSTANCE @@ -51,28 +53,28 @@ abstract class KotlinScriptDefinitionAdapterFromNewAPIBase : KotlinScriptDefinit get() = emptyList() override val dependencyResolver: DependenciesResolver by lazy(LazyThreadSafetyMode.PUBLICATION) { - BridgeDependenciesResolver(scriptDefinition, scriptDefinition) + BridgeDependenciesResolver(scriptDefinition, null) } override val acceptedAnnotations: List> by lazy(LazyThreadSafetyMode.PUBLICATION) { - scriptDefinition.getOrNull(ScriptDefinitionProperties.refineConfigurationOnAnnotations) + scriptDefinition.getOrNull(ScriptDefinition.refineConfigurationOnAnnotations) .orEmpty() .map { getScriptingClass(it) as KClass } } override val implicitReceivers: List by lazy(LazyThreadSafetyMode.PUBLICATION) { - scriptDefinition.getOrNull(ScriptDefinitionProperties.scriptImplicitReceivers) + scriptDefinition.getOrNull(ScriptDefinition.scriptImplicitReceivers) .orEmpty() .map { getScriptingClass(it).starProjectedType } } override val environmentVariables: List> by lazy(LazyThreadSafetyMode.PUBLICATION) { - scriptDefinition.getOrNull(ScriptDefinitionProperties.contextVariables) + scriptDefinition.getOrNull(ScriptDefinition.contextVariables) ?.map { (k, v) -> k to getScriptingClass(v).starProjectedType }.orEmpty() } override val additionalCompilerArguments: List - get() = scriptDefinition.getOrNull(ScriptDefinitionProperties.compilerOptions) + get() = scriptDefinition.getOrNull(ScriptDefinition.compilerOptions) .orEmpty() override val scriptExpectedLocations: List = @@ -82,15 +84,15 @@ abstract class KotlinScriptDefinitionAdapterFromNewAPIBase : KotlinScriptDefinit ) override val targetClassAnnotations: List - get() = scriptDefinition.getOrNull(ScriptDefinitionProperties.generatedClassAnnotations) + get() = scriptDefinition.getOrNull(ScriptDefinition.generatedClassAnnotations) .orEmpty() override val targetMethodAnnotations: List - get() = scriptDefinition.getOrNull(ScriptDefinitionProperties.generatedMethodAnnotations) + get() = scriptDefinition.getOrNull(ScriptDefinition.generatedMethodAnnotations) .orEmpty() private val scriptingClassGetter by lazy(LazyThreadSafetyMode.PUBLICATION) { - hostEnvironment.getOrNull(ScriptingEnvironmentProperties.getScriptingClass) + hostEnvironment.getOrNull(ScriptingEnvironment.getScriptingClass) ?: throw IllegalArgumentException("Expecting 'getScriptingClass' property in the scripting environment") } @@ -98,7 +100,7 @@ abstract class KotlinScriptDefinitionAdapterFromNewAPIBase : KotlinScriptDefinit scriptingClassGetter( type, KotlinScriptDefinition::class, // Assuming that the KotlinScriptDefinition class is loaded in the proper classloader - scriptDefinition + hostEnvironment ) } @@ -108,8 +110,8 @@ class KotlinScriptDefinitionAdapterFromNewAPI( override val hostEnvironment: ScriptingEnvironment ) : KotlinScriptDefinitionAdapterFromNewAPIBase() { - override val name: String get() = scriptDefinition.getOrNull(ScriptDefinitionProperties.name) ?: super.name + override val name: String get() = scriptDefinition.getOrNull(ScriptDefinition.name) ?: super.name override val scriptFileExtensionWithDot = - "." + (scriptDefinition.getOrNull(ScriptDefinitionProperties.fileExtension) ?: "kts") + "." + (scriptDefinition.getOrNull(ScriptDefinition.fileExtension) ?: "kts") } diff --git a/plugins/scripting/scripting-cli/src/org/jetbrains/kotlin/scripting/compiler/plugin/LazyScriptDefinitionFromDiscoveredClass.kt b/plugins/scripting/scripting-cli/src/org/jetbrains/kotlin/scripting/compiler/plugin/LazyScriptDefinitionFromDiscoveredClass.kt index 30942be9fc6..b9d8894536b 100644 --- a/plugins/scripting/scripting-cli/src/org/jetbrains/kotlin/scripting/compiler/plugin/LazyScriptDefinitionFromDiscoveredClass.kt +++ b/plugins/scripting/scripting-cli/src/org/jetbrains/kotlin/scripting/compiler/plugin/LazyScriptDefinitionFromDiscoveredClass.kt @@ -19,6 +19,7 @@ import kotlin.script.experimental.api.* import kotlin.script.experimental.definitions.createScriptDefinitionFromAnnotatedBaseClass import kotlin.script.experimental.jvm.JvmDependency import kotlin.script.experimental.jvm.defaultJvmScriptingEnvironment +import kotlin.script.experimental.util.getOrNull class LazyScriptDefinitionFromDiscoveredClass internal constructor( private val annotationsFromAsm: ArrayList, @@ -35,10 +36,10 @@ class LazyScriptDefinitionFromDiscoveredClass internal constructor( ) : this(loadAnnotationsFromClass(classBytes), className, classpath, messageCollector) override val hostEnvironment: ScriptingEnvironment by lazy(LazyThreadSafetyMode.PUBLICATION) { - ScriptingEnvironment( - defaultJvmScriptingEnvironment, - ScriptingEnvironmentProperties.configurationDependencies to listOf(JvmDependency(classpath)) - ) + ScriptingEnvironment.create { + include(defaultJvmScriptingEnvironment) + configurationDependencies(JvmDependency(classpath)) + } } override val scriptDefinition: ScriptDefinition by lazy(LazyThreadSafetyMode.PUBLICATION) { @@ -69,7 +70,7 @@ class LazyScriptDefinitionFromDiscoveredClass internal constructor( // TODO: check whether it actually works ?: annotationsFromAsm.find { it.name == KotlinScript::class.simpleName }?.args?.get(1) ?: scriptDefinition.let { - it.getOrNull(ScriptDefinitionProperties.fileExtension) ?: "kts" + it.getOrNull(ScriptDefinition.fileExtension) ?: "kts" } ".$ext" } @@ -80,4 +81,4 @@ class LazyScriptDefinitionFromDiscoveredClass internal constructor( } } -object InvalidScriptDefinition : ScriptDefinition() +object InvalidScriptDefinition : ScriptDefinition diff --git a/plugins/scripting/scripting-cli/tests/org/jetbrains/kotlin/scripting/compiler/plugin/ScriptingCompilerPluginTest.kt b/plugins/scripting/scripting-cli/tests/org/jetbrains/kotlin/scripting/compiler/plugin/ScriptingCompilerPluginTest.kt index 03e8b2f3e05..9a8af27f801 100644 --- a/plugins/scripting/scripting-cli/tests/org/jetbrains/kotlin/scripting/compiler/plugin/ScriptingCompilerPluginTest.kt +++ b/plugins/scripting/scripting-cli/tests/org/jetbrains/kotlin/scripting/compiler/plugin/ScriptingCompilerPluginTest.kt @@ -43,7 +43,7 @@ class ScriptingCompilerPluginTest : TestCaseWithTmpdir() { val compilerClasspath = listOf(kotlinPaths.compilerPath) val runtimeClasspath = listOf( kotlinPaths.stdlibPath, kotlinPaths.scriptRuntimePath, kotlinPaths.reflectPath) - val scriptingClasspath = listOf("kotlin-scripting-common.jar", "kotlin-scripting-misc.jar").map { File(kotlinPaths.libPath, it) } + val scriptingClasspath = listOf("kotlin-scripting-common.jar").map { File(kotlinPaths.libPath, it) } private fun createEnvironment( sources: List, destDir: File, messageCollector: MessageCollector, confBody: CompilerConfiguration.() -> Unit diff --git a/plugins/scripting/scripting-embeddable/build.gradle.kts b/plugins/scripting/scripting-embeddable/build.gradle.kts index 3ed91969c2b..145aff1fd78 100644 --- a/plugins/scripting/scripting-embeddable/build.gradle.kts +++ b/plugins/scripting/scripting-embeddable/build.gradle.kts @@ -9,7 +9,6 @@ val packedJars by configurations.creating dependencies { packedJars(project(":kotlin-scripting-compiler")) { isTransitive = false } packedJars(project(":kotlin-scripting-common")) { isTransitive = false } - packedJars(project(":kotlin-scripting-misc")) { isTransitive = false } packedJars(project(":kotlin-scripting-jvm")) { isTransitive = false } } diff --git a/settings.gradle b/settings.gradle index 3710066892a..2d979e90fc2 100644 --- a/settings.gradle +++ b/settings.gradle @@ -161,7 +161,6 @@ include ":kotlin-build-common", ":kotlin-annotations-jvm", ":kotlin-annotations-android", ":kotlin-scripting-common", - ":kotlin-scripting-misc", ":kotlin-scripting-jvm", ":kotlin-scripting-jvm-host", ":kotlin-scripting-compiler", @@ -274,7 +273,6 @@ project(':examples:kotlin-jsr223-daemon-local-eval-example').projectDir = "$root project(':kotlin-annotations-jvm').projectDir = "$rootDir/libraries/tools/kotlin-annotations-jvm" as File project(':kotlin-annotations-android').projectDir = "$rootDir/libraries/tools/kotlin-annotations-android" as File project(':kotlin-scripting-common').projectDir = "$rootDir/libraries/scripting/common" as File -project(':kotlin-scripting-misc').projectDir = "$rootDir/libraries/scripting/misc" as File project(':kotlin-scripting-jvm').projectDir = "$rootDir/libraries/scripting/jvm" as File project(':kotlin-scripting-jvm-host').projectDir = "$rootDir/libraries/scripting/jvm-host" as File project(':kotlin-scripting-compiler').projectDir = "$rootDir/plugins/scripting/scripting-cli" as File