or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

error-handling.mdhost-integration.mdindex.mdrepl-system.mdscript-annotations.mdscript-compilation.mdscript-evaluation.mdsource-code.mdtype-system.md

error-handling.mddocs/

0

# Error Handling and Diagnostics

1

2

Comprehensive error handling system with diagnostic reporting, result wrapper types, and utility functions. Provides structured error reporting and result handling throughout the Kotlin scripting system.

3

4

## Capabilities

5

6

### ResultWithDiagnostics

7

8

Primary result wrapper type that combines operation results with diagnostic information.

9

10

```kotlin { .api }

11

/**

12

* Result wrapper that includes diagnostic information

13

*/

14

sealed class ResultWithDiagnostics<out R> {

15

/** List of diagnostic reports associated with this result */

16

abstract val reports: List<ScriptDiagnostic>

17

18

/**

19

* Successful result with optional diagnostic reports

20

*/

21

data class Success<out R>(

22

val value: R,

23

override val reports: List<ScriptDiagnostic> = emptyList()

24

) : ResultWithDiagnostics<R>()

25

26

/**

27

* Failed result with diagnostic reports explaining the failure

28

*/

29

data class Failure(

30

override val reports: List<ScriptDiagnostic>

31

) : ResultWithDiagnostics<Nothing>()

32

}

33

```

34

35

### ScriptDiagnostic

36

37

Detailed diagnostic information for script processing errors, warnings, and information.

38

39

```kotlin { .api }

40

/**

41

* Diagnostic report for script processing

42

*/

43

data class ScriptDiagnostic(

44

/** Diagnostic code identifier */

45

val code: Int,

46

/** Human-readable diagnostic message */

47

val message: String,

48

/** Severity level of the diagnostic */

49

val severity: Severity = Severity.ERROR,

50

/** Source file path where the diagnostic occurred */

51

val sourcePath: String? = null,

52

/** Location within the source where the diagnostic occurred */

53

val location: SourceCode.Location? = null,

54

/** Exception that caused this diagnostic, if any */

55

val exception: Throwable? = null

56

) {

57

/**

58

* Severity levels for diagnostics

59

*/

60

enum class Severity {

61

DEBUG,

62

INFO,

63

WARNING,

64

ERROR,

65

FATAL

66

}

67

68

/**

69

* Alternative constructor with LocationWithId

70

*/

71

constructor(

72

code: Int,

73

message: String,

74

severity: Severity = Severity.ERROR,

75

locationWithId: SourceCode.LocationWithId?,

76

exception: Throwable? = null

77

) : this(code, message, severity, locationWithId?.codeLocationId, locationWithId?.locationInText, exception)

78

}

79

```

80

81

### Result Extension Functions

82

83

Utility functions for working with ResultWithDiagnostics instances.

84

85

```kotlin { .api }

86

/**

87

* Execute action if result is successful

88

*/

89

fun <R, T> ResultWithDiagnostics<R>.onSuccess(

90

action: (R) -> T

91

): T?

92

93

/**

94

* Execute action if result is a failure

95

*/

96

fun <R> ResultWithDiagnostics<R>.onFailure(

97

action: (List<ScriptDiagnostic>) -> Unit

98

): ResultWithDiagnostics<R>

99

100

/**

101

* Get the value if successful, null if failed

102

*/

103

fun <R> ResultWithDiagnostics<R>.valueOrNull(): R?

104

105

/**

106

* Get the value if successful, or default value if failed

107

*/

108

fun <R> ResultWithDiagnostics<R>.valueOr(default: R): R

109

110

/**

111

* Get the value if successful, or throw exception if failed

112

*/

113

fun <R> ResultWithDiagnostics<R>.valueOrThrow(): R

114

115

/**

116

* Transform successful result value

117

*/

118

fun <R, T> ResultWithDiagnostics<R>.map(transform: (R) -> T): ResultWithDiagnostics<T>

119

120

/**

121

* Transform successful result and flatten nested results

122

*/

123

fun <R, T> ResultWithDiagnostics<R>.flatMap(

124

transform: (R) -> ResultWithDiagnostics<T>

125

): ResultWithDiagnostics<T>

126

```

127

128

### Diagnostic Extension Functions

129

130

Utility functions for working with ScriptDiagnostic instances.

131

132

```kotlin { .api }

133

/**

134

* Check if diagnostic represents an error

135

*/

136

fun ScriptDiagnostic.isError(): Boolean

137

138

/**

139

* Check if diagnostic represents a warning

140

*/

141

fun ScriptDiagnostic.isWarning(): Boolean

142

143

/**

144

* Check if diagnostic represents informational message

145

*/

146

fun ScriptDiagnostic.isInfo(): Boolean

147

```

148

149

### Collection Utilities

150

151

Utilities for working with collections of results and diagnostics.

152

153

```kotlin { .api }

154

/**

155

* Collector for iterating over multiple results

156

*/

157

class IterableResultsCollector<T> {

158

fun collect(iterable: Iterable<ResultWithDiagnostics<T>>): ResultWithDiagnostics<List<T>>

159

}

160

161

/**

162

* Transform collection if all results are successful

163

*/

164

fun <T, R> Iterable<ResultWithDiagnostics<T>>.mapSuccess(

165

transform: (T) -> R

166

): ResultWithDiagnostics<List<R>>

167

168

/**

169

* Transform collection and flatten nested results

170

*/

171

fun <T, R> Iterable<ResultWithDiagnostics<T>>.flatMapSuccess(

172

transform: (T) -> ResultWithDiagnostics<R>

173

): ResultWithDiagnostics<List<R>>

174

```

175

176

**Usage Examples:**

177

178

```kotlin

179

import kotlin.script.experimental.api.*

180

181

// Creating successful results

182

val successResult = "Hello World".asSuccess()

183

val successWithWarnings = "Hello World".asSuccess(listOf(

184

ScriptDiagnostic(

185

message = "Deprecated API used",

186

severity = ScriptDiagnostic.Severity.WARNING

187

)

188

))

189

190

// Creating failure results

191

val failureResult = listOf(

192

ScriptDiagnostic(

193

code = 1001,

194

message = "Compilation failed: unresolved reference",

195

severity = ScriptDiagnostic.Severity.ERROR,

196

location = SourceCode.Location(

197

start = SourceCode.Position(line = 5, col = 10)

198

)

199

)

200

).asFailure()

201

202

// Handling results

203

when (val result = compileScript()) {

204

is ResultWithDiagnostics.Success -> {

205

val compiledScript = result.value

206

println("Compilation successful: ${compiledScript.sourceLocationId}")

207

208

// Handle warnings

209

result.reports.filter { it.isWarning() }.forEach { warning ->

210

println("Warning: ${warning.message}")

211

}

212

}

213

is ResultWithDiagnostics.Failure -> {

214

result.reports.forEach { diagnostic ->

215

val location = diagnostic.location?.let { loc ->

216

" at line ${loc.start.line}, column ${loc.start.col}"

217

} ?: ""

218

println("${diagnostic.severity}: ${diagnostic.message}$location")

219

}

220

}

221

}

222

```

223

224

### Result Transformation

225

226

```kotlin

227

// Transform successful results

228

val originalResult: ResultWithDiagnostics<String> = "42".asSuccess()

229

val transformedResult: ResultWithDiagnostics<Int> = originalResult.map { it.toInt() }

230

231

// Chain operations with flatMap

232

val chainedResult = originalResult

233

.flatMap { value ->

234

if (value.isNotEmpty()) {

235

value.toIntOrNull()?.asSuccess() ?: "Invalid number".asFailure()

236

} else {

237

"Empty value".asFailure()

238

}

239

}

240

.map { number -> number * 2 }

241

242

// Using utility functions

243

val value = originalResult.valueOrNull() // "42" or null

244

val safeValue = originalResult.valueOr("default") // "42" or "default"

245

246

try {

247

val requiredValue = originalResult.valueOrThrow() // "42" or throws exception

248

} catch (e: Exception) {

249

println("Failed to get value: ${e.message}")

250

}

251

```

252

253

### Error Creation Utilities

254

255

```kotlin

256

// Create diagnostic reports

257

fun createCompilationError(message: String, location: SourceCode.Location? = null): ScriptDiagnostic {

258

return ScriptDiagnostic(

259

code = 2000,

260

message = message,

261

severity = ScriptDiagnostic.Severity.ERROR,

262

location = location

263

)

264

}

265

266

fun createWarning(message: String): ScriptDiagnostic {

267

return ScriptDiagnostic(

268

message = message,

269

severity = ScriptDiagnostic.Severity.WARNING

270

)

271

}

272

273

// Helper extensions for creating results

274

fun <T> T.asSuccess(reports: List<ScriptDiagnostic> = emptyList()): ResultWithDiagnostics<T> {

275

return ResultWithDiagnostics.Success(this, reports)

276

}

277

278

fun List<ScriptDiagnostic>.asFailure(): ResultWithDiagnostics<Nothing> {

279

return ResultWithDiagnostics.Failure(this)

280

}

281

282

fun String.asFailure(): ResultWithDiagnostics<Nothing> {

283

return listOf(ScriptDiagnostic(message = this)).asFailure()

284

}

285

286

// Usage

287

val result1 = "success".asSuccess()

288

val result2 = "Compilation failed".asFailure()

289

val result3 = listOf(

290

createCompilationError("Missing import"),

291

createWarning("Unused variable")

292

).asFailure()

293

```

294

295

### Advanced Error Handling

296

297

```kotlin

298

// Collect multiple results

299

fun processMultipleScripts(scripts: List<SourceCode>): ResultWithDiagnostics<List<CompiledScript>> {

300

val results = scripts.map { script ->

301

compileScript(script) // Returns ResultWithDiagnostics<CompiledScript>

302

}

303

304

// Collect all results - fails if any individual result fails

305

return IterableResultsCollector<CompiledScript>().collect(results)

306

}

307

308

// Transform with success mapping

309

fun getScriptNames(scripts: List<SourceCode>): ResultWithDiagnostics<List<String>> {

310

return scripts

311

.map { compileScript(it) }

312

.mapSuccess { compiledScript ->

313

compiledScript.sourceLocationId ?: "unknown"

314

}

315

}

316

317

// Chain operations with error accumulation

318

fun processScriptPipeline(source: SourceCode): ResultWithDiagnostics<String> {

319

return compileScript(source)

320

.flatMap { compiled -> evaluateScript(compiled) }

321

.flatMap { evaluated -> formatResult(evaluated) }

322

.map { formatted -> "Result: $formatted" }

323

}

324

325

// Custom error handling

326

class ScriptProcessingException(

327

message: String,

328

val diagnostics: List<ScriptDiagnostic>,

329

cause: Throwable? = null

330

) : Exception(message, cause)

331

332

fun handleScriptErrors(result: ResultWithDiagnostics<*>) {

333

result.onFailure { diagnostics ->

334

val errorMessages = diagnostics

335

.filter { it.severity >= ScriptDiagnostic.Severity.ERROR }

336

.map { it.message }

337

338

if (errorMessages.isNotEmpty()) {

339

throw ScriptProcessingException(

340

message = "Script processing failed: ${errorMessages.joinToString("; ")}",

341

diagnostics = diagnostics

342

)

343

}

344

}

345

}

346

```

347

348

### Diagnostic Filtering and Analysis

349

350

```kotlin

351

// Filter diagnostics by severity

352

fun filterErrors(diagnostics: List<ScriptDiagnostic>): List<ScriptDiagnostic> {

353

return diagnostics.filter { it.severity >= ScriptDiagnostic.Severity.ERROR }

354

}

355

356

fun filterWarnings(diagnostics: List<ScriptDiagnostic>): List<ScriptDiagnostic> {

357

return diagnostics.filter { it.severity == ScriptDiagnostic.Severity.WARNING }

358

}

359

360

// Diagnostic analysis

361

fun analyzeDiagnostics(diagnostics: List<ScriptDiagnostic>): DiagnosticSummary {

362

return DiagnosticSummary(

363

errorCount = diagnostics.count { it.isError() },

364

warningCount = diagnostics.count { it.isWarning() },

365

infoCount = diagnostics.count { it.isInfo() },

366

hasErrors = diagnostics.any { it.isError() },

367

mostSevere = diagnostics.maxByOrNull { it.severity.ordinal }?.severity

368

)

369

}

370

371

data class DiagnosticSummary(

372

val errorCount: Int,

373

val warningCount: Int,

374

val infoCount: Int,

375

val hasErrors: Boolean,

376

val mostSevere: ScriptDiagnostic.Severity?

377

)

378

```