Introducing transient properties in scripting API
This commit is contained in:
@@ -130,17 +130,17 @@ val ScriptCompilationConfigurationKeys.compilerOptions by PropertiesCollection.k
|
|||||||
/**
|
/**
|
||||||
* The callback that will be called on the script compilation before parsing the script
|
* The callback that will be called on the script compilation before parsing the script
|
||||||
*/
|
*/
|
||||||
val ScriptCompilationConfigurationKeys.refineConfigurationBeforeParsing by PropertiesCollection.key<List<RefineConfigurationUnconditionallyData>>()
|
val ScriptCompilationConfigurationKeys.refineConfigurationBeforeParsing by PropertiesCollection.key<List<RefineConfigurationUnconditionallyData>>(isTransient = true)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The callback that will be called on the script compilation after parsing script file annotations
|
* The callback that will be called on the script compilation after parsing script file annotations
|
||||||
*/
|
*/
|
||||||
val ScriptCompilationConfigurationKeys.refineConfigurationOnAnnotations by PropertiesCollection.key<List<RefineConfigurationOnAnnotationsData>>()
|
val ScriptCompilationConfigurationKeys.refineConfigurationOnAnnotations by PropertiesCollection.key<List<RefineConfigurationOnAnnotationsData>>(isTransient = true)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The callback that will be called on the script compilation immediately before starting the compilation
|
* The callback that will be called on the script compilation immediately before starting the compilation
|
||||||
*/
|
*/
|
||||||
val ScriptCompilationConfigurationKeys.refineConfigurationBeforeCompiling by PropertiesCollection.key<List<RefineConfigurationUnconditionallyData>>()
|
val ScriptCompilationConfigurationKeys.refineConfigurationBeforeCompiling by PropertiesCollection.key<List<RefineConfigurationUnconditionallyData>>(isTransient = true)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The list of script fragments that should be compiled intead of the whole text
|
* The list of script fragments that should be compiled intead of the whole text
|
||||||
@@ -151,7 +151,7 @@ val ScriptCompilationConfigurationKeys.sourceFragments by PropertiesCollection.k
|
|||||||
/**
|
/**
|
||||||
* Scripting host configuration
|
* Scripting host configuration
|
||||||
*/
|
*/
|
||||||
val ScriptCompilationConfigurationKeys.hostConfiguration by PropertiesCollection.key<ScriptingHostConfiguration>()
|
val ScriptCompilationConfigurationKeys.hostConfiguration by PropertiesCollection.key<ScriptingHostConfiguration>(isTransient = true)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The sub-builder DSL for configuring refinement callbacks
|
* The sub-builder DSL for configuring refinement callbacks
|
||||||
|
|||||||
@@ -68,10 +68,10 @@ val ScriptEvaluationConfigurationKeys.constructorArgs by PropertiesCollection.ke
|
|||||||
* For the first snippet in a REPL an empty list should be passed explicitly
|
* For the first snippet in a REPL an empty list should be passed explicitly
|
||||||
* An array of the previous snippets will be passed to the current snippet constructor
|
* An array of the previous snippets will be passed to the current snippet constructor
|
||||||
*/
|
*/
|
||||||
val ScriptEvaluationConfigurationKeys.previousSnippets by PropertiesCollection.key<List<Any>>()
|
val ScriptEvaluationConfigurationKeys.previousSnippets by PropertiesCollection.key<List<Any>>(isTransient = true)
|
||||||
|
|
||||||
@Deprecated("use scriptsInstancesSharing flag instead", level = DeprecationLevel.ERROR)
|
@Deprecated("use scriptsInstancesSharing flag instead", level = DeprecationLevel.ERROR)
|
||||||
val ScriptEvaluationConfigurationKeys.scriptsInstancesSharingMap by PropertiesCollection.key<MutableMap<KClass<*>, EvaluationResult>>()
|
val ScriptEvaluationConfigurationKeys.scriptsInstancesSharingMap by PropertiesCollection.key<MutableMap<KClass<*>, EvaluationResult>>(isTransient = true)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* If enabled - the evaluator will try to get imported script from a shared container
|
* If enabled - the evaluator will try to get imported script from a shared container
|
||||||
@@ -83,12 +83,12 @@ val ScriptEvaluationConfigurationKeys.scriptsInstancesSharing by PropertiesColle
|
|||||||
/**
|
/**
|
||||||
* Scripting host configuration
|
* Scripting host configuration
|
||||||
*/
|
*/
|
||||||
val ScriptEvaluationConfigurationKeys.hostConfiguration by PropertiesCollection.key<ScriptingHostConfiguration>()
|
val ScriptEvaluationConfigurationKeys.hostConfiguration by PropertiesCollection.key<ScriptingHostConfiguration>(isTransient = true)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The callback that will be called on the script compilation immediately before starting the compilation
|
* The callback that will be called on the script compilation immediately before starting the compilation
|
||||||
*/
|
*/
|
||||||
val ScriptEvaluationConfigurationKeys.refineConfigurationBeforeEvaluate by PropertiesCollection.key<List<RefineEvaluationConfigurationData>>()
|
val ScriptEvaluationConfigurationKeys.refineConfigurationBeforeEvaluate by PropertiesCollection.key<List<RefineEvaluationConfigurationData>>(isTransient = true)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A helper to enable scriptsInstancesSharingMap with default implementation
|
* A helper to enable scriptsInstancesSharingMap with default implementation
|
||||||
|
|||||||
@@ -50,7 +50,7 @@ val ScriptingHostConfigurationKeys.configurationDependencies by PropertiesCollec
|
|||||||
/**
|
/**
|
||||||
* The pointer to the generic "class loader" for the types used in the script configurations
|
* The pointer to the generic "class loader" for the types used in the script configurations
|
||||||
*/
|
*/
|
||||||
val ScriptingHostConfigurationKeys.getScriptingClass by PropertiesCollection.key<GetScriptingClass>()
|
val ScriptingHostConfigurationKeys.getScriptingClass by PropertiesCollection.key<GetScriptingClass>(isTransient = true)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The interface to the generic "class loader" for the types used in the script configurations
|
* The interface to the generic "class loader" for the types used in the script configurations
|
||||||
|
|||||||
+33
-7
@@ -5,15 +5,20 @@
|
|||||||
|
|
||||||
package kotlin.script.experimental.util
|
package kotlin.script.experimental.util
|
||||||
|
|
||||||
|
import java.io.ObjectInputStream
|
||||||
|
import java.io.ObjectOutputStream
|
||||||
import java.io.Serializable
|
import java.io.Serializable
|
||||||
import kotlin.reflect.KClass
|
import kotlin.reflect.KClass
|
||||||
import kotlin.reflect.KProperty
|
import kotlin.reflect.KProperty
|
||||||
import kotlin.reflect.KType
|
import kotlin.reflect.KType
|
||||||
import kotlin.script.experimental.api.KotlinType
|
import kotlin.script.experimental.api.KotlinType
|
||||||
|
|
||||||
open class PropertiesCollection(private val properties: Map<Key<*>, Any?> = emptyMap()) : Serializable {
|
open class PropertiesCollection(private var properties: Map<Key<*>, Any?> = emptyMap()) : Serializable {
|
||||||
|
|
||||||
class Key<T>(val name: String, @Transient val getDefaultValue: PropertiesCollection.() -> T?) : Serializable {
|
open class Key<T>(
|
||||||
|
val name: String,
|
||||||
|
@Transient val getDefaultValue: PropertiesCollection.() -> T?
|
||||||
|
) : Serializable {
|
||||||
|
|
||||||
constructor(name: String, defaultValue: T? = null) : this(name, { defaultValue })
|
constructor(name: String, defaultValue: T? = null) : this(name, { defaultValue })
|
||||||
|
|
||||||
@@ -27,11 +32,17 @@ open class PropertiesCollection(private val properties: Map<Key<*>, Any?> = empt
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class PropertyKeyDelegate<T>(private val getDefaultValue: PropertiesCollection.() -> T?) {
|
class TransientKey<T>(
|
||||||
constructor(defaultValue: T?) : this({ defaultValue })
|
name: String,
|
||||||
|
getDefaultValue: PropertiesCollection.() -> T?
|
||||||
|
) : Key<T>(name, getDefaultValue)
|
||||||
|
|
||||||
|
class PropertyKeyDelegate<T>(private val getDefaultValue: PropertiesCollection.() -> T?, val isTransient: Boolean = false) {
|
||||||
|
constructor(defaultValue: T?, isTransient: Boolean = false) : this({ defaultValue }, isTransient)
|
||||||
|
|
||||||
operator fun getValue(thisRef: Any?, property: KProperty<*>): Key<T> =
|
operator fun getValue(thisRef: Any?, property: KProperty<*>): Key<T> =
|
||||||
Key(property.name, getDefaultValue)
|
if (isTransient) TransientKey(property.name, getDefaultValue)
|
||||||
|
else Key(property.name, getDefaultValue)
|
||||||
}
|
}
|
||||||
|
|
||||||
class PropertyKeyCopyDelegate<T>(val source: Key<T>) {
|
class PropertyKeyCopyDelegate<T>(val source: Key<T>) {
|
||||||
@@ -51,14 +62,29 @@ open class PropertiesCollection(private val properties: Map<Key<*>, Any?> = empt
|
|||||||
|
|
||||||
fun entries(): Set<Map.Entry<Key<*>, Any?>> = properties.entries
|
fun entries(): Set<Map.Entry<Key<*>, Any?>> = properties.entries
|
||||||
|
|
||||||
|
val notTransientData: Map<Key<*>, Any?> get() = properties.filterKeys { it !is TransientKey<*>}
|
||||||
|
|
||||||
override fun equals(other: Any?): Boolean =
|
override fun equals(other: Any?): Boolean =
|
||||||
(other as? PropertiesCollection)?.let { it.properties == properties } == true
|
(other as? PropertiesCollection)?.let { it.properties == properties } == true
|
||||||
|
|
||||||
override fun hashCode(): Int = properties.hashCode()
|
override fun hashCode(): Int = properties.hashCode()
|
||||||
|
|
||||||
|
private fun writeObject(outputStream: ObjectOutputStream) {
|
||||||
|
outputStream.writeObject(notTransientData)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun readObject(inputStream: ObjectInputStream) {
|
||||||
|
@Suppress("UNCHECKED_CAST")
|
||||||
|
properties = inputStream.readObject() as Map<Key<*>, Any?>
|
||||||
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
fun <T> key(defaultValue: T? = null): PropertyKeyDelegate<T> = PropertyKeyDelegate(defaultValue)
|
fun <T> key(defaultValue: T? = null, isTransient: Boolean = false): PropertyKeyDelegate<T> =
|
||||||
fun <T> key(getDefaultValue: PropertiesCollection.() -> T?): PropertyKeyDelegate<T> = PropertyKeyDelegate(getDefaultValue)
|
PropertyKeyDelegate(defaultValue, isTransient)
|
||||||
|
|
||||||
|
fun <T> key(getDefaultValue: PropertiesCollection.() -> T?, isTransient: Boolean = false): PropertyKeyDelegate<T> =
|
||||||
|
PropertyKeyDelegate(getDefaultValue, isTransient)
|
||||||
|
|
||||||
fun <T> keyCopy(source: Key<T>): PropertyKeyCopyDelegate<T> = PropertyKeyCopyDelegate(source)
|
fun <T> keyCopy(source: Key<T>): PropertyKeyCopyDelegate<T> = PropertyKeyCopyDelegate(source)
|
||||||
|
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
|
|||||||
+10
-8
@@ -128,7 +128,7 @@ class CachingTest : TestCase() {
|
|||||||
Assert.assertEquals(1, cache.storedScripts)
|
Assert.assertEquals(1, cache.storedScripts)
|
||||||
Assert.assertEquals(0, cache.retrievedScripts)
|
Assert.assertEquals(0, cache.retrievedScripts)
|
||||||
|
|
||||||
val cachedScript = cache.get(script.toScriptSource(), scriptCompilationConfiguration)
|
val cachedScript = cache.get(script.toScriptSource(), compiledScript!!.compilationConfiguration)
|
||||||
Assert.assertNotNull(cachedScript)
|
Assert.assertNotNull(cachedScript)
|
||||||
Assert.assertEquals(1, cache.retrievedScripts)
|
Assert.assertEquals(1, cache.retrievedScripts)
|
||||||
|
|
||||||
@@ -164,7 +164,7 @@ private interface ScriptingCacheWithCounters : CompiledJvmScriptsCache {
|
|||||||
|
|
||||||
private class SimpleMemoryScriptsCache : ScriptingCacheWithCounters {
|
private class SimpleMemoryScriptsCache : ScriptingCacheWithCounters {
|
||||||
|
|
||||||
internal val data = hashMapOf<Pair<SourceCode, ScriptCompilationConfiguration>, CompiledScript<*>>()
|
internal val data = hashMapOf<Pair<SourceCode, Map<*, *>>, CompiledScript<*>>()
|
||||||
|
|
||||||
private var _storedScripts = 0
|
private var _storedScripts = 0
|
||||||
private var _retrievedScripts = 0
|
private var _retrievedScripts = 0
|
||||||
@@ -176,14 +176,14 @@ private class SimpleMemoryScriptsCache : ScriptingCacheWithCounters {
|
|||||||
get() = _retrievedScripts
|
get() = _retrievedScripts
|
||||||
|
|
||||||
override fun get(script: SourceCode, scriptCompilationConfiguration: ScriptCompilationConfiguration): CompiledScript<*>? =
|
override fun get(script: SourceCode, scriptCompilationConfiguration: ScriptCompilationConfiguration): CompiledScript<*>? =
|
||||||
data[script to scriptCompilationConfiguration]?.also { _retrievedScripts++ }
|
data[script to scriptCompilationConfiguration.notTransientData]?.also { _retrievedScripts++ }
|
||||||
|
|
||||||
override fun store(
|
override fun store(
|
||||||
compiledScript: CompiledScript<*>,
|
compiledScript: CompiledScript<*>,
|
||||||
script: SourceCode,
|
script: SourceCode,
|
||||||
scriptCompilationConfiguration: ScriptCompilationConfiguration
|
scriptCompilationConfiguration: ScriptCompilationConfiguration
|
||||||
) {
|
) {
|
||||||
data[script to scriptCompilationConfiguration] = compiledScript
|
data[script to scriptCompilationConfiguration.notTransientData] = compiledScript
|
||||||
_storedScripts++
|
_storedScripts++
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -242,10 +242,12 @@ class TestCompiledScriptJarsCache(val baseDir: File) : CompiledScriptJarsCache(
|
|||||||
internal fun uniqueScriptHash(script: SourceCode, scriptCompilationConfiguration: ScriptCompilationConfiguration): String {
|
internal fun uniqueScriptHash(script: SourceCode, scriptCompilationConfiguration: ScriptCompilationConfiguration): String {
|
||||||
val digestWrapper = MessageDigest.getInstance("MD5")
|
val digestWrapper = MessageDigest.getInstance("MD5")
|
||||||
digestWrapper.update(script.text.toByteArray())
|
digestWrapper.update(script.text.toByteArray())
|
||||||
scriptCompilationConfiguration.entries().sortedBy { it.key.name }.forEach {
|
scriptCompilationConfiguration.notTransientData.entries
|
||||||
digestWrapper.update(it.key.name.toByteArray())
|
.sortedBy { it.key.name }
|
||||||
digestWrapper.update(it.value.toString().toByteArray())
|
.forEach {
|
||||||
}
|
digestWrapper.update(it.key.name.toByteArray())
|
||||||
|
digestWrapper.update(it.value.toString().toByteArray())
|
||||||
|
}
|
||||||
return digestWrapper.digest().toHexString()
|
return digestWrapper.digest().toHexString()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+12
-6
@@ -32,9 +32,12 @@ open class Jsr223CompilationConfigurationBuilder : PropertiesCollection.Builder(
|
|||||||
|
|
||||||
val ScriptCompilationConfigurationKeys.jsr223 get() = Jsr223CompilationConfigurationBuilder()
|
val ScriptCompilationConfigurationKeys.jsr223 get() = Jsr223CompilationConfigurationBuilder()
|
||||||
|
|
||||||
val Jsr223CompilationConfigurationKeys.getScriptContext by PropertiesCollection.key<() -> ScriptContext?> {
|
val Jsr223CompilationConfigurationKeys.getScriptContext by PropertiesCollection.key<() -> ScriptContext?>(
|
||||||
get(ScriptCompilationConfiguration.hostConfiguration)?.get(ScriptingHostConfiguration.jsr223.getScriptContext)
|
{
|
||||||
}
|
get(ScriptCompilationConfiguration.hostConfiguration)?.get(ScriptingHostConfiguration.jsr223.getScriptContext)
|
||||||
|
},
|
||||||
|
isTransient = true
|
||||||
|
)
|
||||||
|
|
||||||
val Jsr223CompilationConfigurationKeys.importAllBindings by PropertiesCollection.key<Boolean>(false)
|
val Jsr223CompilationConfigurationKeys.importAllBindings by PropertiesCollection.key<Boolean>(false)
|
||||||
|
|
||||||
@@ -47,8 +50,11 @@ open class Jsr223EvaluationConfigurationBuilder : PropertiesCollection.Builder()
|
|||||||
|
|
||||||
val ScriptEvaluationConfigurationKeys.jsr223 get() = Jsr223EvaluationConfigurationBuilder()
|
val ScriptEvaluationConfigurationKeys.jsr223 get() = Jsr223EvaluationConfigurationBuilder()
|
||||||
|
|
||||||
val Jsr223EvaluationConfigurationKeys.getScriptContext by PropertiesCollection.key<() -> ScriptContext?> {
|
val Jsr223EvaluationConfigurationKeys.getScriptContext by PropertiesCollection.key<() -> ScriptContext?>(
|
||||||
get(ScriptEvaluationConfiguration.hostConfiguration)?.get(ScriptingHostConfiguration.jsr223.getScriptContext)
|
{
|
||||||
}
|
get(ScriptEvaluationConfiguration.hostConfiguration)?.get(ScriptingHostConfiguration.jsr223.getScriptContext)
|
||||||
|
},
|
||||||
|
isTransient = true
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -8,7 +8,10 @@
|
|||||||
package kotlin.script.experimental.jvm
|
package kotlin.script.experimental.jvm
|
||||||
|
|
||||||
import kotlin.reflect.KClass
|
import kotlin.reflect.KClass
|
||||||
import kotlin.script.experimental.api.*
|
import kotlin.script.experimental.api.EvaluationResult
|
||||||
|
import kotlin.script.experimental.api.ScriptEvaluationConfiguration
|
||||||
|
import kotlin.script.experimental.api.ScriptEvaluationConfigurationKeys
|
||||||
|
import kotlin.script.experimental.api.hostConfiguration
|
||||||
import kotlin.script.experimental.host.ScriptingHostConfiguration
|
import kotlin.script.experimental.host.ScriptingHostConfiguration
|
||||||
import kotlin.script.experimental.util.PropertiesCollection
|
import kotlin.script.experimental.util.PropertiesCollection
|
||||||
|
|
||||||
@@ -22,10 +25,13 @@ open class JvmScriptEvaluationConfigurationBuilder : PropertiesCollection.Builde
|
|||||||
/**
|
/**
|
||||||
* The base classloader to use for script classes loading
|
* The base classloader to use for script classes loading
|
||||||
*/
|
*/
|
||||||
val JvmScriptEvaluationConfigurationKeys.baseClassLoader by PropertiesCollection.key<ClassLoader?> {
|
val JvmScriptEvaluationConfigurationKeys.baseClassLoader by PropertiesCollection.key<ClassLoader?>(
|
||||||
get(ScriptEvaluationConfiguration.hostConfiguration)?.get(ScriptingHostConfiguration.jvm.baseClassLoader)
|
{
|
||||||
?: Thread.currentThread().contextClassLoader
|
get(ScriptEvaluationConfiguration.hostConfiguration)?.get(ScriptingHostConfiguration.jvm.baseClassLoader)
|
||||||
}
|
?: Thread.currentThread().contextClassLoader
|
||||||
|
},
|
||||||
|
isTransient = true
|
||||||
|
)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Load script dependencies before evaluation, true by default
|
* Load script dependencies before evaluation, true by default
|
||||||
@@ -38,8 +44,10 @@ val JvmScriptEvaluationConfigurationKeys.loadDependencies by PropertiesCollectio
|
|||||||
*/
|
*/
|
||||||
val JvmScriptEvaluationConfigurationKeys.mainArguments by PropertiesCollection.key<Array<out String>>()
|
val JvmScriptEvaluationConfigurationKeys.mainArguments by PropertiesCollection.key<Array<out String>>()
|
||||||
|
|
||||||
internal val JvmScriptEvaluationConfigurationKeys.actualClassLoader by PropertiesCollection.key<ClassLoader?>()
|
internal val JvmScriptEvaluationConfigurationKeys.actualClassLoader by PropertiesCollection.key<ClassLoader?>(isTransient = true)
|
||||||
|
|
||||||
internal val JvmScriptEvaluationConfigurationKeys.scriptsInstancesSharingMap by PropertiesCollection.key<MutableMap<KClass<*>, EvaluationResult>>()
|
internal val JvmScriptEvaluationConfigurationKeys.scriptsInstancesSharingMap by PropertiesCollection.key<MutableMap<KClass<*>, EvaluationResult>>(
|
||||||
|
isTransient = true
|
||||||
|
)
|
||||||
|
|
||||||
val ScriptEvaluationConfigurationKeys.jvm get() = JvmScriptEvaluationConfigurationBuilder()
|
val ScriptEvaluationConfigurationKeys.jvm get() = JvmScriptEvaluationConfigurationBuilder()
|
||||||
|
|||||||
+10
-6
@@ -9,7 +9,8 @@ import java.io.File
|
|||||||
import java.io.Serializable
|
import java.io.Serializable
|
||||||
import java.net.URLClassLoader
|
import java.net.URLClassLoader
|
||||||
import kotlin.reflect.KClass
|
import kotlin.reflect.KClass
|
||||||
import kotlin.script.experimental.api.*
|
import kotlin.script.experimental.api.KotlinType
|
||||||
|
import kotlin.script.experimental.api.ScriptDependency
|
||||||
import kotlin.script.experimental.host.*
|
import kotlin.script.experimental.host.*
|
||||||
import kotlin.script.experimental.jvm.impl.toClassPathOrEmpty
|
import kotlin.script.experimental.jvm.impl.toClassPathOrEmpty
|
||||||
import kotlin.script.experimental.util.PropertiesCollection
|
import kotlin.script.experimental.util.PropertiesCollection
|
||||||
@@ -26,11 +27,14 @@ val JvmScriptingHostConfigurationKeys.javaHome by PropertiesCollection.key<File>
|
|||||||
|
|
||||||
val JvmScriptingHostConfigurationKeys.jdkHome by PropertiesCollection.key<File>()
|
val JvmScriptingHostConfigurationKeys.jdkHome by PropertiesCollection.key<File>()
|
||||||
|
|
||||||
val JvmScriptingHostConfigurationKeys.baseClassLoader by PropertiesCollection.key<ClassLoader> {
|
val JvmScriptingHostConfigurationKeys.baseClassLoader by PropertiesCollection.key<ClassLoader>(
|
||||||
get(ScriptingHostConfiguration.configurationDependencies)?.let {
|
{
|
||||||
URLClassLoader(it.toClassPathOrEmpty().map { f -> f.toURI().toURL() }.toTypedArray())
|
get(ScriptingHostConfiguration.configurationDependencies)?.let {
|
||||||
}
|
URLClassLoader(it.toClassPathOrEmpty().map { f -> f.toURI().toURL() }.toTypedArray())
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
isTransient = true
|
||||||
|
)
|
||||||
|
|
||||||
@Suppress("unused")
|
@Suppress("unused")
|
||||||
val ScriptingHostConfigurationKeys.jvm
|
val ScriptingHostConfigurationKeys.jvm
|
||||||
|
|||||||
Reference in New Issue
Block a user