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 55257aa58c9..3e909c2cd55 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 @@ -14,26 +14,25 @@ import kotlin.script.dependencies.ScriptContents import kotlin.script.dependencies.ScriptDependenciesResolver 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.jvm.JvmDependency -import kotlin.script.experimental.jvm.jvmJavaHomeParams -import kotlin.script.experimental.jvm.mapLegacyDiagnosticSeverity -import kotlin.script.experimental.jvm.mapLegacyScriptPosition +import kotlin.script.experimental.jvm.* import kotlin.script.experimental.misc.invoke import kotlin.script.experimental.util.TypedKey @KotlinScript @KotlinScriptFileExtension("scriptwithdeps.kts") -@KotlinScriptPropertiesFromList(MyConfiguration::class) +@KotlinScriptProperties(MyConfiguration::class) abstract class MyScriptWithMavenDeps { // abstract fun body(vararg args: String): Int } -object MyConfiguration : ArrayList, Any?>>( - jvmJavaHomeParams + with(ScriptDefinitionProperties) { - listOf( - defaultImports(DependsOn::class.qualifiedName!!, Repository::class.qualifiedName!!), +object MyConfiguration : ScriptingProperties() { + init { + include(jvmJavaHomeScriptingProperties) + ScriptDefinitionProperties { + defaultImports(DependsOn::class.qualifiedName!!, Repository::class.qualifiedName!!) dependencies( JvmDependency( scriptCompilationClasspathFromContext( @@ -41,12 +40,12 @@ object MyConfiguration : ArrayList, Any?>>( "kotlin-script-util" // DependsOn annotation is taken from script-util ) ) - ), - refineConfiguration(MyConfigurator()), + ) + refineConfiguration(MyConfigurator()) refineConfigurationOnAnnotations(DependsOn::class, Repository::class) - ) + } } -) +} class MyConfigurator : RefineScriptCompilationConfiguration { 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 ed6d012a86a..f82dbda8885 100644 --- a/libraries/scripting/common/src/kotlin/script/experimental/annotations/scriptAnnotations.kt +++ b/libraries/scripting/common/src/kotlin/script/experimental/annotations/scriptAnnotations.kt @@ -13,6 +13,7 @@ package kotlin.script.experimental.annotations import kotlin.reflect.KClass +import kotlin.script.experimental.api.ScriptingProperties @Target(AnnotationTarget.CLASS) @Retention(AnnotationRetention.RUNTIME) @@ -28,6 +29,13 @@ annotation class KotlinScriptFileExtension( @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 +) diff --git a/libraries/scripting/common/src/kotlin/script/experimental/api/propertiesDsl.kt b/libraries/scripting/common/src/kotlin/script/experimental/api/propertiesDsl.kt new file mode 100644 index 00000000000..0282957fa9b --- /dev/null +++ b/libraries/scripting/common/src/kotlin/script/experimental/api/propertiesDsl.kt @@ -0,0 +1,115 @@ +/* + * 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.KType +import kotlin.script.experimental.util.ChainedPropertyBag +import kotlin.script.experimental.util.TypedKey + +interface PropertiesGroup + +open class ScriptingProperties(body: ScriptingProperties.() -> Unit = {}) { + + var parentPropertiesBag: ChainedPropertyBag? = null + var parentPropertiesBuilder: ScriptingProperties? = null + val data = HashMap, Any?>() + + init { + body() + } + + internal fun makePropertyBag(): ChainedPropertyBag = + ChainedPropertyBag.createOptimized(parentPropertiesBag ?: parentPropertiesBuilder?.makePropertyBag(), data) + + // generic invoke for properties groups + inline operator fun T.invoke(body: T.() -> Unit) = 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) { + data.putAll(props.data) + } + + fun include(props: ChainedPropertyBag) { + data.putAll(props.data) + } + + // builders for known property types: + + inline operator fun TypedKey.invoke(v: T) { + data[this] = v + } + + 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) + } + + operator fun TypedKey>.invoke(vararg classes: KClass<*>) { + data[this] = classes.map { KotlinType(it) } + } + + operator fun TypedKey>.invoke(vararg types: KType) { + data[this] = types.map { KotlinType(it) } + } + + operator fun TypedKey>.invoke(vararg fqnames: String) { + data[this] = fqnames.map { KotlinType(it) } + } + + inline operator fun TypedKey>.invoke(vararg vs: E) { + data[this] = vs.toList() + } + + @JvmName("invoke_kotlintype_map_from_kclass") + inline operator fun TypedKey>.invoke(vararg classes: Pair>) { + data[this] = HashMap().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) { + data[this] = HashMap().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) { + data[this] = HashMap().also { it.putAll(fqnames.asSequence().map { (k, v) -> k to KotlinType(v) }) } + } + + inline operator fun TypedKey>.invoke(vararg vs: Pair) { + data[this] = hashMapOf(*vs) + } +} 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 08c119f6bcb..e5f0aa2f350 100644 --- a/libraries/scripting/common/src/kotlin/script/experimental/api/scriptConfiguration.kt +++ b/libraries/scripting/common/src/kotlin/script/experimental/api/scriptConfiguration.kt @@ -12,14 +12,14 @@ import kotlin.script.experimental.util.typedKey typealias ScriptCompileConfiguration = ChainedPropertyBag -object ScriptCompileConfigurationProperties { +object ScriptCompileConfigurationProperties : PropertiesGroup { val sourceFragments by typedKey>() } typealias ProcessedScriptData = ChainedPropertyBag -object ProcessedScriptDataProperties { +object ProcessedScriptDataProperties : PropertiesGroup { val foundAnnotations by typedKey>() val foundFragments by typedKey>() 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 3c43d5c13de..c17cc0deb41 100644 --- a/libraries/scripting/common/src/kotlin/script/experimental/api/scriptDefinition.kt +++ b/libraries/scripting/common/src/kotlin/script/experimental/api/scriptDefinition.kt @@ -12,7 +12,7 @@ import kotlin.script.experimental.util.typedKey typealias ScriptDefinition = ChainedPropertyBag -object ScriptDefinitionProperties { +object ScriptDefinitionProperties : PropertiesGroup { val name by typedKey() // Name of the script type, by default "Kotlin script" 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 36356e9a9c3..36dd2b80620 100644 --- a/libraries/scripting/common/src/kotlin/script/experimental/api/scriptingEnvironment.kt +++ b/libraries/scripting/common/src/kotlin/script/experimental/api/scriptingEnvironment.kt @@ -11,7 +11,7 @@ import kotlin.script.experimental.util.typedKey typealias ScriptingEnvironment = ChainedPropertyBag -object ScriptingEnvironmentProperties { +object ScriptingEnvironmentProperties : PropertiesGroup { // should contain all dependencies needed for baseClass and compilationConfigurator val configurationDependencies by typedKey>() 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 cb6707be77b..4a2ef14449b 100644 --- a/libraries/scripting/common/src/kotlin/script/experimental/definitions/definitionFromAnnotation.kt +++ b/libraries/scripting/common/src/kotlin/script/experimental/definitions/definitionFromAnnotation.kt @@ -10,6 +10,7 @@ import kotlin.reflect.full.createInstance 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 @@ -57,6 +58,15 @@ fun createScriptDefinitionFromAnnotatedBaseClass( } } } + baseClass.annotations.filterIsInstance(KotlinScriptProperties::class.java).forEach { ann -> + val params = try { + ann.definitionProperties.objectInstance ?: ann.definitionProperties.createInstance() + } catch (e: Throwable) { + throw IllegalArgumentException(ILLEGAL_CONFIG_ANN_ARG, e) + } + propertiesData.putAll(params.data) + // TODO: chaining is lost here, fix it + } return ScriptingEnvironment.createOptimized(null, propertiesData) } diff --git a/libraries/scripting/common/src/kotlin/script/experimental/util/propertyBag.kt b/libraries/scripting/common/src/kotlin/script/experimental/util/propertyBag.kt index f87d63b1dbc..b5cc112d2fa 100644 --- a/libraries/scripting/common/src/kotlin/script/experimental/util/propertyBag.kt +++ b/libraries/scripting/common/src/kotlin/script/experimental/util/propertyBag.kt @@ -17,7 +17,7 @@ class TypedKeyDelegate(val defaultValue: T? = null) { fun typedKey(defaultValue: T? = null) = TypedKeyDelegate(defaultValue) -open class ChainedPropertyBag private constructor(private val parent: ChainedPropertyBag?, private val data: Map, Any?>) { +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) }) 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 69f36c529c8..c099768fc54 100644 --- a/libraries/scripting/jvm/src/kotlin/script/experimental/jvm/jvmScriptConfiguration.kt +++ b/libraries/scripting/jvm/src/kotlin/script/experimental/jvm/jvmScriptConfiguration.kt @@ -6,7 +6,13 @@ package kotlin.script.experimental.jvm import java.io.File +import kotlin.script.experimental.api.ScriptingProperties val jvmJavaHomeParams = with(JvmScriptCompileConfigurationProperties) { listOf(javaHomeDir to File(System.getProperty("java.home"))) } + +object jvmJavaHomeScriptingProperties : ScriptingProperties( + { + JvmScriptCompileConfigurationProperties.javaHomeDir(File(System.getProperty("java.home"))) + }) diff --git a/libraries/scripting/jvm/src/kotlin/script/experimental/jvm/jvmScriptData.kt b/libraries/scripting/jvm/src/kotlin/script/experimental/jvm/jvmScriptData.kt index 3354dcc9fde..cd34b14ec66 100644 --- a/libraries/scripting/jvm/src/kotlin/script/experimental/jvm/jvmScriptData.kt +++ b/libraries/scripting/jvm/src/kotlin/script/experimental/jvm/jvmScriptData.kt @@ -8,10 +8,11 @@ package kotlin.script.experimental.jvm import java.io.File +import kotlin.script.experimental.api.PropertiesGroup import kotlin.script.experimental.api.ScriptDependency import kotlin.script.experimental.util.typedKey -object JvmScriptCompileConfigurationProperties { +object JvmScriptCompileConfigurationProperties : PropertiesGroup { val javaHomeDir by typedKey() }