Document scripting common API, drop unused bits
This commit is contained in:
+29
@@ -10,6 +10,35 @@ package kotlin.script.experimental.annotations
|
|||||||
import kotlin.reflect.KClass
|
import kotlin.reflect.KClass
|
||||||
import kotlin.script.experimental.api.ScriptCompilationConfiguration
|
import kotlin.script.experimental.api.ScriptCompilationConfiguration
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The annotation for declaring a script definition (template)
|
||||||
|
* A class marked with this annotation is considered a script definition and could be used in script definitions discovery or
|
||||||
|
* referenced explicitly by FQName for compiler or IDE. The compilation configuration is constructed from the annotated class
|
||||||
|
* (it is used as a compiled script super class) and annotation parameters.
|
||||||
|
*
|
||||||
|
* It is important to specify [fileExtension] property via the parameter for
|
||||||
|
* optimal discovery and definitions loading performance.
|
||||||
|
*
|
||||||
|
* @param displayName script definition display name, stored as {@link ScriptCompilationConfigurationKeys#displayName},
|
||||||
|
* default - "Kotlin script"
|
||||||
|
* @param fileExtension distinct filename extension for the script type being defined, stored in the configuration
|
||||||
|
* as {@link ScriptCompilationConfigurationKeys#fileExtension},
|
||||||
|
* default - "kts"
|
||||||
|
* @param compilationConfiguration an object or a class with default constructor containing initial script compilation configuration
|
||||||
|
* default - {@link ScriptCompilationConfiguration#Default}
|
||||||
|
*
|
||||||
|
* Simple usage example:
|
||||||
|
* <pre>
|
||||||
|
* {@code
|
||||||
|
* object MyScriptConfiguration : ScriptCompilationConfiguration({
|
||||||
|
* defaultImports("java.io.File")
|
||||||
|
* })
|
||||||
|
*
|
||||||
|
* @KotlinScript(fileExtension("myscript.kts"))
|
||||||
|
* abstract class MyScriptBaseClass
|
||||||
|
* }
|
||||||
|
* </pre>
|
||||||
|
*/
|
||||||
@Target(AnnotationTarget.CLASS)
|
@Target(AnnotationTarget.CLASS)
|
||||||
@Retention(AnnotationRetention.RUNTIME)
|
@Retention(AnnotationRetention.RUNTIME)
|
||||||
annotation class KotlinScript(
|
annotation class KotlinScript(
|
||||||
|
|||||||
@@ -7,23 +7,46 @@
|
|||||||
|
|
||||||
package kotlin.script.experimental.api
|
package kotlin.script.experimental.api
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The single script diagnostic report
|
||||||
|
* @param message diagnostic message
|
||||||
|
* @param severity diagnostic severity ({@link ScriptDiagnostic#Severity})
|
||||||
|
* @param location optional source location for the diagnostic
|
||||||
|
* @param exception optional exception caused the diagnostic
|
||||||
|
*/
|
||||||
data class ScriptDiagnostic(
|
data class ScriptDiagnostic(
|
||||||
val message: String,
|
val message: String,
|
||||||
val severity: Severity = Severity.ERROR,
|
val severity: Severity = Severity.ERROR,
|
||||||
val location: SourceCode.Location? = null,
|
val location: SourceCode.Location? = null,
|
||||||
val exception: Throwable? = null
|
val exception: Throwable? = null
|
||||||
) {
|
) {
|
||||||
|
/**
|
||||||
|
* The diagnostic severity
|
||||||
|
*/
|
||||||
enum class Severity { FATAL, ERROR, WARNING, INFO, DEBUG }
|
enum class Severity { FATAL, ERROR, WARNING, INFO, DEBUG }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The result wrapper with diagnostics container
|
||||||
|
*/
|
||||||
sealed class ResultWithDiagnostics<out R> {
|
sealed class ResultWithDiagnostics<out R> {
|
||||||
|
/**
|
||||||
|
* The diagnostic reports container
|
||||||
|
*/
|
||||||
abstract val reports: List<ScriptDiagnostic>
|
abstract val reports: List<ScriptDiagnostic>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The successful [value] result with optional [reports] with diagnostics
|
||||||
|
*/
|
||||||
data class Success<out R>(
|
data class Success<out R>(
|
||||||
val value: R,
|
val value: R,
|
||||||
override val reports: List<ScriptDiagnostic> = listOf()
|
override val reports: List<ScriptDiagnostic> = listOf()
|
||||||
) : ResultWithDiagnostics<R>()
|
) : ResultWithDiagnostics<R>()
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The class representing the failure result
|
||||||
|
* @param reports diagnostics associated with the failure
|
||||||
|
*/
|
||||||
data class Failure(
|
data class Failure(
|
||||||
override val reports: List<ScriptDiagnostic>
|
override val reports: List<ScriptDiagnostic>
|
||||||
) : ResultWithDiagnostics<Nothing>() {
|
) : ResultWithDiagnostics<Nothing>() {
|
||||||
@@ -31,14 +54,22 @@ sealed class ResultWithDiagnostics<out R> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// call chaining
|
/**
|
||||||
|
* Chains actions on successful result:
|
||||||
|
* If receiver is success - executes [body] and merge diagnostic reports
|
||||||
|
* otherwise returns the failure as is
|
||||||
|
*/
|
||||||
suspend fun <R1, R2> ResultWithDiagnostics<R1>.onSuccess(body: suspend (R1) -> ResultWithDiagnostics<R2>): ResultWithDiagnostics<R2> =
|
suspend fun <R1, R2> ResultWithDiagnostics<R1>.onSuccess(body: suspend (R1) -> ResultWithDiagnostics<R2>): ResultWithDiagnostics<R2> =
|
||||||
when (this) {
|
when (this) {
|
||||||
is ResultWithDiagnostics.Success -> this.reports + body(this.value)
|
is ResultWithDiagnostics.Success -> this.reports + body(this.value)
|
||||||
is ResultWithDiagnostics.Failure -> this
|
is ResultWithDiagnostics.Failure -> this
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Chains actions on failure:
|
||||||
|
* If receiver is failure - executed [body]
|
||||||
|
* otherwise returns the receiver as is
|
||||||
|
*/
|
||||||
suspend fun <R> ResultWithDiagnostics<R>.onFailure(body: suspend (ResultWithDiagnostics<R>) -> Unit): ResultWithDiagnostics<R> {
|
suspend fun <R> ResultWithDiagnostics<R>.onFailure(body: suspend (ResultWithDiagnostics<R>) -> Unit): ResultWithDiagnostics<R> {
|
||||||
if (this is ResultWithDiagnostics.Failure) {
|
if (this is ResultWithDiagnostics.Failure) {
|
||||||
body(this)
|
body(this)
|
||||||
@@ -46,22 +77,35 @@ suspend fun <R> ResultWithDiagnostics<R>.onFailure(body: suspend (ResultWithDiag
|
|||||||
return this
|
return this
|
||||||
}
|
}
|
||||||
|
|
||||||
operator fun <R> List<ScriptDiagnostic>.plus(res: ResultWithDiagnostics<R>): ResultWithDiagnostics<R> = when (res) {
|
/**
|
||||||
is ResultWithDiagnostics.Success -> ResultWithDiagnostics.Success(res.value, this + res.reports)
|
* Merges diagnostics report with the [result] wrapper
|
||||||
is ResultWithDiagnostics.Failure -> ResultWithDiagnostics.Failure(this + res.reports)
|
*/
|
||||||
|
operator fun <R> List<ScriptDiagnostic>.plus(result: ResultWithDiagnostics<R>): ResultWithDiagnostics<R> = when (result) {
|
||||||
|
is ResultWithDiagnostics.Success -> ResultWithDiagnostics.Success(result.value, this + result.reports)
|
||||||
|
is ResultWithDiagnostics.Failure -> ResultWithDiagnostics.Failure(this + result.reports)
|
||||||
}
|
}
|
||||||
|
|
||||||
// results creation
|
/**
|
||||||
|
* Converts the receiver value to the Success result wrapper with optional diagnostic [reports]
|
||||||
|
*/
|
||||||
fun <R> R.asSuccess(reports: List<ScriptDiagnostic> = listOf()): ResultWithDiagnostics.Success<R> =
|
fun <R> R.asSuccess(reports: List<ScriptDiagnostic> = listOf()): ResultWithDiagnostics.Success<R> =
|
||||||
ResultWithDiagnostics.Success(this, reports)
|
ResultWithDiagnostics.Success(this, reports)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts the receiver Throwable to the Failure results wrapper with optional [message] and [location]
|
||||||
|
*/
|
||||||
fun Throwable.asDiagnostics(customMessage: String? = null, location: SourceCode.Location? = null): ScriptDiagnostic =
|
fun Throwable.asDiagnostics(customMessage: String? = null, location: SourceCode.Location? = null): ScriptDiagnostic =
|
||||||
ScriptDiagnostic(customMessage ?: message ?: "$this", ScriptDiagnostic.Severity.ERROR, location, this)
|
ScriptDiagnostic(customMessage ?: message ?: "$this", ScriptDiagnostic.Severity.ERROR, location, this)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts the receiver String to error diagnostic report with optional [location]
|
||||||
|
*/
|
||||||
fun String.asErrorDiagnostics(location: SourceCode.Location? = null): ScriptDiagnostic =
|
fun String.asErrorDiagnostics(location: SourceCode.Location? = null): ScriptDiagnostic =
|
||||||
ScriptDiagnostic(this, ScriptDiagnostic.Severity.ERROR, location)
|
ScriptDiagnostic(this, ScriptDiagnostic.Severity.ERROR, location)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Extracts the result value from the receiver wrapper or null if receiver represents a Failure
|
||||||
|
*/
|
||||||
fun<R> ResultWithDiagnostics<R>.resultOrNull(): R? = when (this) {
|
fun<R> ResultWithDiagnostics<R>.resultOrNull(): R? = when (this) {
|
||||||
is ResultWithDiagnostics.Success<R> -> value
|
is ResultWithDiagnostics.Success<R> -> value
|
||||||
else -> null
|
else -> null
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ import kotlin.reflect.KClass
|
|||||||
import kotlin.reflect.KType
|
import kotlin.reflect.KType
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A Kotlin type representation for using in the scripting API
|
* The Kotlin type representation for using in the scripting API
|
||||||
*/
|
*/
|
||||||
class KotlinType private constructor(
|
class KotlinType private constructor(
|
||||||
val typeName: String,
|
val typeName: String,
|
||||||
|
|||||||
+107
-25
@@ -13,6 +13,10 @@ import kotlin.script.experimental.util.PropertiesCollection
|
|||||||
|
|
||||||
interface ScriptCompilationConfigurationKeys
|
interface ScriptCompilationConfigurationKeys
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The container for script compilation configuration
|
||||||
|
* For usages see {@link KotlinScript} and actual code examples
|
||||||
|
*/
|
||||||
open class ScriptCompilationConfiguration(baseConfigurations: Iterable<ScriptCompilationConfiguration>, body: Builder.() -> Unit) :
|
open class ScriptCompilationConfiguration(baseConfigurations: Iterable<ScriptCompilationConfiguration>, body: Builder.() -> Unit) :
|
||||||
PropertiesCollection(Builder(baseConfigurations).apply(body).data) {
|
PropertiesCollection(Builder(baseConfigurations).apply(body).data) {
|
||||||
|
|
||||||
@@ -31,78 +35,142 @@ open class ScriptCompilationConfiguration(baseConfigurations: Iterable<ScriptCom
|
|||||||
object Default : ScriptCompilationConfiguration()
|
object Default : ScriptCompilationConfiguration()
|
||||||
}
|
}
|
||||||
|
|
||||||
val ScriptCompilationConfigurationKeys.displayName by PropertiesCollection.key<String>("Kotlin script") // Name of the script type
|
/**
|
||||||
|
* The script type display name
|
||||||
|
*/
|
||||||
|
val ScriptCompilationConfigurationKeys.displayName by PropertiesCollection.key<String>("Kotlin script")
|
||||||
|
|
||||||
val ScriptCompilationConfigurationKeys.fileExtension by PropertiesCollection.key<String>("kts") // file extension
|
/**
|
||||||
|
* The script filename extension
|
||||||
|
*/
|
||||||
|
val ScriptCompilationConfigurationKeys.fileExtension by PropertiesCollection.key<String>("kts")
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The superclass for target script class
|
||||||
|
*/
|
||||||
val ScriptCompilationConfigurationKeys.baseClass by PropertiesCollection.key<KotlinType>() // script base class
|
val ScriptCompilationConfigurationKeys.baseClass by PropertiesCollection.key<KotlinType>() // script base class
|
||||||
|
|
||||||
val ScriptCompilationConfigurationKeys.scriptBodyTarget by PropertiesCollection.key<ScriptBodyTarget>(ScriptBodyTarget.Constructor)
|
/**
|
||||||
|
* The list of classes that will be used as implicit receivers in the script body, as if the whole body is wrapped with "with" calls:
|
||||||
|
* <pre>
|
||||||
|
* {@code
|
||||||
|
* with (receiver1) {
|
||||||
|
* ...
|
||||||
|
* with (receiverN) {
|
||||||
|
* // script body
|
||||||
|
* }
|
||||||
|
* }
|
||||||
|
* }
|
||||||
|
* </pre>
|
||||||
|
*
|
||||||
|
* Note: the actual receivers values should be passed to the constructor of the generated script class
|
||||||
|
*/
|
||||||
val ScriptCompilationConfigurationKeys.implicitReceivers by PropertiesCollection.key<List<KotlinType>>() // in the order from outer to inner scope
|
val ScriptCompilationConfigurationKeys.implicitReceivers by PropertiesCollection.key<List<KotlinType>>() // in the order from outer to inner scope
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The map of names to the types
|
||||||
|
*/
|
||||||
val ScriptCompilationConfigurationKeys.providedProperties by PropertiesCollection.key<Map<String, KotlinType>>() // external variables
|
val ScriptCompilationConfigurationKeys.providedProperties by PropertiesCollection.key<Map<String, KotlinType>>() // external variables
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The list of import expressions that will be implicitly applied to the script body, the syntax is the same as for the "import" statement
|
||||||
|
*/
|
||||||
val ScriptCompilationConfigurationKeys.defaultImports by PropertiesCollection.key<List<String>>()
|
val ScriptCompilationConfigurationKeys.defaultImports by PropertiesCollection.key<List<String>>()
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The list of script dependencies - platform specific
|
||||||
|
*/
|
||||||
val ScriptCompilationConfigurationKeys.dependencies by PropertiesCollection.key<List<ScriptDependency>>()
|
val ScriptCompilationConfigurationKeys.dependencies by PropertiesCollection.key<List<ScriptDependency>>()
|
||||||
|
|
||||||
val ScriptCompilationConfigurationKeys.copyAnnotationsFrom by PropertiesCollection.key<List<KotlinType>>()
|
/**
|
||||||
|
* The list of compiler options that will be applied on script compilation, the syntax is the same as for CLI compiler
|
||||||
|
*/
|
||||||
val ScriptCompilationConfigurationKeys.compilerOptions by PropertiesCollection.key<List<String>>() // Q: CommonCompilerOptions instead?
|
val ScriptCompilationConfigurationKeys.compilerOptions by PropertiesCollection.key<List<String>>() // Q: CommonCompilerOptions instead?
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The callback that will be called on the script compilation before parsing the script
|
||||||
|
*/
|
||||||
val ScriptCompilationConfigurationKeys.refineConfigurationBeforeParsing by PropertiesCollection.key<RefineConfigurationBeforeParsingData>()
|
val ScriptCompilationConfigurationKeys.refineConfigurationBeforeParsing by PropertiesCollection.key<RefineConfigurationBeforeParsingData>()
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The callback that will be called on the script compilation after parsing script file annotations
|
||||||
|
*/
|
||||||
val ScriptCompilationConfigurationKeys.refineConfigurationOnAnnotations by PropertiesCollection.key<RefineConfigurationOnAnnotationsData>()
|
val ScriptCompilationConfigurationKeys.refineConfigurationOnAnnotations by PropertiesCollection.key<RefineConfigurationOnAnnotationsData>()
|
||||||
|
|
||||||
val ScriptCompilationConfigurationKeys.refineConfigurationOnSections by PropertiesCollection.key<RefineConfigurationOnSectionsData>()
|
/**
|
||||||
|
* The list of script fragments that should be compiled intead of the whole text
|
||||||
|
* (for use primary with the refinement callbacks)
|
||||||
|
*/
|
||||||
val ScriptCompilationConfigurationKeys.sourceFragments by PropertiesCollection.key<List<ScriptSourceNamedFragment>>()
|
val ScriptCompilationConfigurationKeys.sourceFragments by PropertiesCollection.key<List<ScriptSourceNamedFragment>>()
|
||||||
|
|
||||||
// DSL:
|
/**
|
||||||
|
* The sub-builder DSL for configuring refinement callbacks
|
||||||
|
*/
|
||||||
val ScriptCompilationConfiguration.Builder.refineConfiguration get() = RefineConfigurationBuilder()
|
val ScriptCompilationConfiguration.Builder.refineConfiguration get() = RefineConfigurationBuilder()
|
||||||
|
|
||||||
|
|
||||||
class RefineConfigurationBuilder : PropertiesCollection.Builder() {
|
class RefineConfigurationBuilder : PropertiesCollection.Builder() {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The callback that will be called on the script compilation before parsing the script
|
||||||
|
* @param handler the callback that will be called
|
||||||
|
*/
|
||||||
fun beforeParsing(handler: RefineScriptCompilationConfigurationHandler) {
|
fun beforeParsing(handler: RefineScriptCompilationConfigurationHandler) {
|
||||||
set(ScriptCompilationConfiguration.refineConfigurationBeforeParsing, RefineConfigurationBeforeParsingData(handler))
|
set(ScriptCompilationConfiguration.refineConfigurationBeforeParsing, RefineConfigurationBeforeParsingData(handler))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The callback that will be called on the script compilation after parsing script file annotations
|
||||||
|
* @param annotations the list of annotations to trigger the callback on
|
||||||
|
* @param handler the callback that will be called
|
||||||
|
*/
|
||||||
fun onAnnotations(annotations: List<KotlinType>, handler: RefineScriptCompilationConfigurationHandler) {
|
fun onAnnotations(annotations: List<KotlinType>, handler: RefineScriptCompilationConfigurationHandler) {
|
||||||
set(ScriptCompilationConfiguration.refineConfigurationOnAnnotations, RefineConfigurationOnAnnotationsData(annotations, handler))
|
set(ScriptCompilationConfiguration.refineConfigurationOnAnnotations, RefineConfigurationOnAnnotationsData(annotations, handler))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The callback that will be called on the script compilation after parsing script file annotations
|
||||||
|
* @param annotations the list of annotations to trigger the callback on
|
||||||
|
* @param handler the callback that will be called
|
||||||
|
*/
|
||||||
fun onAnnotations(vararg annotations: KotlinType, handler: RefineScriptCompilationConfigurationHandler) {
|
fun onAnnotations(vararg annotations: KotlinType, handler: RefineScriptCompilationConfigurationHandler) {
|
||||||
onAnnotations(annotations.asList(), handler)
|
onAnnotations(annotations.asList(), handler)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The callback that will be called on the script compilation after parsing script file annotations
|
||||||
|
* @param annotations the list of annotations to trigger the callback on
|
||||||
|
* @param handler the callback that will be called
|
||||||
|
*/
|
||||||
inline fun <reified T : Annotation> onAnnotations(noinline handler: RefineScriptCompilationConfigurationHandler) {
|
inline fun <reified T : Annotation> onAnnotations(noinline handler: RefineScriptCompilationConfigurationHandler) {
|
||||||
onAnnotations(listOf(KotlinType(T::class)), handler)
|
onAnnotations(listOf(KotlinType(T::class)), handler)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The callback that will be called on the script compilation after parsing script file annotations
|
||||||
|
* @param annotations the list of annotations to trigger the callback on
|
||||||
|
* @param handler the callback that will be called
|
||||||
|
*/
|
||||||
fun onAnnotations(vararg annotations: KClass<out Annotation>, handler: RefineScriptCompilationConfigurationHandler) {
|
fun onAnnotations(vararg annotations: KClass<out Annotation>, handler: RefineScriptCompilationConfigurationHandler) {
|
||||||
onAnnotations(annotations.map { KotlinType(it) }, handler)
|
onAnnotations(annotations.map { KotlinType(it) }, handler)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The callback that will be called on the script compilation after parsing script file annotations
|
||||||
|
* @param annotations the list of annotations to trigger the callback on
|
||||||
|
* @param handler the callback that will be called
|
||||||
|
*/
|
||||||
fun onAnnotations(annotations: Iterable<KClass<out Annotation>>, handler: RefineScriptCompilationConfigurationHandler) {
|
fun onAnnotations(annotations: Iterable<KClass<out Annotation>>, handler: RefineScriptCompilationConfigurationHandler) {
|
||||||
onAnnotations(annotations.map { KotlinType(it) }, handler)
|
onAnnotations(annotations.map { KotlinType(it) }, handler)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun onSections(sections: List<String>, handler: RefineScriptCompilationConfigurationHandler) {
|
|
||||||
set(ScriptCompilationConfiguration.refineConfigurationOnSections, RefineConfigurationOnSectionsData(sections, handler))
|
|
||||||
}
|
|
||||||
|
|
||||||
fun onSections(vararg sections: String, handler: RefineScriptCompilationConfigurationHandler) {
|
|
||||||
onSections(sections.asList(), handler)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The refinement callback function signature
|
||||||
|
*/
|
||||||
typealias RefineScriptCompilationConfigurationHandler =
|
typealias RefineScriptCompilationConfigurationHandler =
|
||||||
(ScriptConfigurationRefinementContext) -> ResultWithDiagnostics<ScriptCompilationConfiguration>
|
(ScriptConfigurationRefinementContext) -> ResultWithDiagnostics<ScriptCompilationConfiguration>
|
||||||
|
|
||||||
// to make it "hasheable" for cashing
|
|
||||||
class RefineConfigurationBeforeParsingData(
|
class RefineConfigurationBeforeParsingData(
|
||||||
val handler: RefineScriptCompilationConfigurationHandler
|
val handler: RefineScriptCompilationConfigurationHandler
|
||||||
) : Serializable
|
) : Serializable
|
||||||
@@ -112,24 +180,38 @@ class RefineConfigurationOnAnnotationsData(
|
|||||||
val handler: RefineScriptCompilationConfigurationHandler
|
val handler: RefineScriptCompilationConfigurationHandler
|
||||||
) : Serializable
|
) : Serializable
|
||||||
|
|
||||||
class RefineConfigurationOnSectionsData(
|
|
||||||
val sections: List<String>,
|
|
||||||
val handler: RefineScriptCompilationConfigurationHandler
|
|
||||||
) : Serializable
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The functional interface to the script compiler
|
||||||
|
*/
|
||||||
interface ScriptCompiler {
|
interface ScriptCompiler {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Compiles the [script] according to the [scriptCompilationConfiguration]
|
||||||
|
* @param script the interface to the script source code
|
||||||
|
* @param scriptCompilationConfiguration the script compilation configuration properties
|
||||||
|
* @return result wrapper, if successful - with compiled script
|
||||||
|
*/
|
||||||
suspend operator fun invoke(
|
suspend operator fun invoke(
|
||||||
script: SourceCode,
|
script: SourceCode,
|
||||||
scriptCompilationConfiguration: ScriptCompilationConfiguration
|
scriptCompilationConfiguration: ScriptCompilationConfiguration
|
||||||
): ResultWithDiagnostics<CompiledScript<*>>
|
): ResultWithDiagnostics<CompiledScript<*>>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The interface to the compiled script
|
||||||
|
*/
|
||||||
interface CompiledScript<out ScriptBase : Any> {
|
interface CompiledScript<out ScriptBase : Any> {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The compilation configuration used for script compilation
|
||||||
|
*/
|
||||||
val compilationConfiguration: ScriptCompilationConfiguration
|
val compilationConfiguration: ScriptCompilationConfiguration
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The function that loads compiled script class
|
||||||
|
* @param scriptEvaluationConfiguration the script evaluation configuration properties
|
||||||
|
* @return result wrapper, if successful - with loaded KClass
|
||||||
|
*/
|
||||||
suspend fun getClass(scriptEvaluationConfiguration: ScriptEvaluationConfiguration?): ResultWithDiagnostics<KClass<*>>
|
suspend fun getClass(scriptEvaluationConfiguration: ScriptEvaluationConfiguration?): ResultWithDiagnostics<KClass<*>>
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,51 +11,77 @@ import java.io.Serializable
|
|||||||
import java.net.URL
|
import java.net.URL
|
||||||
import kotlin.script.experimental.util.PropertiesCollection
|
import kotlin.script.experimental.util.PropertiesCollection
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The interface to the script or snippet source code
|
||||||
|
*/
|
||||||
interface SourceCode {
|
interface SourceCode {
|
||||||
|
/**
|
||||||
|
* The source code text
|
||||||
|
*/
|
||||||
val text: String
|
val text: String
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The source code position
|
||||||
|
* @param line source code position line
|
||||||
|
* @param col source code position column
|
||||||
|
* @param absolutePos absolute source code text position, if available
|
||||||
|
*/
|
||||||
data class Position(val line: Int, val col: Int, val absolutePos: Int? = null)
|
data class Position(val line: Int, val col: Int, val absolutePos: Int? = null)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The source code positions range
|
||||||
|
* @param start range start position
|
||||||
|
* @param end range end position (after the last char)
|
||||||
|
*/
|
||||||
data class Range(val start: Position, val end: Position)
|
data class Range(val start: Position, val end: Position)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The source code location, pointing either at a position or at a range
|
||||||
|
* @param start location start position
|
||||||
|
* @param end optional range location end position (after the last char)
|
||||||
|
*/
|
||||||
data class Location(val start: Position, val end: Position? = null)
|
data class Location(val start: Position, val end: Position? = null)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The interface for the source code located externally
|
||||||
|
*/
|
||||||
interface ExternalSourceCode : SourceCode {
|
interface ExternalSourceCode : SourceCode {
|
||||||
|
/**
|
||||||
|
* The source code location url
|
||||||
|
*/
|
||||||
val externalLocation: URL
|
val externalLocation: URL
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The source code [range] with the the optional [name]
|
||||||
|
*/
|
||||||
data class ScriptSourceNamedFragment(val name: String?, val range: SourceCode.Range)
|
data class ScriptSourceNamedFragment(val name: String?, val range: SourceCode.Range)
|
||||||
|
|
||||||
enum class ScriptBodyTarget {
|
/**
|
||||||
Constructor,
|
* The general interface to the Script dependency (see platform-specific implementations)
|
||||||
SAMFunction
|
*/
|
||||||
}
|
interface ScriptDependency : Serializable
|
||||||
|
|
||||||
data class ResolvingRestrictionRule(
|
|
||||||
val action: Action,
|
|
||||||
val pattern: String // FQN wildcard
|
|
||||||
) {
|
|
||||||
enum class Action {
|
|
||||||
Allow,
|
|
||||||
Deny
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
interface ScriptDependency : Serializable {
|
|
||||||
// Q: anything generic here?
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
interface ScriptCollectedDataKeys
|
interface ScriptCollectedDataKeys
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The container for script data collected during compilation
|
||||||
|
* Used for transferring data to the configuration refinement callbacks
|
||||||
|
*/
|
||||||
class ScriptCollectedData(properties: Map<PropertiesCollection.Key<*>, Any>) : PropertiesCollection(properties) {
|
class ScriptCollectedData(properties: Map<PropertiesCollection.Key<*>, Any>) : PropertiesCollection(properties) {
|
||||||
|
|
||||||
companion object : ScriptCollectedDataKeys
|
companion object : ScriptCollectedDataKeys
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The script file-level annotations found during script source parsing
|
||||||
|
*/
|
||||||
val ScriptCollectedDataKeys.foundAnnotations by PropertiesCollection.key<List<Annotation>>()
|
val ScriptCollectedDataKeys.foundAnnotations by PropertiesCollection.key<List<Annotation>>()
|
||||||
|
|
||||||
val ScriptCollectedDataKeys.foundFragments by PropertiesCollection.key<List<ScriptSourceNamedFragment>>()
|
/**
|
||||||
|
* The facade to the script data for refinement callbacks
|
||||||
|
*/
|
||||||
class ScriptConfigurationRefinementContext(
|
class ScriptConfigurationRefinementContext(
|
||||||
val script: SourceCode,
|
val script: SourceCode,
|
||||||
val compilationConfiguration: ScriptCompilationConfiguration,
|
val compilationConfiguration: ScriptCompilationConfiguration,
|
||||||
|
|||||||
@@ -11,6 +11,10 @@ import kotlin.script.experimental.util.PropertiesCollection
|
|||||||
|
|
||||||
interface ScriptEvaluationConfigurationKeys
|
interface ScriptEvaluationConfigurationKeys
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The container for script evaluation configuration
|
||||||
|
* For usages see actual code examples
|
||||||
|
*/
|
||||||
class ScriptEvaluationConfiguration(baseEvaluationConfigurations: Iterable<ScriptEvaluationConfiguration>, body: Builder.() -> Unit) :
|
class ScriptEvaluationConfiguration(baseEvaluationConfigurations: Iterable<ScriptEvaluationConfiguration>, body: Builder.() -> Unit) :
|
||||||
PropertiesCollection(Builder(baseEvaluationConfigurations).apply(body).data) {
|
PropertiesCollection(Builder(baseEvaluationConfigurations).apply(body).data) {
|
||||||
|
|
||||||
@@ -26,14 +30,25 @@ class ScriptEvaluationConfiguration(baseEvaluationConfigurations: Iterable<Scrip
|
|||||||
companion object : ScriptEvaluationConfigurationKeys
|
companion object : ScriptEvaluationConfigurationKeys
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The list of actual script implicit receiver object, in the same order as specified in {@link ScriptCompilationConfigurationKeys#implicitReceivers}
|
||||||
|
*/
|
||||||
val ScriptEvaluationConfigurationKeys.implicitReceivers by PropertiesCollection.key<List<Any>>()
|
val ScriptEvaluationConfigurationKeys.implicitReceivers by PropertiesCollection.key<List<Any>>()
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The map of names to actual provided properties objects, according to the properties specified in
|
||||||
|
* {@link ScriptCompilationConfigurationKeys#providedProperties}
|
||||||
|
*/
|
||||||
val ScriptEvaluationConfigurationKeys.providedProperties by PropertiesCollection.key<Map<String, Any?>>() // external variables
|
val ScriptEvaluationConfigurationKeys.providedProperties by PropertiesCollection.key<Map<String, Any?>>() // external variables
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor arguments, additional to implicit receivers and provided properties, according to the script base class constructor
|
||||||
|
*/
|
||||||
val ScriptEvaluationConfigurationKeys.constructorArgs by PropertiesCollection.key<List<Any?>>()
|
val ScriptEvaluationConfigurationKeys.constructorArgs by PropertiesCollection.key<List<Any?>>()
|
||||||
|
|
||||||
val ScriptEvaluationConfigurationKeys.runArgs by PropertiesCollection.key<List<Any?>>()
|
/**
|
||||||
|
* The script evaluation result value
|
||||||
|
*/
|
||||||
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() {
|
||||||
override fun toString(): String = "$name: $type = $value"
|
override fun toString(): String = "$name: $type = $value"
|
||||||
@@ -42,10 +57,21 @@ sealed class ResultValue {
|
|||||||
object Unit : ResultValue()
|
object Unit : ResultValue()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The facade for the evaluation result and evaluation configuration, used in the evaluator interface
|
||||||
|
*/
|
||||||
data class EvaluationResult(val returnValue: ResultValue, val configuration: ScriptEvaluationConfiguration?)
|
data class EvaluationResult(val returnValue: ResultValue, val configuration: ScriptEvaluationConfiguration?)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The functional interface to the script evaluator
|
||||||
|
*/
|
||||||
interface ScriptEvaluator {
|
interface ScriptEvaluator {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Evaluates [compiledScript] using the data from [scriptEvaluationConfiguration]
|
||||||
|
* @param compiledScript the compiled script class
|
||||||
|
* @param scriptEvaluationConfiguration evaluation configuration
|
||||||
|
*/
|
||||||
suspend operator fun invoke(
|
suspend operator fun invoke(
|
||||||
compiledScript: CompiledScript<*>,
|
compiledScript: CompiledScript<*>,
|
||||||
scriptEvaluationConfiguration: ScriptEvaluationConfiguration?
|
scriptEvaluationConfiguration: ScriptEvaluationConfiguration?
|
||||||
|
|||||||
@@ -22,12 +22,21 @@ import kotlinx.coroutines.experimental.CoroutineScope
|
|||||||
import kotlinx.coroutines.experimental.runBlocking
|
import kotlinx.coroutines.experimental.runBlocking
|
||||||
import kotlin.script.experimental.api.*
|
import kotlin.script.experimental.api.*
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The base class for scripting host implementations
|
||||||
|
*/
|
||||||
abstract class BasicScriptingHost(
|
abstract class BasicScriptingHost(
|
||||||
val compiler: ScriptCompiler,
|
val compiler: ScriptCompiler,
|
||||||
val evaluator: ScriptEvaluator
|
val evaluator: ScriptEvaluator
|
||||||
) {
|
) {
|
||||||
|
/**
|
||||||
|
* The overridable wrapper for executing evaluation in a desired coroutines context
|
||||||
|
*/
|
||||||
open fun <T> runInCoroutineContext(block: suspend CoroutineScope.() -> T): T = runBlocking { block() }
|
open fun <T> runInCoroutineContext(block: suspend CoroutineScope.() -> T): T = runBlocking { block() }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The default implementation of the evaluation function
|
||||||
|
*/
|
||||||
open fun eval(
|
open fun eval(
|
||||||
script: SourceCode,
|
script: SourceCode,
|
||||||
scriptCompilationConfiguration: ScriptCompilationConfiguration,
|
scriptCompilationConfiguration: ScriptCompilationConfiguration,
|
||||||
|
|||||||
+7
@@ -19,6 +19,13 @@ private const val SCRIPT_RUNTIME_TEMPLATES_PACKAGE = "kotlin.script.templates.st
|
|||||||
@KotlinScript
|
@KotlinScript
|
||||||
private abstract class DummyScriptTemplate
|
private abstract class DummyScriptTemplate
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates the compilation configuration from annotated script base class
|
||||||
|
* @param baseClassType the annotated script base class to construct the configuration from
|
||||||
|
* @param hostConfiguration scripting host configuration properties
|
||||||
|
* @param contextClass optional context class to extract classloading strategy from
|
||||||
|
* @param body optional configuration function to add more properties to the compilation configuration
|
||||||
|
*/
|
||||||
fun createCompilationConfigurationFromTemplate(
|
fun createCompilationConfigurationFromTemplate(
|
||||||
baseClassType: KotlinType,
|
baseClassType: KotlinType,
|
||||||
hostConfiguration: ScriptingHostConfiguration,
|
hostConfiguration: ScriptingHostConfiguration,
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import java.io.File
|
|||||||
import java.net.URL
|
import java.net.URL
|
||||||
import kotlin.script.experimental.api.*
|
import kotlin.script.experimental.api.*
|
||||||
|
|
||||||
|
// helper function
|
||||||
fun getMergedScriptText(script: SourceCode, configuration: ScriptCompilationConfiguration?): String {
|
fun getMergedScriptText(script: SourceCode, configuration: ScriptCompilationConfiguration?): String {
|
||||||
val originalScriptText = script.text
|
val originalScriptText = script.text
|
||||||
val sourceFragments = configuration?.get(ScriptCompilationConfiguration.sourceFragments)
|
val sourceFragments = configuration?.get(ScriptCompilationConfiguration.sourceFragments)
|
||||||
@@ -38,15 +39,27 @@ fun getMergedScriptText(script: SourceCode, configuration: ScriptCompilationConf
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The implementation of the SourceCode for a script located in a file
|
||||||
|
*/
|
||||||
open class FileScriptSource(val file: File) : ExternalSourceCode {
|
open class FileScriptSource(val file: File) : ExternalSourceCode {
|
||||||
override val externalLocation: URL get() = file.toURI().toURL()
|
override val externalLocation: URL get() = file.toURI().toURL()
|
||||||
override val text: String by lazy { file.readText() }
|
override val text: String by lazy { file.readText() }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts the file into the SourceCode
|
||||||
|
*/
|
||||||
fun File.toScriptSource(): SourceCode = FileScriptSource(this)
|
fun File.toScriptSource(): SourceCode = FileScriptSource(this)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The implementation of the ScriptSource for a script in a String
|
||||||
|
*/
|
||||||
open class StringScriptSource(val source: String) : SourceCode {
|
open class StringScriptSource(val source: String) : SourceCode {
|
||||||
override val text: String get() = source
|
override val text: String get() = source
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts the String into the SourceCode
|
||||||
|
*/
|
||||||
fun String.toScriptSource(): SourceCode = StringScriptSource(this)
|
fun String.toScriptSource(): SourceCode = StringScriptSource(this)
|
||||||
|
|||||||
+15
-8
@@ -12,6 +12,10 @@ import kotlin.script.experimental.util.PropertiesCollection
|
|||||||
|
|
||||||
interface ScriptingHostConfigurationKeys
|
interface ScriptingHostConfigurationKeys
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The container for script evaluation configuration
|
||||||
|
* For usages see actual code examples
|
||||||
|
*/
|
||||||
class ScriptingHostConfiguration(baseScriptingConfigurations: Iterable<ScriptingHostConfiguration>, body: Builder.() -> Unit) :
|
class ScriptingHostConfiguration(baseScriptingConfigurations: Iterable<ScriptingHostConfiguration>, body: Builder.() -> Unit) :
|
||||||
PropertiesCollection(Builder(baseScriptingConfigurations).apply(body).data) {
|
PropertiesCollection(Builder(baseScriptingConfigurations).apply(body).data) {
|
||||||
|
|
||||||
@@ -27,27 +31,30 @@ class ScriptingHostConfiguration(baseScriptingConfigurations: Iterable<Scripting
|
|||||||
companion object : ScriptingHostConfigurationKeys
|
companion object : ScriptingHostConfigurationKeys
|
||||||
}
|
}
|
||||||
|
|
||||||
// should contain all dependencies needed for baseClass and compilationConfigurator
|
/**
|
||||||
|
* The list of all dependencies required for the script base class and refinement callbacks
|
||||||
|
*/
|
||||||
val ScriptingHostConfigurationKeys.configurationDependencies by PropertiesCollection.key<List<ScriptDependency>>()
|
val ScriptingHostConfigurationKeys.configurationDependencies by PropertiesCollection.key<List<ScriptDependency>>()
|
||||||
|
|
||||||
// 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
|
* The pointer to the generic "class loader" for the types used in the script configurations
|
||||||
// compilation and instantiation, but compilationConfigurator could be excluded)
|
*/
|
||||||
val ScriptingHostConfigurationKeys.isolatedDependencies by PropertiesCollection.key<Boolean>(false)
|
|
||||||
|
|
||||||
// a "class loader" for KotlinTypes
|
|
||||||
val ScriptingHostConfigurationKeys.getScriptingClass by PropertiesCollection.key<GetScriptingClass>()
|
val ScriptingHostConfigurationKeys.getScriptingClass by PropertiesCollection.key<GetScriptingClass>()
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The interface to the generic "class loader" for the types used in the script configurations
|
||||||
|
*/
|
||||||
interface GetScriptingClass {
|
interface GetScriptingClass {
|
||||||
operator fun invoke(classType: KotlinType, contextClass: KClass<*>, hostConfiguration: ScriptingHostConfiguration): KClass<*>
|
operator fun invoke(classType: KotlinType, contextClass: KClass<*>, hostConfiguration: ScriptingHostConfiguration): KClass<*>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// helper method
|
||||||
fun ScriptingHostConfiguration.getScriptingClass(type: KotlinType, contextClass: KClass<*>): KClass<*> {
|
fun ScriptingHostConfiguration.getScriptingClass(type: KotlinType, contextClass: KClass<*>): KClass<*> {
|
||||||
val getClass = get(ScriptingHostConfiguration.getScriptingClass)
|
val getClass = get(ScriptingHostConfiguration.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)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// helper method
|
||||||
fun ScriptingHostConfiguration.getScriptingClass(type: KotlinType, context: Any): KClass<*> = getScriptingClass(type, context::class)
|
fun ScriptingHostConfiguration.getScriptingClass(type: KotlinType, context: Any): KClass<*> = getScriptingClass(type, context::class)
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user