diff --git a/libraries/scripting/common/src/kotlin/script/experimental/annotations/scriptAnnotations.kt b/libraries/scripting/common/src/kotlin/script/experimental/annotations/scriptAnnotations.kt index 2ea2a778940..c6c2abb56ef 100644 --- a/libraries/scripting/common/src/kotlin/script/experimental/annotations/scriptAnnotations.kt +++ b/libraries/scripting/common/src/kotlin/script/experimental/annotations/scriptAnnotations.kt @@ -10,6 +10,35 @@ package kotlin.script.experimental.annotations import kotlin.reflect.KClass 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: + *
+ * {@code
+ *   object MyScriptConfiguration : ScriptCompilationConfiguration({
+ *     defaultImports("java.io.File")
+ *   })
+ *
+ *   @KotlinScript(fileExtension("myscript.kts"))
+ *   abstract class MyScriptBaseClass
+ * }
+ * 
+ */ @Target(AnnotationTarget.CLASS) @Retention(AnnotationRetention.RUNTIME) annotation class KotlinScript( diff --git a/libraries/scripting/common/src/kotlin/script/experimental/api/errorHandling.kt b/libraries/scripting/common/src/kotlin/script/experimental/api/errorHandling.kt index 3bf2ea3479a..f00d7aae3bb 100644 --- a/libraries/scripting/common/src/kotlin/script/experimental/api/errorHandling.kt +++ b/libraries/scripting/common/src/kotlin/script/experimental/api/errorHandling.kt @@ -7,23 +7,46 @@ 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( val message: String, val severity: Severity = Severity.ERROR, val location: SourceCode.Location? = null, val exception: Throwable? = null ) { + /** + * The diagnostic severity + */ enum class Severity { FATAL, ERROR, WARNING, INFO, DEBUG } } +/** + * The result wrapper with diagnostics container + */ sealed class ResultWithDiagnostics { + /** + * The diagnostic reports container + */ abstract val reports: List + /** + * The successful [value] result with optional [reports] with diagnostics + */ data class Success( val value: R, override val reports: List = listOf() ) : ResultWithDiagnostics() + /** + * The class representing the failure result + * @param reports diagnostics associated with the failure + */ data class Failure( override val reports: List ) : ResultWithDiagnostics() { @@ -31,14 +54,22 @@ sealed class ResultWithDiagnostics { } } -// 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 ResultWithDiagnostics.onSuccess(body: suspend (R1) -> ResultWithDiagnostics): ResultWithDiagnostics = when (this) { is ResultWithDiagnostics.Success -> this.reports + body(this.value) is ResultWithDiagnostics.Failure -> this } +/** + * Chains actions on failure: + * If receiver is failure - executed [body] + * otherwise returns the receiver as is + */ suspend fun ResultWithDiagnostics.onFailure(body: suspend (ResultWithDiagnostics) -> Unit): ResultWithDiagnostics { if (this is ResultWithDiagnostics.Failure) { body(this) @@ -46,22 +77,35 @@ suspend fun ResultWithDiagnostics.onFailure(body: suspend (ResultWithDiag return this } -operator fun List.plus(res: ResultWithDiagnostics): ResultWithDiagnostics = when (res) { - is ResultWithDiagnostics.Success -> ResultWithDiagnostics.Success(res.value, this + res.reports) - is ResultWithDiagnostics.Failure -> ResultWithDiagnostics.Failure(this + res.reports) +/** + * Merges diagnostics report with the [result] wrapper + */ +operator fun List.plus(result: ResultWithDiagnostics): ResultWithDiagnostics = 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.asSuccess(reports: List = listOf()): ResultWithDiagnostics.Success = 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 = 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 = ScriptDiagnostic(this, ScriptDiagnostic.Severity.ERROR, location) +/** + * Extracts the result value from the receiver wrapper or null if receiver represents a Failure + */ fun ResultWithDiagnostics.resultOrNull(): R? = when (this) { is ResultWithDiagnostics.Success -> value else -> null diff --git a/libraries/scripting/common/src/kotlin/script/experimental/api/kotlinType.kt b/libraries/scripting/common/src/kotlin/script/experimental/api/kotlinType.kt index bf20848496d..6f889a392d7 100644 --- a/libraries/scripting/common/src/kotlin/script/experimental/api/kotlinType.kt +++ b/libraries/scripting/common/src/kotlin/script/experimental/api/kotlinType.kt @@ -10,7 +10,7 @@ import kotlin.reflect.KClass 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( val typeName: String, diff --git a/libraries/scripting/common/src/kotlin/script/experimental/api/scriptCompilation.kt b/libraries/scripting/common/src/kotlin/script/experimental/api/scriptCompilation.kt index 5e72e3fa7cf..99d59f7e7f4 100644 --- a/libraries/scripting/common/src/kotlin/script/experimental/api/scriptCompilation.kt +++ b/libraries/scripting/common/src/kotlin/script/experimental/api/scriptCompilation.kt @@ -13,6 +13,10 @@ import kotlin.script.experimental.util.PropertiesCollection interface ScriptCompilationConfigurationKeys +/** + * The container for script compilation configuration + * For usages see {@link KotlinScript} and actual code examples + */ open class ScriptCompilationConfiguration(baseConfigurations: Iterable, body: Builder.() -> Unit) : PropertiesCollection(Builder(baseConfigurations).apply(body).data) { @@ -31,78 +35,142 @@ open class ScriptCompilationConfiguration(baseConfigurations: Iterable("Kotlin script") // Name of the script type +/** + * The script type display name + */ +val ScriptCompilationConfigurationKeys.displayName by PropertiesCollection.key("Kotlin script") -val ScriptCompilationConfigurationKeys.fileExtension by PropertiesCollection.key("kts") // file extension +/** + * The script filename extension + */ +val ScriptCompilationConfigurationKeys.fileExtension by PropertiesCollection.key("kts") +/** + * The superclass for target script class + */ val ScriptCompilationConfigurationKeys.baseClass by PropertiesCollection.key() // script base class -val ScriptCompilationConfigurationKeys.scriptBodyTarget by PropertiesCollection.key(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: + *
+ * {@code
+ *   with (receiver1) {
+ *     ...
+ *       with (receiverN) {
+ *         // script body
+ *       }
+ *   }
+ * }
+ * 
+ * + * Note: the actual receivers values should be passed to the constructor of the generated script class + */ val ScriptCompilationConfigurationKeys.implicitReceivers by PropertiesCollection.key>() // in the order from outer to inner scope +/** + * The map of names to the types + */ val ScriptCompilationConfigurationKeys.providedProperties by PropertiesCollection.key>() // 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>() +/** + * The list of script dependencies - platform specific + */ val ScriptCompilationConfigurationKeys.dependencies by PropertiesCollection.key>() -val ScriptCompilationConfigurationKeys.copyAnnotationsFrom by PropertiesCollection.key>() - +/** + * 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>() // Q: CommonCompilerOptions instead? +/** + * The callback that will be called on the script compilation before parsing the script + */ val ScriptCompilationConfigurationKeys.refineConfigurationBeforeParsing by PropertiesCollection.key() +/** + * The callback that will be called on the script compilation after parsing script file annotations + */ val ScriptCompilationConfigurationKeys.refineConfigurationOnAnnotations by PropertiesCollection.key() -val ScriptCompilationConfigurationKeys.refineConfigurationOnSections by PropertiesCollection.key() - +/** + * 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>() -// DSL: - +/** + * The sub-builder DSL for configuring refinement callbacks + */ val ScriptCompilationConfiguration.Builder.refineConfiguration get() = RefineConfigurationBuilder() 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) { 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, handler: RefineScriptCompilationConfigurationHandler) { 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) { 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 onAnnotations(noinline handler: RefineScriptCompilationConfigurationHandler) { 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, handler: RefineScriptCompilationConfigurationHandler) { 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>, handler: RefineScriptCompilationConfigurationHandler) { onAnnotations(annotations.map { KotlinType(it) }, handler) } - - fun onSections(sections: List, 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 = (ScriptConfigurationRefinementContext) -> ResultWithDiagnostics -// to make it "hasheable" for cashing class RefineConfigurationBeforeParsingData( val handler: RefineScriptCompilationConfigurationHandler ) : Serializable @@ -112,24 +180,38 @@ class RefineConfigurationOnAnnotationsData( val handler: RefineScriptCompilationConfigurationHandler ) : Serializable -class RefineConfigurationOnSectionsData( - val sections: List, - val handler: RefineScriptCompilationConfigurationHandler -) : Serializable - +/** + * The functional interface to the script compiler + */ 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( script: SourceCode, scriptCompilationConfiguration: ScriptCompilationConfiguration ): ResultWithDiagnostics> } - +/** + * The interface to the compiled script + */ interface CompiledScript { + /** + * The compilation configuration used for script compilation + */ 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> } diff --git a/libraries/scripting/common/src/kotlin/script/experimental/api/scriptData.kt b/libraries/scripting/common/src/kotlin/script/experimental/api/scriptData.kt index 6acfcad4b4f..c4c00e7e93e 100644 --- a/libraries/scripting/common/src/kotlin/script/experimental/api/scriptData.kt +++ b/libraries/scripting/common/src/kotlin/script/experimental/api/scriptData.kt @@ -11,51 +11,77 @@ import java.io.Serializable import java.net.URL import kotlin.script.experimental.util.PropertiesCollection +/** + * The interface to the script or snippet source code + */ interface SourceCode { + /** + * The source code text + */ 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) + + /** + * 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) + + /** + * 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) } +/** + * The interface for the source code located externally + */ interface ExternalSourceCode : SourceCode { + /** + * The source code location url + */ val externalLocation: URL } +/** + * The source code [range] with the the optional [name] + */ data class ScriptSourceNamedFragment(val name: String?, val range: SourceCode.Range) -enum class ScriptBodyTarget { - Constructor, - SAMFunction -} - -data class ResolvingRestrictionRule( - val action: Action, - val pattern: String // FQN wildcard -) { - enum class Action { - Allow, - Deny - } -} - -interface ScriptDependency : Serializable { - // Q: anything generic here? -} - +/** + * The general interface to the Script dependency (see platform-specific implementations) + */ +interface ScriptDependency : Serializable interface ScriptCollectedDataKeys +/** + * The container for script data collected during compilation + * Used for transferring data to the configuration refinement callbacks + */ class ScriptCollectedData(properties: Map, Any>) : PropertiesCollection(properties) { companion object : ScriptCollectedDataKeys } +/** + * The script file-level annotations found during script source parsing + */ val ScriptCollectedDataKeys.foundAnnotations by PropertiesCollection.key>() -val ScriptCollectedDataKeys.foundFragments by PropertiesCollection.key>() - +/** + * The facade to the script data for refinement callbacks + */ class ScriptConfigurationRefinementContext( val script: SourceCode, val compilationConfiguration: ScriptCompilationConfiguration, diff --git a/libraries/scripting/common/src/kotlin/script/experimental/api/scriptEvaluation.kt b/libraries/scripting/common/src/kotlin/script/experimental/api/scriptEvaluation.kt index 2fd021502e9..82853eafa2f 100644 --- a/libraries/scripting/common/src/kotlin/script/experimental/api/scriptEvaluation.kt +++ b/libraries/scripting/common/src/kotlin/script/experimental/api/scriptEvaluation.kt @@ -11,6 +11,10 @@ import kotlin.script.experimental.util.PropertiesCollection interface ScriptEvaluationConfigurationKeys +/** + * The container for script evaluation configuration + * For usages see actual code examples + */ class ScriptEvaluationConfiguration(baseEvaluationConfigurations: Iterable, body: Builder.() -> Unit) : PropertiesCollection(Builder(baseEvaluationConfigurations).apply(body).data) { @@ -26,14 +30,25 @@ class ScriptEvaluationConfiguration(baseEvaluationConfigurations: Iterable>() +/** + * The map of names to actual provided properties objects, according to the properties specified in + * {@link ScriptCompilationConfigurationKeys#providedProperties} + */ val ScriptEvaluationConfigurationKeys.providedProperties by PropertiesCollection.key>() // external variables +/** + * Constructor arguments, additional to implicit receivers and provided properties, according to the script base class constructor + */ val ScriptEvaluationConfigurationKeys.constructorArgs by PropertiesCollection.key>() -val ScriptEvaluationConfigurationKeys.runArgs by PropertiesCollection.key>() - +/** + * The script evaluation result value + */ sealed class ResultValue { class Value(val name: String, val value: Any?, val type: String) : ResultValue() { override fun toString(): String = "$name: $type = $value" @@ -42,10 +57,21 @@ sealed class 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?) +/** + * The functional interface to the script evaluator + */ interface ScriptEvaluator { + /** + * Evaluates [compiledScript] using the data from [scriptEvaluationConfiguration] + * @param compiledScript the compiled script class + * @param scriptEvaluationConfiguration evaluation configuration + */ suspend operator fun invoke( compiledScript: CompiledScript<*>, scriptEvaluationConfiguration: ScriptEvaluationConfiguration? diff --git a/libraries/scripting/common/src/kotlin/script/experimental/host/BasicScriptingHost.kt b/libraries/scripting/common/src/kotlin/script/experimental/host/BasicScriptingHost.kt index 522f6313ac8..ed0c9880824 100644 --- a/libraries/scripting/common/src/kotlin/script/experimental/host/BasicScriptingHost.kt +++ b/libraries/scripting/common/src/kotlin/script/experimental/host/BasicScriptingHost.kt @@ -22,12 +22,21 @@ import kotlinx.coroutines.experimental.CoroutineScope import kotlinx.coroutines.experimental.runBlocking import kotlin.script.experimental.api.* +/** + * The base class for scripting host implementations + */ abstract class BasicScriptingHost( val compiler: ScriptCompiler, val evaluator: ScriptEvaluator ) { + /** + * The overridable wrapper for executing evaluation in a desired coroutines context + */ open fun runInCoroutineContext(block: suspend CoroutineScope.() -> T): T = runBlocking { block() } + /** + * The default implementation of the evaluation function + */ open fun eval( script: SourceCode, scriptCompilationConfiguration: ScriptCompilationConfiguration, diff --git a/libraries/scripting/common/src/kotlin/script/experimental/host/configurationFromTemplate.kt b/libraries/scripting/common/src/kotlin/script/experimental/host/configurationFromTemplate.kt index f0a21b262db..7298e474e22 100644 --- a/libraries/scripting/common/src/kotlin/script/experimental/host/configurationFromTemplate.kt +++ b/libraries/scripting/common/src/kotlin/script/experimental/host/configurationFromTemplate.kt @@ -19,6 +19,13 @@ private const val SCRIPT_RUNTIME_TEMPLATES_PACKAGE = "kotlin.script.templates.st @KotlinScript 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( baseClassType: KotlinType, hostConfiguration: ScriptingHostConfiguration, diff --git a/libraries/scripting/common/src/kotlin/script/experimental/host/scriptHostUtil.kt b/libraries/scripting/common/src/kotlin/script/experimental/host/scriptHostUtil.kt index a5e29e2e27d..f20aca26815 100644 --- a/libraries/scripting/common/src/kotlin/script/experimental/host/scriptHostUtil.kt +++ b/libraries/scripting/common/src/kotlin/script/experimental/host/scriptHostUtil.kt @@ -9,6 +9,7 @@ import java.io.File import java.net.URL import kotlin.script.experimental.api.* +// helper function fun getMergedScriptText(script: SourceCode, configuration: ScriptCompilationConfiguration?): String { val originalScriptText = script.text 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 { override val externalLocation: URL get() = file.toURI().toURL() override val text: String by lazy { file.readText() } } +/** + * Converts the file into the SourceCode + */ fun File.toScriptSource(): SourceCode = FileScriptSource(this) +/** + * The implementation of the ScriptSource for a script in a String + */ open class StringScriptSource(val source: String) : SourceCode { override val text: String get() = source } +/** + * Converts the String into the SourceCode + */ fun String.toScriptSource(): SourceCode = StringScriptSource(this) diff --git a/libraries/scripting/common/src/kotlin/script/experimental/host/scriptingEnvironment.kt b/libraries/scripting/common/src/kotlin/script/experimental/host/scriptingEnvironment.kt index fc34c646593..92c6f7b25f8 100644 --- a/libraries/scripting/common/src/kotlin/script/experimental/host/scriptingEnvironment.kt +++ b/libraries/scripting/common/src/kotlin/script/experimental/host/scriptingEnvironment.kt @@ -12,6 +12,10 @@ import kotlin.script.experimental.util.PropertiesCollection interface ScriptingHostConfigurationKeys +/** + * The container for script evaluation configuration + * For usages see actual code examples + */ class ScriptingHostConfiguration(baseScriptingConfigurations: Iterable, body: Builder.() -> Unit) : PropertiesCollection(Builder(baseScriptingConfigurations).apply(body).data) { @@ -27,27 +31,30 @@ class ScriptingHostConfiguration(baseScriptingConfigurations: Iterable>() -// do not use configurationDependencies as script dependencies, so only the dependencies defined by compilationConfigurator will be used -// (NOTE: in this case they should include the dependencies for the base class anyway, since this class is needed for script -// compilation and instantiation, but compilationConfigurator could be excluded) -val ScriptingHostConfigurationKeys.isolatedDependencies by PropertiesCollection.key(false) - -// a "class loader" for KotlinTypes +/** + * The pointer to the generic "class loader" for the types used in the script configurations + */ val ScriptingHostConfigurationKeys.getScriptingClass by PropertiesCollection.key() - +/** + * The interface to the generic "class loader" for the types used in the script configurations + */ interface GetScriptingClass { operator fun invoke(classType: KotlinType, contextClass: KClass<*>, hostConfiguration: ScriptingHostConfiguration): KClass<*> } +// helper method fun ScriptingHostConfiguration.getScriptingClass(type: KotlinType, contextClass: KClass<*>): KClass<*> { val getClass = get(ScriptingHostConfiguration.getScriptingClass) ?: throw IllegalArgumentException("Expecting 'getScriptingClass' property in the scripting environment: unable to load scripting class $type") return getClass(type, contextClass, this) } +// helper method fun ScriptingHostConfiguration.getScriptingClass(type: KotlinType, context: Any): KClass<*> = getScriptingClass(type, context::class)