Kotlin Scripting JVM host for executing and compiling Kotlin scripts in JVM environments with JSR-223 integration and comprehensive caching mechanisms
—
The script compilation system provides JVM script compilation capabilities using the Kotlin compiler infrastructure with comprehensive configuration support and proxy-based compilation.
JVM script compiler implementation that handles script compilation with configurable host configuration and compiler proxy.
/**
* JVM script compiler for compiling Kotlin scripts with proxy-based compilation
* @param baseHostConfiguration Base host configuration for compilation
* @param compilerProxy Optional custom compiler proxy, defaults to ScriptJvmCompilerIsolated
*/
open class JvmScriptCompiler(
baseHostConfiguration: ScriptingHostConfiguration = defaultJvmScriptingHostConfiguration,
compilerProxy: ScriptCompilerProxy? = null
) : ScriptCompiler {
/** Final host configuration with defaults applied */
val hostConfiguration: ScriptingHostConfiguration
/** Compiler proxy for performing actual compilation */
val compilerProxy: ScriptCompilerProxy
/**
* Compiles a script with the given configuration
* @param script Source code to compile
* @param scriptCompilationConfiguration Compilation configuration
* @returns Result with diagnostics containing compiled script or errors
*/
override suspend operator fun invoke(
script: SourceCode,
scriptCompilationConfiguration: ScriptCompilationConfiguration
): ResultWithDiagnostics<CompiledScript>
}Usage Examples:
import kotlin.script.experimental.jvmhost.JvmScriptCompiler
import kotlin.script.experimental.api.*
import kotlin.script.experimental.jvm.*
// Basic compiler usage
val compiler = JvmScriptCompiler()
val script = """
val message = "Hello from compiled script!"
println(message)
message.length
""".trimIndent()
val compilationConfig = ScriptCompilationConfiguration {
dependencies(JvmDependency(kotlinStdlib))
compilerOptions.append("-opt-in=kotlin.RequiresOptIn")
}
val compilationResult = compiler(script.toScriptSource(), compilationConfig)
when (compilationResult) {
is ResultWithDiagnostics.Success -> {
val compiledScript = compilationResult.value
println("Compilation successful: ${compiledScript.sourceLocationId}")
// Get script class
val classResult = compiledScript.getClass()
when (classResult) {
is ResultWithDiagnostics.Success -> {
println("Script class: ${classResult.value.simpleName}")
}
is ResultWithDiagnostics.Failure -> {
println("Failed to get script class")
}
}
}
is ResultWithDiagnostics.Failure -> {
compilationResult.reports.forEach {
println("Compilation error: ${it.message}")
}
}
}
// Advanced compiler with custom configuration
val customHostConfiguration = ScriptingHostConfiguration {
jvm {
// Custom JVM configuration
compilationCache(FileBasedScriptCache(File("cache")))
}
}
val advancedCompiler = JvmScriptCompiler(
baseHostConfiguration = customHostConfiguration
)
val advancedCompilationConfig = ScriptCompilationConfiguration {
// Template-based configuration
baseClass(KotlinType(Any::class))
// Dependencies
dependencies(
JvmDependency(File("lib1.jar")),
JvmDependency(File("lib2.jar"))
)
// Import scripts
importScripts(FileBasedScriptSource(File("common.kts")))
// Compiler options
compilerOptions.append(
"-language-version", "2.0",
"-api-version", "2.0"
)
// IDE support
ide {
acceptedLocations(ScriptAcceptedLocation.Everywhere)
}
}
val advancedResult = advancedCompiler(script.toScriptSource(), advancedCompilationConfig)The compilation system uses ScriptCompilationConfiguration to control various aspects of script compilation.
// Core configuration builders (imported from kotlin.script.experimental.api)
fun ScriptCompilationConfiguration.Builder.dependencies(vararg dependencies: ScriptDependency): ScriptCompilationConfiguration.Builder
fun ScriptCompilationConfiguration.Builder.importScripts(vararg scripts: SourceCode): ScriptCompilationConfiguration.Builder
fun ScriptCompilationConfiguration.Builder.compilerOptions(vararg options: String): ScriptCompilationConfiguration.Builder
fun ScriptCompilationConfiguration.Builder.baseClass(baseClass: KotlinType): ScriptCompilationConfiguration.Builder
fun ScriptCompilationConfiguration.Builder.hostConfiguration(configuration: ScriptingHostConfiguration): ScriptCompilationConfiguration.BuilderConfiguration Examples:
// Dependency configuration
val configWithDependencies = ScriptCompilationConfiguration {
dependencies(
JvmDependency(kotlinStdlib),
JvmDependency(File("my-library.jar")),
JvmDependency("org.apache.commons:commons-lang3:3.12.0") // Maven coordinates
)
}
// Import scripts configuration
val configWithImports = ScriptCompilationConfiguration {
importScripts(
FileBasedScriptSource(File("utilities.kts")),
StringScriptSource("val commonConstant = 42", "common.kts")
)
}
// Compiler options configuration
val configWithOptions = ScriptCompilationConfiguration {
compilerOptions.append(
"-opt-in=kotlin.RequiresOptIn",
"-Xmulti-platform",
"-language-version", "2.0"
)
}
// Template-based configuration
@KotlinScript(
fileExtension = "custom.kts",
compilationConfiguration = CustomScriptConfiguration::class
)
class CustomScriptTemplate
object CustomScriptConfiguration : ScriptCompilationConfiguration({
baseClass(KotlinType(CustomScriptTemplate::class))
dependencies(JvmDependency(kotlinStdlib))
compilerOptions.append("-opt-in=kotlin.ExperimentalStdlibApi")
})
val templateConfig = ScriptCompilationConfiguration {
baseClass(KotlinType(CustomScriptTemplate::class))
refineConfiguration {
// Dynamic configuration refinement
onAnnotations(DependsOn::class, Repository::class) { context ->
// Process annotations to add dependencies
context.collectedData?.get(DependsOn::class)?.let { dependsOnList ->
ScriptCompilationConfiguration(context.compilationConfiguration) {
dependencies.append(JvmDependency(dependsOnList.flatMap { it.artifacts }))
}.asSuccess()
} ?: context.compilationConfiguration.asSuccess()
}
}
}The JVM script compiler uses a proxy pattern to delegate actual compilation to pluggable compiler implementations.
// Compiler proxy interface (from kotlin.scripting.compiler.plugin)
interface ScriptCompilerProxy {
suspend fun compile(
script: SourceCode,
scriptCompilationConfiguration: ScriptCompilationConfiguration
): ResultWithDiagnostics<CompiledScript>
}Custom Compiler Proxy Example:
import org.jetbrains.kotlin.scripting.compiler.plugin.ScriptCompilerProxy
class CustomScriptCompilerProxy(
private val hostConfiguration: ScriptingHostConfiguration
) : ScriptCompilerProxy {
override suspend fun compile(
script: SourceCode,
scriptCompilationConfiguration: ScriptCompilationConfiguration
): ResultWithDiagnostics<CompiledScript> {
// Custom compilation logic
return try {
// Perform custom pre-processing
val processedScript = preprocessScript(script)
// Delegate to default compiler
val defaultProxy = ScriptJvmCompilerIsolated(hostConfiguration)
defaultProxy.compile(processedScript, scriptCompilationConfiguration)
} catch (e: Exception) {
ResultWithDiagnostics.Failure(
listOf(e.asErrorDiagnostics("Custom compilation failed"))
)
}
}
private fun preprocessScript(script: SourceCode): SourceCode {
// Custom preprocessing logic
return StringScriptSource(
script.text.replace("@CustomMacro", "// Expanded macro"),
script.name
)
}
}
// Use custom proxy
val customCompiler = JvmScriptCompiler(
compilerProxy = CustomScriptCompilerProxy(defaultJvmScriptingHostConfiguration)
)The compilation process returns CompiledScript instances that encapsulate the compiled script artifacts.
interface CompiledScript {
/** Compilation configuration used to compile this script */
val compilationConfiguration: ScriptCompilationConfiguration
/** Source location identifier for error reporting */
val sourceLocationId: String?
/** Other scripts that were compiled together with this script */
val otherScripts: List<CompiledScript>
/** Result field information if script has a result expression */
val resultField: Pair<String, KotlinType>?
/**
* Gets the compiled script class
* @param scriptEvaluationConfiguration Optional evaluation configuration
* @returns Result containing the script class or compilation errors
*/
suspend fun getClass(scriptEvaluationConfiguration: ScriptEvaluationConfiguration? = null): ResultWithDiagnostics<KClass<*>>
}Working with Compiled Scripts:
val compilationResult = compiler(script.toScriptSource(), compilationConfig)
when (compilationResult) {
is ResultWithDiagnostics.Success -> {
val compiledScript = compilationResult.value
// Access compilation metadata
println("Source: ${compiledScript.sourceLocationId}")
println("Has result field: ${compiledScript.resultField != null}")
println("Other scripts: ${compiledScript.otherScripts.size}")
// Get script class for evaluation
val classResult = compiledScript.getClass()
when (classResult) {
is ResultWithDiagnostics.Success -> {
val scriptClass = classResult.value
// Create script instance
val constructor = scriptClass.constructors.first()
val scriptInstance = constructor.call()
// Access result field if available
compiledScript.resultField?.let { (fieldName, fieldType) ->
val field = scriptClass.java.getDeclaredField(fieldName)
field.isAccessible = true
val result = field.get(scriptInstance)
println("Script result: $result (${fieldType.typeName})")
}
}
is ResultWithDiagnostics.Failure -> {
println("Failed to get script class")
}
}
}
is ResultWithDiagnostics.Failure -> {
println("Compilation failed")
}
}Compilation errors are reported through the diagnostic system with detailed location information and error categories.
Detailed Error Handling:
val result = compiler(script.toScriptSource(), compilationConfig)
when (result) {
is ResultWithDiagnostics.Failure -> {
result.reports.groupBy { it.severity }.forEach { (severity, reports) ->
println("$severity errors:")
reports.forEach { diagnostic ->
val location = diagnostic.location?.let { loc ->
" at line ${loc.start.line}, column ${loc.start.col}"
} ?: ""
println(" ${diagnostic.message}$location")
// Show exception details if available
diagnostic.exception?.let { ex ->
println(" Caused by: ${ex.javaClass.simpleName}: ${ex.message}")
ex.stackTrace.take(3).forEach { frame ->
println(" at $frame")
}
}
}
}
}
}Install with Tessl CLI
npx tessl i tessl/maven-org-jetbrains-kotlin--kotlin-scripting-jvm-host