Refactoring properties collection after review

This commit is contained in:
Ilya Chernikov
2018-08-16 18:55:31 +02:00
parent 74f8a541c0
commit 04ffe7754e
22 changed files with 225 additions and 198 deletions
@@ -208,7 +208,7 @@ fun loadDefinitionsFromTemplates(
) )
} }
template.annotations.firstIsInstanceOrNull<kotlin.script.experimental.annotations.KotlinScript>() != null -> { template.annotations.firstIsInstanceOrNull<kotlin.script.experimental.annotations.KotlinScript>() != null -> {
val hostEnvironment = ScriptingEnvironment.create { val hostEnvironment = ScriptingEnvironment {
include(defaultJvmScriptingEnvironment) include(defaultJvmScriptingEnvironment)
configurationDependencies(JvmDependency(classpath)) configurationDependencies(JvmDependency(classpath))
} }
@@ -18,7 +18,6 @@ import kotlin.script.experimental.jvm.compat.mapLegacyDiagnosticSeverity
import kotlin.script.experimental.jvm.compat.mapLegacyScriptPosition import kotlin.script.experimental.jvm.compat.mapLegacyScriptPosition
import kotlin.script.experimental.jvm.dependenciesFromCurrentContext import kotlin.script.experimental.jvm.dependenciesFromCurrentContext
import kotlin.script.experimental.jvm.jvm import kotlin.script.experimental.jvm.jvm
import kotlin.script.experimental.util.getOrNull
@KotlinScript( @KotlinScript(
extension = "scriptwithdeps.kts", extension = "scriptwithdeps.kts",
@@ -28,8 +27,8 @@ abstract class MyScriptWithMavenDeps {
// abstract fun body(vararg args: String): Int // abstract fun body(vararg args: String): Int
} }
object MyScriptDefinition : ScriptDefinition { object MyScriptDefinition : ScriptDefinition(
override val properties = properties { {
defaultImports<DependsOn>() defaultImports<DependsOn>()
defaultImports(Repository::class) defaultImports(Repository::class)
jvm { jvm {
@@ -47,7 +46,7 @@ object MyScriptDefinition : ScriptDefinition {
// other triggers: beforeParsing, onSections // other triggers: beforeParsing, onSections
} }
} }
} )
class MyConfigurator : RefineScriptCompilationConfigurationHandler { class MyConfigurator : RefineScriptCompilationConfigurationHandler {
@@ -59,7 +58,7 @@ class MyConfigurator : RefineScriptCompilationConfigurationHandler {
configuration: ScriptCompileConfiguration?, configuration: ScriptCompileConfiguration?,
processedScriptData: ProcessedScriptData? processedScriptData: ProcessedScriptData?
): ResultWithDiagnostics<ScriptCompileConfiguration?> { ): ResultWithDiagnostics<ScriptCompileConfiguration?> {
val annotations = processedScriptData?.getOrNull(ProcessedScriptData.foundAnnotations)?.takeIf { it.isNotEmpty() } val annotations = processedScriptData?.get(ProcessedScriptData.foundAnnotations)?.takeIf { it.isNotEmpty() }
?: return configuration.asSuccess() ?: return configuration.asSuccess()
val scriptContents = object : ScriptContents { val scriptContents = object : ScriptContents {
override val annotations: Iterable<Annotation> = annotations override val annotations: Iterable<Annotation> = annotations
@@ -75,7 +74,7 @@ class MyConfigurator : RefineScriptCompilationConfigurationHandler {
?: return configuration.asSuccess(diagnostics) ?: return configuration.asSuccess(diagnostics)
val resolvedClasspath = newDepsFromResolver.classpath.toList().takeIf { it.isNotEmpty() } val resolvedClasspath = newDepsFromResolver.classpath.toList().takeIf { it.isNotEmpty() }
?: return configuration.asSuccess(diagnostics) ?: return configuration.asSuccess(diagnostics)
ScriptCompileConfiguration.create { ScriptCompileConfiguration {
dependencies(JvmDependency(resolvedClasspath)) dependencies(JvmDependency(resolvedClasspath))
}.asSuccess(diagnostics) }.asSuccess(diagnostics)
} catch (e: Throwable) { } catch (e: Throwable) {
@@ -17,7 +17,7 @@ import kotlin.script.experimental.jvm.jvm
import kotlin.script.experimental.jvmhost.makeBasicHostFromAnnotatedScriptBaseClass import kotlin.script.experimental.jvmhost.makeBasicHostFromAnnotatedScriptBaseClass
fun evalFile(scriptFile: File): ResultWithDiagnostics<EvaluationResult> { fun evalFile(scriptFile: File): ResultWithDiagnostics<EvaluationResult> {
val additionalCompilationProperties = ScriptCompileConfiguration.create { val additionalCompilationProperties = ScriptCompileConfiguration {
jvm { jvm {
dependenciesFromCurrentContext( dependenciesFromCurrentContext(
"scripting-jvm-simple-script" /* script library jar name */ "scripting-jvm-simple-script" /* script library jar name */
@@ -9,45 +9,52 @@ package kotlin.script.experimental.api
import kotlin.script.experimental.util.PropertiesCollection import kotlin.script.experimental.util.PropertiesCollection
interface ScriptCompileConfiguration : PropertiesCollection { interface ScriptCompileConfigurationKeys
class ScriptCompileConfiguration(baseConfigurations: Iterable<ScriptCompileConfiguration>, body: Builder.() -> Unit) :
PropertiesCollection(Builder(baseConfigurations).apply(body).data) {
constructor(body: Builder.() -> Unit = {}) : this(emptyList(), body)
constructor(
vararg baseConfigurations: ScriptCompileConfiguration, body: Builder.() -> Unit = {}
) : this(baseConfigurations.asIterable(), body)
class Builder internal constructor(baseConfigurations: Iterable<ScriptCompileConfiguration>) :
ScriptCompileConfigurationKeys,
PropertiesCollection.Builder(baseConfigurations)
companion object : ScriptCompileConfiguration { companion object : ScriptCompileConfigurationKeys
class Builder internal constructor() : PropertiesCollection.Builder(), ScriptCompileConfiguration {
override val properties = data
}
fun create(body: Builder.() -> Unit): ScriptCompileConfiguration = Builder().apply(body)
}
} }
val ScriptCompileConfiguration.sourceFragments by PropertiesCollection.key<List<ScriptSourceNamedFragment>>() val ScriptCompileConfigurationKeys.sourceFragments by PropertiesCollection.key<List<ScriptSourceNamedFragment>>()
val ScriptCompileConfiguration.scriptBodyTarget by PropertiesCollection.keyCopy(ScriptDefinition.scriptBodyTarget) val ScriptCompileConfigurationKeys.scriptBodyTarget by PropertiesCollection.keyCopy(ScriptDefinition.scriptBodyTarget)
val ScriptCompileConfiguration.scriptImplicitReceivers by PropertiesCollection.keyCopy(ScriptDefinition.scriptImplicitReceivers) val ScriptCompileConfigurationKeys.scriptImplicitReceivers by PropertiesCollection.keyCopy(ScriptDefinition.scriptImplicitReceivers)
val ScriptCompileConfiguration.contextVariables by PropertiesCollection.keyCopy(ScriptDefinition.contextVariables) val ScriptCompileConfigurationKeys.contextVariables by PropertiesCollection.keyCopy(ScriptDefinition.contextVariables)
val ScriptCompileConfiguration.defaultImports by PropertiesCollection.keyCopy(ScriptDefinition.defaultImports) val ScriptCompileConfigurationKeys.defaultImports by PropertiesCollection.keyCopy(ScriptDefinition.defaultImports)
val ScriptCompileConfiguration.restrictions by PropertiesCollection.keyCopy(ScriptDefinition.restrictions) val ScriptCompileConfigurationKeys.restrictions by PropertiesCollection.keyCopy(ScriptDefinition.restrictions)
val ScriptCompileConfiguration.importedScripts by PropertiesCollection.keyCopy(ScriptDefinition.importedScripts) val ScriptCompileConfigurationKeys.importedScripts by PropertiesCollection.keyCopy(ScriptDefinition.importedScripts)
val ScriptCompileConfiguration.dependencies by PropertiesCollection.keyCopy(ScriptDefinition.dependencies) val ScriptCompileConfigurationKeys.dependencies by PropertiesCollection.keyCopy(ScriptDefinition.dependencies)
val ScriptCompileConfiguration.compilerOptions by PropertiesCollection.keyCopy(ScriptDefinition.compilerOptions) val ScriptCompileConfigurationKeys.compilerOptions by PropertiesCollection.keyCopy(ScriptDefinition.compilerOptions)
interface ProcessedScriptData : PropertiesCollection { interface ProcessedScriptDataKeys
companion object : ProcessedScriptData class ProcessedScriptData(properties: Map<PropertiesCollection.Key<*>, Any>) : PropertiesCollection(properties) {
companion object : ProcessedScriptDataKeys
} }
val ProcessedScriptData.foundAnnotations by PropertiesCollection.key<List<Annotation>>() val ProcessedScriptDataKeys.foundAnnotations by PropertiesCollection.key<List<Annotation>>()
val ProcessedScriptData.foundFragments by PropertiesCollection.key<List<ScriptSourceNamedFragment>>() val ProcessedScriptDataKeys.foundFragments by PropertiesCollection.key<List<ScriptSourceNamedFragment>>()
interface RefineScriptCompilationConfigurationHandler { interface RefineScriptCompilationConfigurationHandler {
@@ -10,57 +10,62 @@ package kotlin.script.experimental.api
import kotlin.reflect.KClass import kotlin.reflect.KClass
import kotlin.script.experimental.util.PropertiesCollection import kotlin.script.experimental.util.PropertiesCollection
interface ScriptDefinition : PropertiesCollection { interface ScriptDefinitionKeys
companion object : ScriptDefinition { open class ScriptDefinition(baseDefinitions: Iterable<ScriptDefinition>, body: Builder.() -> Unit) :
PropertiesCollection(Builder(baseDefinitions).apply(body).data) {
class Builder internal constructor() : PropertiesCollection.Builder(), ScriptDefinition { constructor(body: Builder.() -> Unit = {}) : this(emptyList(), body)
override val properties = data constructor(vararg baseDefinitions: ScriptDefinition, body: Builder.() -> Unit = {}) : this(baseDefinitions.asIterable(), body)
}
fun create(body: Builder.() -> Unit): ScriptDefinition = Builder().apply(body) class Builder internal constructor(baseDefinitions: Iterable<ScriptDefinition>) :
ScriptDefinitionKeys,
PropertiesCollection.Builder(baseDefinitions)
// inherited from script definition for using as a keys anchor
companion object : ScriptDefinitionKeys {
val Default = ScriptDefinition()
} }
object Default : ScriptDefinition
} }
val ScriptDefinition.name by PropertiesCollection.key<String>("Kotlin script") // Name of the script type val ScriptDefinitionKeys.name by PropertiesCollection.key<String>("Kotlin script") // Name of the script type
val ScriptDefinition.fileExtension by PropertiesCollection.key<String>("kts") // file extension val ScriptDefinitionKeys.fileExtension by PropertiesCollection.key<String>("kts") // file extension
val ScriptDefinition.baseClass by PropertiesCollection.key<KotlinType>() // script base class val ScriptDefinitionKeys.baseClass by PropertiesCollection.key<KotlinType>() // script base class
val ScriptDefinition.scriptBodyTarget by PropertiesCollection.key<ScriptBodyTarget>(ScriptBodyTarget.Constructor) val ScriptDefinitionKeys.scriptBodyTarget by PropertiesCollection.key<ScriptBodyTarget>(ScriptBodyTarget.Constructor)
val ScriptDefinition.scriptImplicitReceivers by PropertiesCollection.key<List<KotlinType>>() // in the order from outer to inner scope val ScriptDefinitionKeys.scriptImplicitReceivers by PropertiesCollection.key<List<KotlinType>>() // in the order from outer to inner scope
val ScriptDefinition.contextVariables by PropertiesCollection.key<Map<String, KotlinType>>() // external variables val ScriptDefinitionKeys.contextVariables by PropertiesCollection.key<Map<String, KotlinType>>() // external variables
val ScriptDefinition.defaultImports by PropertiesCollection.key<List<String>>() val ScriptDefinitionKeys.defaultImports by PropertiesCollection.key<List<String>>()
val ScriptDefinition.restrictions by PropertiesCollection.key<List<ResolvingRestrictionRule>>() val ScriptDefinitionKeys.restrictions by PropertiesCollection.key<List<ResolvingRestrictionRule>>()
val ScriptDefinition.importedScripts by PropertiesCollection.key<List<ScriptSource>>() val ScriptDefinitionKeys.importedScripts by PropertiesCollection.key<List<ScriptSource>>()
val ScriptDefinition.dependencies by PropertiesCollection.key<List<ScriptDependency>>() val ScriptDefinitionKeys.dependencies by PropertiesCollection.key<List<ScriptDependency>>()
val ScriptDefinition.generatedClassAnnotations by PropertiesCollection.key<List<Annotation>>() val ScriptDefinitionKeys.generatedClassAnnotations by PropertiesCollection.key<List<Annotation>>()
val ScriptDefinition.generatedMethodAnnotations by PropertiesCollection.key<List<Annotation>>() val ScriptDefinitionKeys.generatedMethodAnnotations by PropertiesCollection.key<List<Annotation>>()
val ScriptDefinition.compilerOptions by PropertiesCollection.key<List<String>>() // Q: CommonCompilerOptions instead? val ScriptDefinitionKeys.compilerOptions by PropertiesCollection.key<List<String>>() // Q: CommonCompilerOptions instead?
val ScriptDefinition.refineConfigurationHandler by PropertiesCollection.key<RefineScriptCompilationConfigurationHandler>() // dynamic configurator val ScriptDefinitionKeys.refineConfigurationHandler by PropertiesCollection.key<RefineScriptCompilationConfigurationHandler>() // dynamic configurator
val ScriptDefinition.refineConfigurationBeforeParsing by PropertiesCollection.key<Boolean>() // default: false val ScriptDefinitionKeys.refineConfigurationBeforeParsing by PropertiesCollection.key<Boolean>() // default: false
val ScriptDefinition.refineConfigurationOnAnnotations by PropertiesCollection.key<List<KotlinType>>() val ScriptDefinitionKeys.refineConfigurationOnAnnotations by PropertiesCollection.key<List<KotlinType>>()
val ScriptDefinition.refineConfigurationOnSections by PropertiesCollection.key<List<String>>() val ScriptDefinitionKeys.refineConfigurationOnSections by PropertiesCollection.key<List<String>>()
// DSL: // DSL:
val ScriptDefinition.refineConfiguration get() = RefineConfigurationBuilder() val ScriptDefinition.Builder.refineConfiguration get() = RefineConfigurationBuilder()
class RefineConfigurationBuilder : PropertiesCollection.Builder() { class RefineConfigurationBuilder : PropertiesCollection.Builder() {
@@ -9,25 +9,30 @@ package kotlin.script.experimental.api
import kotlin.script.experimental.util.PropertiesCollection import kotlin.script.experimental.util.PropertiesCollection
interface ScriptEvaluationEnvironment : PropertiesCollection { interface ScriptEvaluationEnvironmentKeys
companion object : ScriptEvaluationEnvironment { class ScriptEvaluationEnvironment(baseEvaluationEnvironments: Iterable<ScriptEvaluationEnvironment>, body: Builder.() -> Unit) :
PropertiesCollection(Builder(baseEvaluationEnvironments).apply(body).data) {
class Builder internal constructor() : PropertiesCollection.Builder(), ScriptEvaluationEnvironment { constructor(body: Builder.() -> Unit = {}) : this(emptyList(), body)
override val properties = data constructor(
} vararg baseEvaluationEnvironments: ScriptEvaluationEnvironment, body: Builder.() -> Unit = {}
) : this(baseEvaluationEnvironments.asIterable(), body)
fun create(body: Builder.() -> Unit): ScriptEvaluationEnvironment = Builder().apply(body) class Builder internal constructor(baseEvaluationEnvironments: Iterable<ScriptEvaluationEnvironment>) :
} ScriptDefinitionKeys,
PropertiesCollection.Builder(baseEvaluationEnvironments)
companion object : ScriptEvaluationEnvironmentKeys
} }
val ScriptEvaluationEnvironment.implicitReceivers by PropertiesCollection.key<List<Any>>() val ScriptEvaluationEnvironmentKeys.implicitReceivers by PropertiesCollection.key<List<Any>>()
val ScriptEvaluationEnvironment.contextVariables by PropertiesCollection.key<Map<String, Any?>>() // external variables val ScriptEvaluationEnvironmentKeys.contextVariables by PropertiesCollection.key<Map<String, Any?>>() // external variables
val ScriptEvaluationEnvironment.constructorArgs by PropertiesCollection.key<List<Any?>>() val ScriptEvaluationEnvironmentKeys.constructorArgs by PropertiesCollection.key<List<Any?>>()
val ScriptEvaluationEnvironment.runArgs by PropertiesCollection.key<List<Any?>>() val ScriptEvaluationEnvironmentKeys.runArgs by PropertiesCollection.key<List<Any?>>()
sealed class ResultValue { sealed class ResultValue {
class Value(val name: String, val value: Any?, val type: String) : ResultValue() { class Value(val name: String, val value: Any?, val type: String) : ResultValue() {
@@ -7,37 +7,42 @@ package kotlin.script.experimental.api
import kotlin.reflect.KClass import kotlin.reflect.KClass
import kotlin.script.experimental.util.PropertiesCollection import kotlin.script.experimental.util.PropertiesCollection
import kotlin.script.experimental.util.getOrNull
interface ScriptingEnvironment : PropertiesCollection { interface ScriptingEnvironmentKeys
companion object : ScriptingEnvironment { class ScriptingEnvironment(baseScriptingEnvironments: Iterable<ScriptingEnvironment>, body: Builder.() -> Unit) :
PropertiesCollection(Builder(baseScriptingEnvironments).apply(body).data) {
class Builder internal constructor() : PropertiesCollection.Builder(), ScriptingEnvironment { constructor(body: Builder.() -> Unit = {}) : this(emptyList(), body)
override val properties = data constructor(
} vararg baseScriptingEnvironments: ScriptingEnvironment, body: Builder.() -> Unit = {}
) : this(baseScriptingEnvironments.asIterable(), body)
fun create(body: Builder.() -> Unit): ScriptingEnvironment = Builder().apply(body) class Builder internal constructor(baseScriptingEnvironments: Iterable<ScriptingEnvironment>) :
} ScriptingEnvironmentKeys,
PropertiesCollection.Builder(baseScriptingEnvironments)
companion object : ScriptingEnvironmentKeys
} }
// should contain all dependencies needed for baseClass and compilationConfigurator // should contain all dependencies needed for baseClass and compilationConfigurator
val ScriptingEnvironment.configurationDependencies by PropertiesCollection.key<List<ScriptDependency>>() val ScriptingEnvironmentKeys.configurationDependencies by PropertiesCollection.key<List<ScriptDependency>>()
// do not use configurationDependencies as script dependencies, so only the dependencies defined by compilationConfigurator will be used // 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 // (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) // compilation and instantiation, but compilationConfigurator could be excluded)
val ScriptingEnvironment.isolatedDependencies by PropertiesCollection.key<Boolean>(false) val ScriptingEnvironmentKeys.isolatedDependencies by PropertiesCollection.key<Boolean>(false)
// a "class loader" for KotlinTypes // a "class loader" for KotlinTypes
val ScriptingEnvironment.getScriptingClass by PropertiesCollection.key<GetScriptingClass>() val ScriptingEnvironmentKeys.getScriptingClass by PropertiesCollection.key<GetScriptingClass>()
interface GetScriptingClass { interface GetScriptingClass {
operator fun invoke(classType: KotlinType, contextClass: KClass<*>, environment: ScriptingEnvironment): KClass<*> operator fun invoke(classType: KotlinType, contextClass: KClass<*>, environment: ScriptingEnvironment): KClass<*>
} }
fun ScriptingEnvironment.getScriptingClass(type: KotlinType, contextClass: KClass<*>): KClass<*> { fun ScriptingEnvironment.getScriptingClass(type: KotlinType, contextClass: KClass<*>): KClass<*> {
val getClass = getOrNull(ScriptingEnvironment.getScriptingClass) val getClass = get(ScriptingEnvironment.getScriptingClass)
?: throw IllegalArgumentException("Expecting 'getScriptingClass' property in the scripting environment: unable to load scripting class $type") ?: throw IllegalArgumentException("Expecting 'getScriptingClass' property in the scripting environment: unable to load scripting class $type")
return getClass(type, contextClass, this) return getClass(type, contextClass, this)
} }
@@ -12,7 +12,6 @@ import kotlin.script.experimental.annotations.KotlinScript
import kotlin.script.experimental.annotations.KotlinScriptFileExtension import kotlin.script.experimental.annotations.KotlinScriptFileExtension
import kotlin.script.experimental.annotations.KotlinScriptProperties import kotlin.script.experimental.annotations.KotlinScriptProperties
import kotlin.script.experimental.api.* import kotlin.script.experimental.api.*
import kotlin.script.experimental.util.getOrNull
private const val ERROR_MSG_PREFIX = "Unable to construct script definition: " private const val ERROR_MSG_PREFIX = "Unable to construct script definition: "
@@ -25,7 +24,7 @@ fun createScriptDefinitionFromAnnotatedBaseClass(
contextClass: KClass<*> = ScriptDefinition::class contextClass: KClass<*> = ScriptDefinition::class
): ScriptDefinition { ): ScriptDefinition {
val getScriptingClass = environment.getOrNull(ScriptingEnvironment.getScriptingClass) val getScriptingClass = environment[ScriptingEnvironment.getScriptingClass]
?: throw IllegalArgumentException("${ERROR_MSG_PREFIX}Expecting 'getScriptingClass' parameter in the scripting environment") ?: throw IllegalArgumentException("${ERROR_MSG_PREFIX}Expecting 'getScriptingClass' parameter in the scripting environment")
val baseClass: KClass<*> = val baseClass: KClass<*> =
@@ -44,17 +43,15 @@ fun createScriptDefinitionFromAnnotatedBaseClass(
throw IllegalArgumentException(ILLEGAL_CONFIG_ANN_ARG, e) throw IllegalArgumentException(ILLEGAL_CONFIG_ANN_ARG, e)
} }
return object : ScriptDefinition { return ScriptDefinition {
override val properties = properties { baseClass(baseClassType)
baseClass(baseClassType) fileExtension(baseClass.findAnnotation<KotlinScriptFileExtension>()?.extension ?: mainAnnotation.extension)
fileExtension(baseClass.findAnnotation<KotlinScriptFileExtension>()?.extension ?: mainAnnotation.extension) name(mainAnnotation.name)
name(mainAnnotation.name)
include(scriptingPropsInstance(mainAnnotation.definition)) include(scriptingPropsInstance(mainAnnotation.definition))
baseClass.annotations.filterIsInstance(KotlinScriptProperties::class.java).forEach { ann -> baseClass.annotations.filterIsInstance(KotlinScriptProperties::class.java).forEach { ann ->
include(scriptingPropsInstance(ann.definition)) include(scriptingPropsInstance(ann.definition))
}
} }
} }
} }
@@ -11,7 +11,6 @@ import kotlin.script.experimental.api.ScriptCompileConfiguration
import kotlin.script.experimental.api.ScriptSource import kotlin.script.experimental.api.ScriptSource
import kotlin.script.experimental.api.ScriptSourceNamedFragment import kotlin.script.experimental.api.ScriptSourceNamedFragment
import kotlin.script.experimental.api.sourceFragments import kotlin.script.experimental.api.sourceFragments
import kotlin.script.experimental.util.getOrNull
fun ScriptSource.getScriptText(): String = when { fun ScriptSource.getScriptText(): String = when {
text != null -> text!! text != null -> text!!
@@ -22,7 +21,7 @@ fun ScriptSource.getScriptText(): String = when {
fun getMergedScriptText(script: ScriptSource, configuration: ScriptCompileConfiguration?): String { fun getMergedScriptText(script: ScriptSource, configuration: ScriptCompileConfiguration?): String {
val originalScriptText = script.getScriptText() val originalScriptText = script.getScriptText()
val sourceFragments = configuration?.getOrNull(ScriptCompileConfiguration.sourceFragments) val sourceFragments = configuration?.get(ScriptCompileConfiguration.sourceFragments)
return if (sourceFragments == null || sourceFragments.isEmpty()) { return if (sourceFragments == null || sourceFragments.isEmpty()) {
originalScriptText originalScriptText
} else { } else {
@@ -9,16 +9,21 @@ import kotlin.script.experimental.api.EvaluationResult
import kotlin.script.experimental.api.ResultWithDiagnostics import kotlin.script.experimental.api.ResultWithDiagnostics
import kotlin.script.experimental.util.PropertiesCollection import kotlin.script.experimental.util.PropertiesCollection
interface ReplEvaluationEnvironment : PropertiesCollection { interface ReplEvaluationEnvironmentKeys
companion object : ReplEvaluationEnvironment { class ReplEvaluationEnvironment(baseEvaluationEnvironments: Iterable<ReplEvaluationEnvironment>, body: Builder.() -> Unit) :
PropertiesCollection(Builder(baseEvaluationEnvironments).apply(body).data) {
class Builder internal constructor() : PropertiesCollection.Builder(), ReplEvaluationEnvironment { constructor(body: Builder.() -> Unit = {}) : this(emptyList(), body)
override val properties = data constructor(
} vararg baseEvaluationEnvironments: ReplEvaluationEnvironment, body: Builder.() -> Unit = {}
) : this(baseEvaluationEnvironments.asIterable(), body)
fun create(body: Builder.() -> Unit): ReplEvaluationEnvironment = Builder().apply(body) class Builder internal constructor(baseEvaluationEnvironments: Iterable<ReplEvaluationEnvironment>) :
} ReplEvaluationEnvironmentKeys,
PropertiesCollection.Builder(baseEvaluationEnvironments)
companion object : ReplEvaluationEnvironmentKeys
} }
interface ReplSnippetEvaluator { interface ReplSnippetEvaluator {
@@ -22,19 +22,24 @@ interface ReplCommandProcessor {
data class ReplCommand(val commandName: String, val processor: ReplCommandProcessor) data class ReplCommand(val commandName: String, val processor: ReplCommandProcessor)
interface ReplHostEnvironment : PropertiesCollection { interface ReplHostEnvironmentKeys
companion object : ReplHostEnvironment { class ReplHostEnvironment(baseReplHostEnvironments: Iterable<ReplHostEnvironment>, body: Builder.() -> Unit) :
PropertiesCollection(Builder(baseReplHostEnvironments).apply(body).data) {
class Builder internal constructor() : PropertiesCollection.Builder(), ReplHostEnvironment { constructor(body: Builder.() -> Unit = {}) : this(emptyList(), body)
override val properties = data constructor(
} vararg baseReplHostEnvironments: ReplHostEnvironment, body: Builder.() -> Unit = {}
) : this(baseReplHostEnvironments.asIterable(), body)
fun create(body: Builder.() -> Unit): ReplHostEnvironment = Builder().apply(body) class Builder internal constructor(baseReplHostEnvironments: Iterable<ReplHostEnvironment>) :
} ReplHostEnvironmentKeys,
PropertiesCollection.Builder(baseReplHostEnvironments)
companion object : ReplHostEnvironmentKeys
} }
val ReplHostEnvironment.replCommands by PropertiesCollection.key<List<ReplCommand>>() val ReplHostEnvironmentKeys.replCommands by PropertiesCollection.key<List<ReplCommand>>()
abstract class ReplHost( abstract class ReplHost(
val environment: ReplHostEnvironment, val environment: ReplHostEnvironment,
@@ -10,9 +10,7 @@ import kotlin.reflect.KProperty
import kotlin.reflect.KType import kotlin.reflect.KType
import kotlin.script.experimental.api.KotlinType import kotlin.script.experimental.api.KotlinType
interface PropertiesCollection { open class PropertiesCollection(val properties: Map<Key<*>, Any> = emptyMap()) {
val properties: Map<Key<*>, Any> get() = emptyMap()
data class Key<T>(val name: String, val defaultValue: T? = null) data class Key<T>(val name: String, val defaultValue: T? = null)
@@ -25,22 +23,27 @@ interface PropertiesCollection {
operator fun getValue(thisRef: Any?, property: KProperty<*>): Key<T> = source operator fun getValue(thisRef: Any?, property: KProperty<*>): Key<T> = source
} }
@Suppress("UNCHECKED_CAST")
operator fun <T> get(key: PropertiesCollection.Key<T>): T? =
properties[key]?.let { it as T } ?: key.defaultValue
companion object { companion object {
fun <T> key(defaultValue: T? = null) = PropertyKeyDelegate(defaultValue) fun <T> key(defaultValue: T? = null) = PropertyKeyDelegate(defaultValue)
fun <T> keyCopy(source: Key<T>) = PropertyKeyCopyDelegate(source) fun <T> keyCopy(source: Key<T>) = PropertyKeyCopyDelegate(source)
} }
fun properties(body: Builder.() -> Unit): Map<Key<*>, Any> = Builder().apply(body).data
// properties builder base class (DSL for building properties collection) // properties builder base class (DSL for building properties collection)
open class Builder { open class Builder(baseProperties: Iterable<PropertiesCollection> = emptyList()) {
val data: MutableMap<PropertiesCollection.Key<*>, Any> = LinkedHashMap() val data: MutableMap<PropertiesCollection.Key<*>, Any> = LinkedHashMap<PropertiesCollection.Key<*>, Any>().apply {
baseProperties.forEach { putAll(it.properties) }
}
// generic builder for all properties // generic builder for all properties
operator fun <T : Any> PropertiesCollection.Key<T>.invoke(v: T) { operator fun <T : Any> PropertiesCollection.Key<T>.invoke(v: T) {
set(this, v) data[this] = v
} }
// generic for lists // generic for lists
@@ -59,28 +62,28 @@ interface PropertiesCollection {
@JvmName("invoke_string_fqn_from_generic") @JvmName("invoke_string_fqn_from_generic")
inline operator fun <reified K> PropertiesCollection.Key<String>.invoke() { inline operator fun <reified K> PropertiesCollection.Key<String>.invoke() {
set(this, K::class.qualifiedName!!) data[this] = K::class.java.name
} }
@JvmName("invoke_string_fqn_from_reflected_class") @JvmName("invoke_string_fqn_from_reflected_class")
operator fun PropertiesCollection.Key<String>.invoke(kclass: KClass<*>) { operator fun PropertiesCollection.Key<String>.invoke(kclass: KClass<*>) {
set(this, kclass.qualifiedName!!) data[this] = kclass.java.name
} }
@JvmName("invoke_string_list_fqn_from_generic") @JvmName("invoke_string_list_fqn_from_generic")
inline operator fun <reified K> PropertiesCollection.Key<in List<String>>.invoke() { inline operator fun <reified K> PropertiesCollection.Key<in List<String>>.invoke() {
append(K::class.qualifiedName!!) append(K::class.java.name)
} }
@JvmName("invoke_string_list_fqn_from_reflected_class") @JvmName("invoke_string_list_fqn_from_reflected_class")
operator fun PropertiesCollection.Key<in List<String>>.invoke(vararg kclasses: KClass<*>) { operator fun PropertiesCollection.Key<in List<String>>.invoke(vararg kclasses: KClass<*>) {
append(kclasses.map { it.qualifiedName!! }) append(kclasses.map { it.java.name })
} }
// for KotlinType: // for KotlinType:
inline operator fun <reified K> PropertiesCollection.Key<KotlinType>.invoke() { inline operator fun <reified K> PropertiesCollection.Key<KotlinType>.invoke() {
set(this, KotlinType(K::class)) data[this] = KotlinType(K::class)
} }
operator fun PropertiesCollection.Key<KotlinType>.invoke(kclass: KClass<*>) { operator fun PropertiesCollection.Key<KotlinType>.invoke(kclass: KClass<*>) {
@@ -138,7 +141,7 @@ interface PropertiesCollection {
} }
@Suppress("UNCHECKED_CAST") @Suppress("UNCHECKED_CAST")
operator fun <T : Any> get(key: PropertiesCollection.Key<in T>): T? = data[key]?.let { it as T } private operator fun <T : Any> get(key: PropertiesCollection.Key<in T>): T? = data[key]?.let { it as T }
// appenders to list and map properties // appenders to list and map properties
@@ -174,15 +177,22 @@ interface PropertiesCollection {
this.body() this.body()
this@Builder.data.putAll(this.data) this@Builder.data.putAll(this.data)
} }
// a class for extending properties
interface BuilderExtension<T : Builder> {
fun get(): T
}
// include another builder extension
operator fun <T : Builder> BuilderExtension<T>.invoke(body: T.() -> Unit) {
val builder = this.get().apply(body)
this@Builder.data.putAll(builder.data)
}
} }
} }
@Suppress("UNCHECKED_CAST") fun <T> PropertiesCollection.getOrError(key: PropertiesCollection.Key<T>): T =
fun <T> PropertiesCollection.getOrNull(key: PropertiesCollection.Key<T>): T? = get(key) ?: throw IllegalArgumentException("Unknown key $key")
properties[key]?.let { it as T } ?: key.defaultValue
fun <T> PropertiesCollection.getOrError(key: PropertiesCollection.Key<T>): T =
getOrNull(key) ?: throw IllegalArgumentException("Unknown key $key")
@Suppress("UNCHECKED_CAST") @Suppress("UNCHECKED_CAST")
fun <T> getFirstFromChainOrNull(key: PropertiesCollection.Key<T>, vararg propertyCollections: PropertiesCollection?): T? { fun <T> getFirstFromChainOrNull(key: PropertiesCollection.Key<T>, vararg propertyCollections: PropertiesCollection?): T? {
@@ -193,16 +203,3 @@ fun <T> getFirstFromChainOrNull(key: PropertiesCollection.Key<T>, vararg propert
return key.defaultValue return key.defaultValue
} }
@Suppress("UNCHECKED_CAST")
fun <T> getMergedFromChainOrNull(key: PropertiesCollection.Key<List<T>>, vararg propertyCollections: PropertiesCollection?): List<T>? {
var found = false
val res = ArrayList<T>()
for (collection in propertyCollections) {
val value = collection?.properties?.get(key)
if (value != null) {
found = true
res.addAll(value as List<T>)
}
}
return if (found) res else key.defaultValue
}
@@ -40,16 +40,15 @@ import kotlin.script.experimental.api.*
import kotlin.script.experimental.dependencies.DependenciesResolver import kotlin.script.experimental.dependencies.DependenciesResolver
import kotlin.script.experimental.host.getMergedScriptText import kotlin.script.experimental.host.getMergedScriptText
import kotlin.script.experimental.jvm.JvmDependency import kotlin.script.experimental.jvm.JvmDependency
import kotlin.script.experimental.jvm.JvmScriptCompilationConfiguration
import kotlin.script.experimental.jvm.impl.BridgeDependenciesResolver import kotlin.script.experimental.jvm.impl.BridgeDependenciesResolver
import kotlin.script.experimental.jvm.javaHome import kotlin.script.experimental.jvm.javaHome
import kotlin.script.experimental.jvm.jvm
import kotlin.script.experimental.jvmhost.JvmScriptEvaluationEnvironment import kotlin.script.experimental.jvmhost.JvmScriptEvaluationEnvironment
import kotlin.script.experimental.jvmhost.KJvmCompilerProxy import kotlin.script.experimental.jvmhost.KJvmCompilerProxy
import kotlin.script.experimental.jvmhost.baseClassLoader import kotlin.script.experimental.jvmhost.baseClassLoader
import kotlin.script.experimental.util.getFirstFromChainOrNull import kotlin.script.experimental.util.getFirstFromChainOrNull
import kotlin.script.experimental.util.getMergedFromChainOrNull import kotlin.script.experimental.util.getMergedFromChainOrNull
import kotlin.script.experimental.util.getOrError import kotlin.script.experimental.util.getOrError
import kotlin.script.experimental.util.getOrNull
class KJvmCompiledScript<out ScriptBase : Any>( class KJvmCompiledScript<out ScriptBase : Any>(
override val definition: ScriptDefinition, override val definition: ScriptDefinition,
@@ -59,9 +58,9 @@ class KJvmCompiledScript<out ScriptBase : Any>(
) : CompiledScript<ScriptBase> { ) : CompiledScript<ScriptBase> {
override suspend fun instantiate(scriptEvaluationEnvironment: ScriptEvaluationEnvironment?): ResultWithDiagnostics<ScriptBase> = try { override suspend fun instantiate(scriptEvaluationEnvironment: ScriptEvaluationEnvironment?): ResultWithDiagnostics<ScriptBase> = try {
val baseClassLoader = scriptEvaluationEnvironment?.getOrNull(JvmScriptEvaluationEnvironment.baseClassLoader) val baseClassLoader = scriptEvaluationEnvironment?.get(JvmScriptEvaluationEnvironment.baseClassLoader)
?: Thread.currentThread().contextClassLoader ?: Thread.currentThread().contextClassLoader
val dependencies = additionalConfiguration?.getOrNull(ScriptDefinition.dependencies) val dependencies = additionalConfiguration?.get(ScriptDefinition.dependencies)
?.flatMap { (it as? JvmDependency)?.classpath?.map { it.toURI().toURL() } ?: emptyList() } ?.flatMap { (it as? JvmDependency)?.classpath?.map { it.toURI().toURL() } ?: emptyList() }
// TODO: previous dependencies and classloaders should be taken into account here // TODO: previous dependencies and classloaders should be taken into account here
val classLoaderWithDeps = val classLoaderWithDeps =
@@ -98,7 +97,7 @@ class KJvmCompilerImpl(val hostEnvironment: ScriptingEnvironment) : KJvmCompiler
fun updateClasspath(classpath: List<File>) { fun updateClasspath(classpath: List<File>) {
environment!!.updateClasspath(classpath.map(::JvmClasspathRoot)) environment!!.updateClasspath(classpath.map(::JvmClasspathRoot))
if (classpath.isNotEmpty()) { if (classpath.isNotEmpty()) {
updatedScriptCompileConfiguration = ScriptCompileConfiguration.create { updatedScriptCompileConfiguration = ScriptCompileConfiguration {
include(updatedScriptCompileConfiguration) include(updatedScriptCompileConfiguration)
dependencies.append(JvmDependency(classpath)) dependencies.append(JvmDependency(classpath))
} }
@@ -115,7 +114,7 @@ class KJvmCompilerImpl(val hostEnvironment: ScriptingEnvironment) : KJvmCompiler
put(JVMConfigurationKeys.RETAIN_OUTPUT_IN_MEMORY, true) put(JVMConfigurationKeys.RETAIN_OUTPUT_IN_MEMORY, true)
var isModularJava = false var isModularJava = false
getFirstFromChainOrNull(JvmScriptCompilationConfiguration.javaHome, updatedScriptCompileConfiguration, hostEnvironment)?.let { getFirstFromChainOrNull(ScriptCompileConfiguration.jvm.javaHome, updatedScriptCompileConfiguration, hostEnvironment)?.let {
put(JVMConfigurationKeys.JDK_HOME, it) put(JVMConfigurationKeys.JDK_HOME, it)
isModularJava = CoreJrtFileSystem.isModularJdk(it) isModularJava = CoreJrtFileSystem.isModularJdk(it)
} }
@@ -254,7 +253,7 @@ internal class BridgeScriptDefinition(
) { ) {
override val acceptedAnnotations = run { override val acceptedAnnotations = run {
val cl = this::class.java.classLoader val cl = this::class.java.classLoader
additionalCompilationConfiguration?.getOrNull(ScriptDefinition.refineConfigurationOnAnnotations) additionalCompilationConfiguration?.get(ScriptDefinition.refineConfigurationOnAnnotations)
?.map { (cl.loadClass(it.typeName) as Class<out Annotation>).kotlin } ?.map { (cl.loadClass(it.typeName) as Class<out Annotation>).kotlin }
?: emptyList() ?: emptyList()
} }
@@ -14,7 +14,7 @@ internal fun mergeConfigurations(vararg configurations: ScriptCompileConfigurati
return when { return when {
nonEmptyConfigurations.isEmpty() -> null nonEmptyConfigurations.isEmpty() -> null
nonEmptyConfigurations.size == 1 -> nonEmptyConfigurations.first()!! nonEmptyConfigurations.size == 1 -> nonEmptyConfigurations.first()!!
else -> ScriptCompileConfiguration.create { else -> ScriptCompileConfiguration {
for (configuration in nonEmptyConfigurations) { for (configuration in nonEmptyConfigurations) {
include(configuration!!) include(configuration!!)
} }
@@ -28,8 +28,5 @@ fun ScriptingEnvironment.withDefaults(): ScriptingEnvironment =
}) { }) {
this this
} else { } else {
ScriptingEnvironment.create { ScriptingEnvironment(defaultJvmScriptingEnvironment, this)
include(defaultJvmScriptingEnvironment)
include(this)
}
} }
@@ -12,7 +12,6 @@ import kotlin.script.experimental.jvm.defaultJvmScriptingEnvironment
import kotlin.script.experimental.jvmhost.impl.KJvmCompilerImpl import kotlin.script.experimental.jvmhost.impl.KJvmCompilerImpl
import kotlin.script.experimental.jvmhost.impl.mergeConfigurations import kotlin.script.experimental.jvmhost.impl.mergeConfigurations
import kotlin.script.experimental.jvmhost.impl.withDefaults import kotlin.script.experimental.jvmhost.impl.withDefaults
import kotlin.script.experimental.util.getOrNull
interface CompiledJvmScriptsCache { interface CompiledJvmScriptsCache {
fun get(script: ScriptSource, scriptDefinition: ScriptDefinition, configuration: ScriptCompileConfiguration?): CompiledScript<*>? fun get(script: ScriptSource, scriptDefinition: ScriptDefinition, configuration: ScriptCompileConfiguration?): CompiledScript<*>?
@@ -41,9 +40,9 @@ open class JvmScriptCompiler(
scriptDefinition: ScriptDefinition, scriptDefinition: ScriptDefinition,
additionalConfiguration: ScriptCompileConfiguration? additionalConfiguration: ScriptCompileConfiguration?
): ResultWithDiagnostics<CompiledScript<*>> { ): ResultWithDiagnostics<CompiledScript<*>> {
val refineConfigurationFn = scriptDefinition.getOrNull(ScriptDefinition.refineConfigurationHandler) val refineConfigurationFn = scriptDefinition[ScriptDefinition.refineConfigurationHandler]
val refinedConfiguration = val refinedConfiguration =
if (scriptDefinition.getOrNull(ScriptDefinition.refineConfigurationBeforeParsing) == true) { if (scriptDefinition[ScriptDefinition.refineConfigurationBeforeParsing] == true) {
if (refineConfigurationFn == null) { if (refineConfigurationFn == null) {
return ResultWithDiagnostics.Failure("Non-null configurator expected".asErrorDiagnostics()) return ResultWithDiagnostics.Failure("Non-null configurator expected".asErrorDiagnostics())
} }
@@ -9,7 +9,6 @@ package kotlin.script.experimental.jvmhost
import kotlin.script.experimental.api.* import kotlin.script.experimental.api.*
import kotlin.script.experimental.util.PropertiesCollection import kotlin.script.experimental.util.PropertiesCollection
import kotlin.script.experimental.util.getOrNull
open class JvmScriptEvaluationEnvironment : PropertiesCollection.Builder() { open class JvmScriptEvaluationEnvironment : PropertiesCollection.Builder() {
@@ -38,7 +37,7 @@ open class BasicJvmScriptEvaluator : ScriptEvaluator {
if (scriptObject !is Class<*>) if (scriptObject !is Class<*>)
ResultWithDiagnostics.Failure(ScriptDiagnostic("expecting class in this implementation, got ${scriptObject?.javaClass}")) ResultWithDiagnostics.Failure(ScriptDiagnostic("expecting class in this implementation, got ${scriptObject?.javaClass}"))
else { else {
val receivers = scriptEvaluationEnvironment?.getOrNull(ScriptEvaluationEnvironment.implicitReceivers) val receivers = scriptEvaluationEnvironment?.get(ScriptEvaluationEnvironment.implicitReceivers)
val instance = if (receivers == null) { val instance = if (receivers == null) {
scriptObject.getConstructor().newInstance() scriptObject.getConstructor().newInstance()
} else { } else {
@@ -19,7 +19,6 @@ import kotlin.script.experimental.jvm.JvmDependency
import kotlin.script.experimental.jvm.compat.mapToLegacyScriptReportPosition import kotlin.script.experimental.jvm.compat.mapToLegacyScriptReportPosition
import kotlin.script.experimental.jvm.compat.mapToLegacyScriptReportSeverity import kotlin.script.experimental.jvm.compat.mapToLegacyScriptReportSeverity
import kotlin.script.experimental.util.getFirstFromChainOrNull import kotlin.script.experimental.util.getFirstFromChainOrNull
import kotlin.script.experimental.util.getOrNull
class BridgeDependenciesResolver( class BridgeDependenciesResolver(
val scriptDefinition: ScriptDefinition, val scriptDefinition: ScriptDefinition,
@@ -36,13 +35,13 @@ class BridgeDependenciesResolver(
return try { return try {
val diagnostics = arrayListOf<ScriptReport>() val diagnostics = arrayListOf<ScriptReport>()
val processedScriptData = object : ProcessedScriptData { val processedScriptData = ProcessedScriptData(
override val properties = properties { mapOf(
foundAnnotations.append(scriptContents.annotations) ProcessedScriptData.foundAnnotations to scriptContents.annotations
} )
} )
val refineFn = scriptDefinition.getOrNull(ScriptDefinition.refineConfigurationHandler) val refineFn = scriptDefinition[ScriptDefinition.refineConfigurationHandler]
val refinedConfiguration = val refinedConfiguration =
if (refineFn == null) null if (refineFn == null) null
else { else {
@@ -59,7 +58,7 @@ class BridgeDependenciesResolver(
} }
} }
val newClasspath = refinedConfiguration?.getOrNull(ScriptDefinition.dependencies) val newClasspath = refinedConfiguration?.get(ScriptDefinition.dependencies)
?.flatMap { (it as JvmDependency).classpath } ?: emptyList() ?.flatMap { (it as JvmDependency).classpath } ?: emptyList()
if (newClasspath.isNotEmpty()) { if (newClasspath.isNotEmpty()) {
val oldClasspath = val oldClasspath =
@@ -7,14 +7,22 @@
package kotlin.script.experimental.jvm package kotlin.script.experimental.jvm
import kotlin.script.experimental.api.ScriptCompileConfiguration import kotlin.script.experimental.api.ScriptCompileConfigurationKeys
import kotlin.script.experimental.api.ScriptingEnvironment
import kotlin.script.experimental.util.PropertiesCollection import kotlin.script.experimental.util.PropertiesCollection
open class JvmScriptCompilationConfiguration : JvmScriptDefinition() { interface JvmScriptCompilationConfigurationKeys
companion object : JvmScriptCompilationConfiguration() open class JvmScriptCompilationConfigurationBuilder : JvmScriptCompilationConfigurationKeys, JvmScriptDefinition() {
companion object :
PropertiesCollection.Builder.BuilderExtension<JvmScriptCompilationConfigurationBuilder>,
JvmScriptCompilationConfigurationKeys {
override fun get() = JvmScriptCompilationConfigurationBuilder()
}
} }
val JvmScriptCompilationConfiguration.javaHome by PropertiesCollection.keyCopy(JvmScriptingEnvironment.javaHome) val JvmScriptCompilationConfigurationKeys.javaHome by PropertiesCollection.keyCopy(ScriptingEnvironment.jvm.javaHome)
val ScriptCompileConfiguration.jvm get() = JvmScriptCompilationConfiguration() val ScriptCompileConfigurationKeys.jvm get() = JvmScriptCompilationConfigurationBuilder()
@@ -8,16 +8,14 @@ package kotlin.script.experimental.jvm
import org.jetbrains.kotlin.script.util.scriptCompilationClasspathFromContext import org.jetbrains.kotlin.script.util.scriptCompilationClasspathFromContext
import java.io.File import java.io.File
import kotlin.script.experimental.api.ScriptDefinition import kotlin.script.experimental.api.ScriptDefinition
import kotlin.script.experimental.api.ScriptDefinitionKeys
import kotlin.script.experimental.api.ScriptDependency import kotlin.script.experimental.api.ScriptDependency
import kotlin.script.experimental.api.dependencies import kotlin.script.experimental.api.dependencies
import kotlin.script.experimental.util.PropertiesCollection import kotlin.script.experimental.util.PropertiesCollection
open class JvmScriptDefinition : PropertiesCollection.Builder() { open class JvmScriptDefinition : PropertiesCollection.Builder()
companion object : JvmScriptDefinition() val ScriptDefinitionKeys.jvm get() = JvmScriptDefinition()
}
val ScriptDefinition.jvm get() = JvmScriptDefinition()
class JvmDependency(val classpath: List<File>) : ScriptDependency { class JvmDependency(val classpath: List<File>) : ScriptDependency {
@@ -10,17 +10,23 @@ import java.net.URLClassLoader
import kotlin.reflect.KClass import kotlin.reflect.KClass
import kotlin.script.experimental.api.* import kotlin.script.experimental.api.*
import kotlin.script.experimental.util.PropertiesCollection import kotlin.script.experimental.util.PropertiesCollection
import kotlin.script.experimental.util.getOrNull
open class JvmScriptingEnvironment : PropertiesCollection.Builder() { interface JvmScriptingEnvironmentKeys
companion object : JvmScriptingEnvironment()
open class JvmScriptingEnvironmentBuilder : JvmScriptingEnvironmentKeys, PropertiesCollection.Builder() {
companion object : PropertiesCollection.Builder.BuilderExtension<JvmScriptingEnvironmentBuilder>, JvmScriptingEnvironmentKeys {
override fun get() = JvmScriptingEnvironmentBuilder()
}
} }
val JvmScriptingEnvironment.javaHome by PropertiesCollection.key<File>(File(System.getProperty("java.home"))) val JvmScriptingEnvironmentKeys.javaHome by PropertiesCollection.key<File>(File(System.getProperty("java.home")))
val ScriptingEnvironment.jvm get() = JvmScriptingEnvironment() @Suppress("unused")
val ScriptingEnvironmentKeys.jvm
get() = JvmScriptingEnvironmentBuilder
val defaultJvmScriptingEnvironment = ScriptingEnvironment.create { val defaultJvmScriptingEnvironment = ScriptingEnvironment {
getScriptingClass(JvmGetScriptingClass()) getScriptingClass(JvmGetScriptingClass())
} }
@@ -43,7 +49,7 @@ class JvmGetScriptingClass : GetScriptingClass {
if (actualClassLoadersChain.any { it == fromClass.java.classLoader }) return fromClass if (actualClassLoadersChain.any { it == fromClass.java.classLoader }) return fromClass
} }
val newDeps = environment.getOrNull(ScriptingEnvironment.configurationDependencies) val newDeps = environment[ScriptingEnvironment.configurationDependencies]
if (dependencies == null) { if (dependencies == null) {
dependencies = newDeps dependencies = newDeps
} else { } else {
@@ -62,7 +68,7 @@ class JvmGetScriptingClass : GetScriptingClass {
if (classLoader == null) { if (classLoader == null) {
val classpath = dependencies?.flatMap { dependency -> val classpath = dependencies?.flatMap { dependency ->
when(dependency) { when (dependency) {
is JvmDependency -> dependency.classpath.map { it.toURI().toURL() } is JvmDependency -> dependency.classpath.map { it.toURI().toURL() }
else -> throw IllegalArgumentException("unknown dependency type $dependency") else -> throw IllegalArgumentException("unknown dependency type $dependency")
} }
@@ -19,7 +19,6 @@ import kotlin.script.experimental.dependencies.DependenciesResolver
import kotlin.script.experimental.jvm.impl.BridgeDependenciesResolver import kotlin.script.experimental.jvm.impl.BridgeDependenciesResolver
import kotlin.script.experimental.location.ScriptExpectedLocation import kotlin.script.experimental.location.ScriptExpectedLocation
import kotlin.script.experimental.util.getOrError 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 // 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) { abstract class KotlinScriptDefinitionAdapterFromNewAPIBase : KotlinScriptDefinition(Any::class) {
@@ -37,7 +36,7 @@ abstract class KotlinScriptDefinitionAdapterFromNewAPIBase : KotlinScriptDefinit
override val template: KClass<*> get() = baseClass override val template: KClass<*> get() = baseClass
override val name: String override val name: String
get() = scriptDefinition.getOrNull(ScriptDefinition.name) ?: "Kotlin Script" get() = scriptDefinition[ScriptDefinition.name] ?: "Kotlin Script"
override val fileType: LanguageFileType = KotlinFileType.INSTANCE override val fileType: LanguageFileType = KotlinFileType.INSTANCE
@@ -57,24 +56,24 @@ abstract class KotlinScriptDefinitionAdapterFromNewAPIBase : KotlinScriptDefinit
} }
override val acceptedAnnotations: List<KClass<out Annotation>> by lazy(LazyThreadSafetyMode.PUBLICATION) { override val acceptedAnnotations: List<KClass<out Annotation>> by lazy(LazyThreadSafetyMode.PUBLICATION) {
scriptDefinition.getOrNull(ScriptDefinition.refineConfigurationOnAnnotations) scriptDefinition[ScriptDefinition.refineConfigurationOnAnnotations]
.orEmpty() .orEmpty()
.map { getScriptingClass(it) as KClass<out Annotation> } .map { getScriptingClass(it) as KClass<out Annotation> }
} }
override val implicitReceivers: List<KType> by lazy(LazyThreadSafetyMode.PUBLICATION) { override val implicitReceivers: List<KType> by lazy(LazyThreadSafetyMode.PUBLICATION) {
scriptDefinition.getOrNull(ScriptDefinition.scriptImplicitReceivers) scriptDefinition[ScriptDefinition.scriptImplicitReceivers]
.orEmpty() .orEmpty()
.map { getScriptingClass(it).starProjectedType } .map { getScriptingClass(it).starProjectedType }
} }
override val environmentVariables: List<Pair<String, KType>> by lazy(LazyThreadSafetyMode.PUBLICATION) { override val environmentVariables: List<Pair<String, KType>> by lazy(LazyThreadSafetyMode.PUBLICATION) {
scriptDefinition.getOrNull(ScriptDefinition.contextVariables) scriptDefinition[ScriptDefinition.contextVariables]
?.map { (k, v) -> k to getScriptingClass(v).starProjectedType }.orEmpty() ?.map { (k, v) -> k to getScriptingClass(v).starProjectedType }.orEmpty()
} }
override val additionalCompilerArguments: List<String> override val additionalCompilerArguments: List<String>
get() = scriptDefinition.getOrNull(ScriptDefinition.compilerOptions) get() = scriptDefinition[ScriptDefinition.compilerOptions]
.orEmpty() .orEmpty()
override val scriptExpectedLocations: List<ScriptExpectedLocation> = override val scriptExpectedLocations: List<ScriptExpectedLocation> =
@@ -84,15 +83,15 @@ abstract class KotlinScriptDefinitionAdapterFromNewAPIBase : KotlinScriptDefinit
) )
override val targetClassAnnotations: List<Annotation> override val targetClassAnnotations: List<Annotation>
get() = scriptDefinition.getOrNull(ScriptDefinition.generatedClassAnnotations) get() = scriptDefinition[ScriptDefinition.generatedClassAnnotations]
.orEmpty() .orEmpty()
override val targetMethodAnnotations: List<Annotation> override val targetMethodAnnotations: List<Annotation>
get() = scriptDefinition.getOrNull(ScriptDefinition.generatedMethodAnnotations) get() = scriptDefinition[ScriptDefinition.generatedMethodAnnotations]
.orEmpty() .orEmpty()
private val scriptingClassGetter by lazy(LazyThreadSafetyMode.PUBLICATION) { private val scriptingClassGetter by lazy(LazyThreadSafetyMode.PUBLICATION) {
hostEnvironment.getOrNull(ScriptingEnvironment.getScriptingClass) hostEnvironment[ScriptingEnvironment.getScriptingClass]
?: throw IllegalArgumentException("Expecting 'getScriptingClass' property in the scripting environment") ?: throw IllegalArgumentException("Expecting 'getScriptingClass' property in the scripting environment")
} }
@@ -110,8 +109,8 @@ class KotlinScriptDefinitionAdapterFromNewAPI(
override val hostEnvironment: ScriptingEnvironment override val hostEnvironment: ScriptingEnvironment
) : KotlinScriptDefinitionAdapterFromNewAPIBase() { ) : KotlinScriptDefinitionAdapterFromNewAPIBase() {
override val name: String get() = scriptDefinition.getOrNull(ScriptDefinition.name) ?: super.name override val name: String get() = scriptDefinition[ScriptDefinition.name] ?: super.name
override val scriptFileExtensionWithDot = override val scriptFileExtensionWithDot =
"." + (scriptDefinition.getOrNull(ScriptDefinition.fileExtension) ?: "kts") "." + (scriptDefinition[ScriptDefinition.fileExtension] ?: "kts")
} }
@@ -19,7 +19,6 @@ import kotlin.script.experimental.api.*
import kotlin.script.experimental.definitions.createScriptDefinitionFromAnnotatedBaseClass import kotlin.script.experimental.definitions.createScriptDefinitionFromAnnotatedBaseClass
import kotlin.script.experimental.jvm.JvmDependency import kotlin.script.experimental.jvm.JvmDependency
import kotlin.script.experimental.jvm.defaultJvmScriptingEnvironment import kotlin.script.experimental.jvm.defaultJvmScriptingEnvironment
import kotlin.script.experimental.util.getOrNull
class LazyScriptDefinitionFromDiscoveredClass internal constructor( class LazyScriptDefinitionFromDiscoveredClass internal constructor(
private val annotationsFromAsm: ArrayList<BinAnnData>, private val annotationsFromAsm: ArrayList<BinAnnData>,
@@ -36,7 +35,7 @@ class LazyScriptDefinitionFromDiscoveredClass internal constructor(
) : this(loadAnnotationsFromClass(classBytes), className, classpath, messageCollector) ) : this(loadAnnotationsFromClass(classBytes), className, classpath, messageCollector)
override val hostEnvironment: ScriptingEnvironment by lazy(LazyThreadSafetyMode.PUBLICATION) { override val hostEnvironment: ScriptingEnvironment by lazy(LazyThreadSafetyMode.PUBLICATION) {
ScriptingEnvironment.create { ScriptingEnvironment {
include(defaultJvmScriptingEnvironment) include(defaultJvmScriptingEnvironment)
configurationDependencies(JvmDependency(classpath)) configurationDependencies(JvmDependency(classpath))
} }
@@ -70,7 +69,7 @@ class LazyScriptDefinitionFromDiscoveredClass internal constructor(
// TODO: check whether it actually works // TODO: check whether it actually works
?: annotationsFromAsm.find { it.name == KotlinScript::class.simpleName }?.args?.get(1) ?: annotationsFromAsm.find { it.name == KotlinScript::class.simpleName }?.args?.get(1)
?: scriptDefinition.let { ?: scriptDefinition.let {
it.getOrNull(ScriptDefinition.fileExtension) ?: "kts" it[ScriptDefinition.fileExtension] ?: "kts"
} }
".$ext" ".$ext"
} }
@@ -81,4 +80,4 @@ class LazyScriptDefinitionFromDiscoveredClass internal constructor(
} }
} }
object InvalidScriptDefinition : ScriptDefinition val InvalidScriptDefinition = ScriptDefinition()