0
# Script Evaluators
1
2
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.
3
4
## Capabilities
5
6
### Basic JVM Script Evaluator
7
8
Basic implementation of JVM script evaluation for standalone script execution with comprehensive error handling and diagnostics support.
9
10
```kotlin { .api }
11
/**
12
* Basic implementation of JVM script evaluation
13
* Supports single script execution with full error reporting
14
*/
15
open class BasicJvmScriptEvaluator : ScriptEvaluator {
16
/**
17
* Evaluate a compiled script with given configuration
18
* @param compiledScript The compiled script to execute
19
* @param scriptEvaluationConfiguration Configuration for script evaluation
20
* @return Result containing evaluation outcome or diagnostics on failure
21
*/
22
suspend operator fun invoke(
23
compiledScript: CompiledScript,
24
scriptEvaluationConfiguration: ScriptEvaluationConfiguration
25
): ResultWithDiagnostics<EvaluationResult>
26
}
27
```
28
29
**Usage Examples:**
30
31
```kotlin
32
import kotlin.script.experimental.api.*
33
import kotlin.script.experimental.jvm.*
34
import kotlin.script.experimental.host.toScriptSource
35
36
// Create evaluator instance
37
val evaluator = BasicJvmScriptEvaluator()
38
39
// Configure evaluation environment
40
val evaluationConfig = ScriptEvaluationConfiguration {
41
jvm {
42
baseClassLoader = Thread.currentThread().contextClassLoader
43
loadDependencies = true
44
}
45
}
46
47
// Evaluate compiled script
48
val result = evaluator(compiledScript, evaluationConfig)
49
50
when (result) {
51
is ResultWithDiagnostics.Success -> {
52
println("Script executed successfully")
53
println("Result: ${result.value.returnValue}")
54
}
55
is ResultWithDiagnostics.Failure -> {
56
println("Script execution failed:")
57
result.reports.forEach { diagnostic ->
58
println("${diagnostic.severity}: ${diagnostic.message}")
59
}
60
}
61
}
62
```
63
64
### Basic JVM REPL Evaluator
65
66
REPL evaluator for JVM scripts supporting interactive evaluation with snippet history management and incremental execution.
67
68
```kotlin { .api }
69
/**
70
* REPL evaluator for JVM scripts
71
* Maintains execution history and supports incremental evaluation
72
* @param scriptEvaluator Underlying script evaluator (default: BasicJvmScriptEvaluator)
73
*/
74
class BasicJvmReplEvaluator(
75
val scriptEvaluator: ScriptEvaluator = BasicJvmScriptEvaluator()
76
) : ReplEvaluator<CompiledSnippet, KJvmEvaluatedSnippet> {
77
78
/**
79
* Reference to the last evaluated snippet for context
80
*/
81
var lastEvaluatedSnippet: LinkedSnippetImpl<KJvmEvaluatedSnippet>?
82
83
/**
84
* Evaluate a snippet in REPL context
85
* @param snippet Compiled snippet linked to previous evaluations
86
* @param configuration Configuration for evaluation
87
* @return Result containing evaluated snippet or diagnostics
88
*/
89
suspend fun eval(
90
snippet: LinkedSnippet<out CompiledScript>,
91
configuration: ScriptEvaluationConfiguration
92
): ResultWithDiagnostics<LinkedSnippet<KJvmEvaluatedSnippet>>
93
}
94
```
95
96
**Usage Examples:**
97
98
```kotlin
99
import kotlin.script.experimental.api.*
100
import kotlin.script.experimental.jvm.*
101
102
// Create REPL evaluator
103
val replEvaluator = BasicJvmReplEvaluator()
104
105
// Configure REPL evaluation
106
val replConfig = ScriptEvaluationConfiguration {
107
jvm {
108
baseClassLoader = Thread.currentThread().contextClassLoader
109
// Use last snippet's ClassLoader for context
110
lastSnippetClassLoader = replEvaluator.lastEvaluatedSnippet
111
?.get()?.configuration?.jvm?.baseClassLoader?.value
112
}
113
}
114
115
// Evaluate first snippet
116
val snippet1 = // ... compiled snippet
117
val result1 = replEvaluator.eval(snippet1, replConfig)
118
119
// Evaluate second snippet (can reference variables from first)
120
val snippet2 = // ... compiled snippet
121
val result2 = replEvaluator.eval(snippet2, replConfig)
122
123
// Access evaluation history
124
val lastSnippet = replEvaluator.lastEvaluatedSnippet?.get()
125
println("Last result: ${lastSnippet?.result}")
126
```
127
128
### Evaluated Snippet
129
130
Represents an evaluated JVM script snippet with execution results and configuration context.
131
132
```kotlin { .api }
133
/**
134
* Represents an evaluated JVM script snippet
135
* @param compiledSnippet The original compiled snippet
136
* @param configuration Configuration used for evaluation
137
* @param result The evaluation result value
138
*/
139
class KJvmEvaluatedSnippet(
140
compiledSnippet: CompiledSnippet,
141
configuration: ScriptEvaluationConfiguration,
142
result: ResultValue
143
) : EvaluatedSnippet {
144
145
/** The compiled script that was evaluated */
146
override val compiledSnippet: CompiledScript
147
148
/** Configuration used during evaluation */
149
override val configuration: ScriptEvaluationConfiguration
150
151
/** The result of evaluation */
152
override val result: ResultValue
153
}
154
```
155
156
**Usage Example:**
157
158
```kotlin
159
// Access evaluated snippet properties
160
val evaluatedSnippet: KJvmEvaluatedSnippet = // ... from REPL evaluation
161
162
// Check evaluation result
163
when (evaluatedSnippet.result) {
164
is ResultValue.Value -> {
165
println("Snippet returned: ${evaluatedSnippet.result.value}")
166
println("Type: ${evaluatedSnippet.result.type}")
167
}
168
is ResultValue.Error -> {
169
println("Snippet failed with error: ${evaluatedSnippet.result.error}")
170
}
171
is ResultValue.Unit -> {
172
println("Snippet executed successfully (no return value)")
173
}
174
}
175
176
// Access compilation information
177
println("Script class: ${evaluatedSnippet.compiledSnippet}")
178
println("Base ClassLoader: ${evaluatedSnippet.configuration.jvm.baseClassLoader.value}")
179
```
180
181
### Script Execution Utilities
182
183
Utility functions for direct script execution and runner integration.
184
185
```kotlin { .api }
186
/**
187
* Execute a compiled script class directly
188
* @param scriptClass Compiled script class to execute
189
* @param args Command line arguments to pass to script
190
*/
191
fun runCompiledScript(scriptClass: Class<*>, vararg args: String)
192
```
193
194
**Usage Example:**
195
196
```kotlin
197
import kotlin.script.experimental.jvm.runCompiledScript
198
199
// Assume we have a compiled script class
200
val scriptClass: Class<*> = // ... obtained from compilation
201
202
// Execute script with arguments
203
try {
204
runCompiledScript(scriptClass, "arg1", "arg2", "arg3")
205
println("Script executed successfully")
206
} catch (e: Exception) {
207
println("Script execution failed: ${e.message}")
208
}
209
```
210
211
## Advanced Usage Patterns
212
213
### Custom Evaluator
214
215
Create custom evaluator with specialized behavior:
216
217
```kotlin
218
class CustomJvmScriptEvaluator : BasicJvmScriptEvaluator() {
219
override suspend operator fun invoke(
220
compiledScript: CompiledScript,
221
scriptEvaluationConfiguration: ScriptEvaluationConfiguration
222
): ResultWithDiagnostics<EvaluationResult> {
223
// Add custom pre-execution logic
224
println("Executing script: ${compiledScript.sourceLocationId}")
225
226
// Call parent implementation
227
val result = super.invoke(compiledScript, scriptEvaluationConfiguration)
228
229
// Add custom post-execution logic
230
when (result) {
231
is ResultWithDiagnostics.Success -> {
232
println("Execution completed in ${measureExecutionTime()}ms")
233
}
234
is ResultWithDiagnostics.Failure -> {
235
logExecutionFailure(result.reports)
236
}
237
}
238
239
return result
240
}
241
}
242
```
243
244
### REPL with History Persistence
245
246
REPL evaluator with persistent history management:
247
248
```kotlin
249
class PersistentReplEvaluator(
250
private val historyFile: File
251
) : BasicJvmReplEvaluator() {
252
253
private val history = loadHistoryFromFile(historyFile)
254
255
override suspend fun eval(
256
snippet: LinkedSnippet<out CompiledScript>,
257
configuration: ScriptEvaluationConfiguration
258
): ResultWithDiagnostics<LinkedSnippet<KJvmEvaluatedSnippet>> {
259
val result = super.eval(snippet, configuration)
260
261
// Persist successful evaluations
262
if (result is ResultWithDiagnostics.Success) {
263
history.add(snippet, result.value.get())
264
saveHistoryToFile(history, historyFile)
265
}
266
267
return result
268
}
269
}
270
```
271
272
### Concurrent Script Evaluation
273
274
Thread-safe evaluator for concurrent script execution:
275
276
```kotlin
277
import kotlinx.coroutines.*
278
import java.util.concurrent.ConcurrentHashMap
279
280
class ConcurrentScriptEvaluator : BasicJvmScriptEvaluator() {
281
private val executionContexts = ConcurrentHashMap<String, ScriptEvaluationConfiguration>()
282
283
suspend fun evaluateConcurrently(
284
scripts: List<Pair<CompiledScript, ScriptEvaluationConfiguration>>
285
): List<ResultWithDiagnostics<EvaluationResult>> = withContext(Dispatchers.Default) {
286
scripts.map { (script, config) ->
287
async {
288
invoke(script, config)
289
}
290
}.awaitAll()
291
}
292
}
293
```
294
295
### Error Recovery in REPL
296
297
REPL evaluator with error recovery and state restoration:
298
299
```kotlin
300
class RobustReplEvaluator : BasicJvmReplEvaluator() {
301
private var lastKnownGoodState: LinkedSnippetImpl<KJvmEvaluatedSnippet>? = null
302
303
override suspend fun eval(
304
snippet: LinkedSnippet<out CompiledScript>,
305
configuration: ScriptEvaluationConfiguration
306
): ResultWithDiagnostics<LinkedSnippet<KJvmEvaluatedSnippet>> {
307
// Save current state before evaluation
308
val currentState = lastEvaluatedSnippet
309
310
val result = super.eval(snippet, configuration)
311
312
when (result) {
313
is ResultWithDiagnostics.Success -> {
314
lastKnownGoodState = result.value as LinkedSnippetImpl<KJvmEvaluatedSnippet>
315
}
316
is ResultWithDiagnostics.Failure -> {
317
// Restore last known good state on error
318
lastEvaluatedSnippet = lastKnownGoodState
319
}
320
}
321
322
return result
323
}
324
}
325
```