Kotlin JVM scripting support library that provides core functionality for executing and evaluating Kotlin scripts on the JVM platform
—
Script evaluation engines supporting both standalone script execution and REPL (Read-Eval-Print Loop) scenarios. The evaluators provide proper error handling, diagnostics, and support for various execution contexts including interactive development environments.
Basic implementation of JVM script evaluation for standalone script execution with comprehensive error handling and diagnostics support.
/**
* Basic implementation of JVM script evaluation
* Supports single script execution with full error reporting
*/
open class BasicJvmScriptEvaluator : ScriptEvaluator {
/**
* Evaluate a compiled script with given configuration
* @param compiledScript The compiled script to execute
* @param scriptEvaluationConfiguration Configuration for script evaluation
* @return Result containing evaluation outcome or diagnostics on failure
*/
suspend operator fun invoke(
compiledScript: CompiledScript,
scriptEvaluationConfiguration: ScriptEvaluationConfiguration
): ResultWithDiagnostics<EvaluationResult>
}Usage Examples:
import kotlin.script.experimental.api.*
import kotlin.script.experimental.jvm.*
import kotlin.script.experimental.host.toScriptSource
// Create evaluator instance
val evaluator = BasicJvmScriptEvaluator()
// Configure evaluation environment
val evaluationConfig = ScriptEvaluationConfiguration {
jvm {
baseClassLoader = Thread.currentThread().contextClassLoader
loadDependencies = true
}
}
// Evaluate compiled script
val result = evaluator(compiledScript, evaluationConfig)
when (result) {
is ResultWithDiagnostics.Success -> {
println("Script executed successfully")
println("Result: ${result.value.returnValue}")
}
is ResultWithDiagnostics.Failure -> {
println("Script execution failed:")
result.reports.forEach { diagnostic ->
println("${diagnostic.severity}: ${diagnostic.message}")
}
}
}REPL evaluator for JVM scripts supporting interactive evaluation with snippet history management and incremental execution.
/**
* REPL evaluator for JVM scripts
* Maintains execution history and supports incremental evaluation
* @param scriptEvaluator Underlying script evaluator (default: BasicJvmScriptEvaluator)
*/
class BasicJvmReplEvaluator(
val scriptEvaluator: ScriptEvaluator = BasicJvmScriptEvaluator()
) : ReplEvaluator<CompiledSnippet, KJvmEvaluatedSnippet> {
/**
* Reference to the last evaluated snippet for context
*/
var lastEvaluatedSnippet: LinkedSnippetImpl<KJvmEvaluatedSnippet>?
/**
* Evaluate a snippet in REPL context
* @param snippet Compiled snippet linked to previous evaluations
* @param configuration Configuration for evaluation
* @return Result containing evaluated snippet or diagnostics
*/
suspend fun eval(
snippet: LinkedSnippet<out CompiledScript>,
configuration: ScriptEvaluationConfiguration
): ResultWithDiagnostics<LinkedSnippet<KJvmEvaluatedSnippet>>
}Usage Examples:
import kotlin.script.experimental.api.*
import kotlin.script.experimental.jvm.*
// Create REPL evaluator
val replEvaluator = BasicJvmReplEvaluator()
// Configure REPL evaluation
val replConfig = ScriptEvaluationConfiguration {
jvm {
baseClassLoader = Thread.currentThread().contextClassLoader
// Use last snippet's ClassLoader for context
lastSnippetClassLoader = replEvaluator.lastEvaluatedSnippet
?.get()?.configuration?.jvm?.baseClassLoader?.value
}
}
// Evaluate first snippet
val snippet1 = // ... compiled snippet
val result1 = replEvaluator.eval(snippet1, replConfig)
// Evaluate second snippet (can reference variables from first)
val snippet2 = // ... compiled snippet
val result2 = replEvaluator.eval(snippet2, replConfig)
// Access evaluation history
val lastSnippet = replEvaluator.lastEvaluatedSnippet?.get()
println("Last result: ${lastSnippet?.result}")Represents an evaluated JVM script snippet with execution results and configuration context.
/**
* Represents an evaluated JVM script snippet
* @param compiledSnippet The original compiled snippet
* @param configuration Configuration used for evaluation
* @param result The evaluation result value
*/
class KJvmEvaluatedSnippet(
compiledSnippet: CompiledSnippet,
configuration: ScriptEvaluationConfiguration,
result: ResultValue
) : EvaluatedSnippet {
/** The compiled script that was evaluated */
override val compiledSnippet: CompiledScript
/** Configuration used during evaluation */
override val configuration: ScriptEvaluationConfiguration
/** The result of evaluation */
override val result: ResultValue
}Usage Example:
// Access evaluated snippet properties
val evaluatedSnippet: KJvmEvaluatedSnippet = // ... from REPL evaluation
// Check evaluation result
when (evaluatedSnippet.result) {
is ResultValue.Value -> {
println("Snippet returned: ${evaluatedSnippet.result.value}")
println("Type: ${evaluatedSnippet.result.type}")
}
is ResultValue.Error -> {
println("Snippet failed with error: ${evaluatedSnippet.result.error}")
}
is ResultValue.Unit -> {
println("Snippet executed successfully (no return value)")
}
}
// Access compilation information
println("Script class: ${evaluatedSnippet.compiledSnippet}")
println("Base ClassLoader: ${evaluatedSnippet.configuration.jvm.baseClassLoader.value}")Utility functions for direct script execution and runner integration.
/**
* Execute a compiled script class directly
* @param scriptClass Compiled script class to execute
* @param args Command line arguments to pass to script
*/
fun runCompiledScript(scriptClass: Class<*>, vararg args: String)Usage Example:
import kotlin.script.experimental.jvm.runCompiledScript
// Assume we have a compiled script class
val scriptClass: Class<*> = // ... obtained from compilation
// Execute script with arguments
try {
runCompiledScript(scriptClass, "arg1", "arg2", "arg3")
println("Script executed successfully")
} catch (e: Exception) {
println("Script execution failed: ${e.message}")
}Create custom evaluator with specialized behavior:
class CustomJvmScriptEvaluator : BasicJvmScriptEvaluator() {
override suspend operator fun invoke(
compiledScript: CompiledScript,
scriptEvaluationConfiguration: ScriptEvaluationConfiguration
): ResultWithDiagnostics<EvaluationResult> {
// Add custom pre-execution logic
println("Executing script: ${compiledScript.sourceLocationId}")
// Call parent implementation
val result = super.invoke(compiledScript, scriptEvaluationConfiguration)
// Add custom post-execution logic
when (result) {
is ResultWithDiagnostics.Success -> {
println("Execution completed in ${measureExecutionTime()}ms")
}
is ResultWithDiagnostics.Failure -> {
logExecutionFailure(result.reports)
}
}
return result
}
}REPL evaluator with persistent history management:
class PersistentReplEvaluator(
private val historyFile: File
) : BasicJvmReplEvaluator() {
private val history = loadHistoryFromFile(historyFile)
override suspend fun eval(
snippet: LinkedSnippet<out CompiledScript>,
configuration: ScriptEvaluationConfiguration
): ResultWithDiagnostics<LinkedSnippet<KJvmEvaluatedSnippet>> {
val result = super.eval(snippet, configuration)
// Persist successful evaluations
if (result is ResultWithDiagnostics.Success) {
history.add(snippet, result.value.get())
saveHistoryToFile(history, historyFile)
}
return result
}
}Thread-safe evaluator for concurrent script execution:
import kotlinx.coroutines.*
import java.util.concurrent.ConcurrentHashMap
class ConcurrentScriptEvaluator : BasicJvmScriptEvaluator() {
private val executionContexts = ConcurrentHashMap<String, ScriptEvaluationConfiguration>()
suspend fun evaluateConcurrently(
scripts: List<Pair<CompiledScript, ScriptEvaluationConfiguration>>
): List<ResultWithDiagnostics<EvaluationResult>> = withContext(Dispatchers.Default) {
scripts.map { (script, config) ->
async {
invoke(script, config)
}
}.awaitAll()
}
}REPL evaluator with error recovery and state restoration:
class RobustReplEvaluator : BasicJvmReplEvaluator() {
private var lastKnownGoodState: LinkedSnippetImpl<KJvmEvaluatedSnippet>? = null
override suspend fun eval(
snippet: LinkedSnippet<out CompiledScript>,
configuration: ScriptEvaluationConfiguration
): ResultWithDiagnostics<LinkedSnippet<KJvmEvaluatedSnippet>> {
// Save current state before evaluation
val currentState = lastEvaluatedSnippet
val result = super.eval(snippet, configuration)
when (result) {
is ResultWithDiagnostics.Success -> {
lastKnownGoodState = result.value as LinkedSnippetImpl<KJvmEvaluatedSnippet>
}
is ResultWithDiagnostics.Failure -> {
// Restore last known good state on error
lastEvaluatedSnippet = lastKnownGoodState
}
}
return result
}
}Install with Tessl CLI
npx tessl i tessl/maven-org-jetbrains-kotlin--kotlin-scripting-jvm