CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/maven-org-jetbrains-kotlin--kotlin-scripting-common

Core interfaces and data structures for Kotlin script compilation, evaluation, and IDE integration

Pending
Overview
Eval results
Files

error-handling.mddocs/

Error Handling and Diagnostics

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.

Capabilities

ResultWithDiagnostics

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

/**
 * Result wrapper that includes diagnostic information
 */
sealed class ResultWithDiagnostics<out R> {
    /** List of diagnostic reports associated with this result */
    abstract val reports: List<ScriptDiagnostic>
    
    /**
     * Successful result with optional diagnostic reports
     */
    data class Success<out R>(
        val value: R,
        override val reports: List<ScriptDiagnostic> = emptyList()
    ) : ResultWithDiagnostics<R>()
    
    /**
     * Failed result with diagnostic reports explaining the failure
     */
    data class Failure(
        override val reports: List<ScriptDiagnostic>
    ) : ResultWithDiagnostics<Nothing>()
}

ScriptDiagnostic

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

/**
 * Diagnostic report for script processing
 */
data class ScriptDiagnostic(
    /** Diagnostic code identifier */
    val code: Int,
    /** Human-readable diagnostic message */
    val message: String,
    /** Severity level of the diagnostic */
    val severity: Severity = Severity.ERROR,
    /** Source file path where the diagnostic occurred */
    val sourcePath: String? = null,
    /** Location within the source where the diagnostic occurred */
    val location: SourceCode.Location? = null,
    /** Exception that caused this diagnostic, if any */
    val exception: Throwable? = null
) {
    /**
     * Severity levels for diagnostics
     */
    enum class Severity {
        DEBUG,
        INFO, 
        WARNING,
        ERROR,
        FATAL
    }
    
    /**
     * Alternative constructor with LocationWithId
     */
    constructor(
        code: Int,
        message: String,
        severity: Severity = Severity.ERROR,
        locationWithId: SourceCode.LocationWithId?,
        exception: Throwable? = null
    ) : this(code, message, severity, locationWithId?.codeLocationId, locationWithId?.locationInText, exception)
}

Result Extension Functions

Utility functions for working with ResultWithDiagnostics instances.

/**
 * Execute action if result is successful
 */
fun <R, T> ResultWithDiagnostics<R>.onSuccess(
    action: (R) -> T
): T?

/**
 * Execute action if result is a failure
 */
fun <R> ResultWithDiagnostics<R>.onFailure(
    action: (List<ScriptDiagnostic>) -> Unit
): ResultWithDiagnostics<R>

/**
 * Get the value if successful, null if failed
 */
fun <R> ResultWithDiagnostics<R>.valueOrNull(): R?

/**
 * Get the value if successful, or default value if failed
 */
fun <R> ResultWithDiagnostics<R>.valueOr(default: R): R

/**
 * Get the value if successful, or throw exception if failed
 */
fun <R> ResultWithDiagnostics<R>.valueOrThrow(): R

/**
 * Transform successful result value
 */
fun <R, T> ResultWithDiagnostics<R>.map(transform: (R) -> T): ResultWithDiagnostics<T>

/**
 * Transform successful result and flatten nested results
 */
fun <R, T> ResultWithDiagnostics<R>.flatMap(
    transform: (R) -> ResultWithDiagnostics<T>
): ResultWithDiagnostics<T>

Diagnostic Extension Functions

Utility functions for working with ScriptDiagnostic instances.

/**
 * Check if diagnostic represents an error
 */
fun ScriptDiagnostic.isError(): Boolean

/**
 * Check if diagnostic represents a warning
 */
fun ScriptDiagnostic.isWarning(): Boolean

/**
 * Check if diagnostic represents informational message
 */
fun ScriptDiagnostic.isInfo(): Boolean

Collection Utilities

Utilities for working with collections of results and diagnostics.

/**
 * Collector for iterating over multiple results
 */
class IterableResultsCollector<T> {
    fun collect(iterable: Iterable<ResultWithDiagnostics<T>>): ResultWithDiagnostics<List<T>>
}

/**
 * Transform collection if all results are successful
 */
fun <T, R> Iterable<ResultWithDiagnostics<T>>.mapSuccess(
    transform: (T) -> R
): ResultWithDiagnostics<List<R>>

/**
 * Transform collection and flatten nested results
 */
fun <T, R> Iterable<ResultWithDiagnostics<T>>.flatMapSuccess(
    transform: (T) -> ResultWithDiagnostics<R>
): ResultWithDiagnostics<List<R>>

Usage Examples:

import kotlin.script.experimental.api.*

// Creating successful results
val successResult = "Hello World".asSuccess()
val successWithWarnings = "Hello World".asSuccess(listOf(
    ScriptDiagnostic(
        message = "Deprecated API used",
        severity = ScriptDiagnostic.Severity.WARNING
    )
))

// Creating failure results
val failureResult = listOf(
    ScriptDiagnostic(
        code = 1001,
        message = "Compilation failed: unresolved reference",
        severity = ScriptDiagnostic.Severity.ERROR,
        location = SourceCode.Location(
            start = SourceCode.Position(line = 5, col = 10)
        )
    )
).asFailure()

// Handling results
when (val result = compileScript()) {
    is ResultWithDiagnostics.Success -> {
        val compiledScript = result.value
        println("Compilation successful: ${compiledScript.sourceLocationId}")
        
        // Handle warnings
        result.reports.filter { it.isWarning() }.forEach { warning ->
            println("Warning: ${warning.message}")
        }
    }
    is ResultWithDiagnostics.Failure -> {
        result.reports.forEach { diagnostic ->
            val location = diagnostic.location?.let { loc ->
                " at line ${loc.start.line}, column ${loc.start.col}"
            } ?: ""
            println("${diagnostic.severity}: ${diagnostic.message}$location")
        }
    }
}

Result Transformation

// Transform successful results
val originalResult: ResultWithDiagnostics<String> = "42".asSuccess()
val transformedResult: ResultWithDiagnostics<Int> = originalResult.map { it.toInt() }

// Chain operations with flatMap
val chainedResult = originalResult
    .flatMap { value ->
        if (value.isNotEmpty()) {
            value.toIntOrNull()?.asSuccess() ?: "Invalid number".asFailure()
        } else {
            "Empty value".asFailure()
        }
    }
    .map { number -> number * 2 }

// Using utility functions
val value = originalResult.valueOrNull() // "42" or null
val safeValue = originalResult.valueOr("default") // "42" or "default"

try {
    val requiredValue = originalResult.valueOrThrow() // "42" or throws exception
} catch (e: Exception) {
    println("Failed to get value: ${e.message}")
}

Error Creation Utilities

// Create diagnostic reports
fun createCompilationError(message: String, location: SourceCode.Location? = null): ScriptDiagnostic {
    return ScriptDiagnostic(
        code = 2000,
        message = message,
        severity = ScriptDiagnostic.Severity.ERROR,
        location = location
    )
}

fun createWarning(message: String): ScriptDiagnostic {
    return ScriptDiagnostic(
        message = message,
        severity = ScriptDiagnostic.Severity.WARNING
    )
}

// Helper extensions for creating results
fun <T> T.asSuccess(reports: List<ScriptDiagnostic> = emptyList()): ResultWithDiagnostics<T> {
    return ResultWithDiagnostics.Success(this, reports)
}

fun List<ScriptDiagnostic>.asFailure(): ResultWithDiagnostics<Nothing> {
    return ResultWithDiagnostics.Failure(this)
}

fun String.asFailure(): ResultWithDiagnostics<Nothing> {
    return listOf(ScriptDiagnostic(message = this)).asFailure()
}

// Usage
val result1 = "success".asSuccess()
val result2 = "Compilation failed".asFailure()
val result3 = listOf(
    createCompilationError("Missing import"),
    createWarning("Unused variable")
).asFailure()

Advanced Error Handling

// Collect multiple results
fun processMultipleScripts(scripts: List<SourceCode>): ResultWithDiagnostics<List<CompiledScript>> {
    val results = scripts.map { script -> 
        compileScript(script) // Returns ResultWithDiagnostics<CompiledScript>
    }
    
    // Collect all results - fails if any individual result fails
    return IterableResultsCollector<CompiledScript>().collect(results)
}

// Transform with success mapping
fun getScriptNames(scripts: List<SourceCode>): ResultWithDiagnostics<List<String>> {
    return scripts
        .map { compileScript(it) }
        .mapSuccess { compiledScript -> 
            compiledScript.sourceLocationId ?: "unknown"
        }
}

// Chain operations with error accumulation
fun processScriptPipeline(source: SourceCode): ResultWithDiagnostics<String> {
    return compileScript(source)
        .flatMap { compiled -> evaluateScript(compiled) }
        .flatMap { evaluated -> formatResult(evaluated) }
        .map { formatted -> "Result: $formatted" }
}

// Custom error handling
class ScriptProcessingException(
    message: String,
    val diagnostics: List<ScriptDiagnostic>,
    cause: Throwable? = null
) : Exception(message, cause)

fun handleScriptErrors(result: ResultWithDiagnostics<*>) {
    result.onFailure { diagnostics ->
        val errorMessages = diagnostics
            .filter { it.severity >= ScriptDiagnostic.Severity.ERROR }
            .map { it.message }
        
        if (errorMessages.isNotEmpty()) {
            throw ScriptProcessingException(
                message = "Script processing failed: ${errorMessages.joinToString("; ")}",
                diagnostics = diagnostics
            )
        }
    }
}

Diagnostic Filtering and Analysis

// Filter diagnostics by severity
fun filterErrors(diagnostics: List<ScriptDiagnostic>): List<ScriptDiagnostic> {
    return diagnostics.filter { it.severity >= ScriptDiagnostic.Severity.ERROR }
}

fun filterWarnings(diagnostics: List<ScriptDiagnostic>): List<ScriptDiagnostic> {
    return diagnostics.filter { it.severity == ScriptDiagnostic.Severity.WARNING }
}

// Diagnostic analysis
fun analyzeDiagnostics(diagnostics: List<ScriptDiagnostic>): DiagnosticSummary {
    return DiagnosticSummary(
        errorCount = diagnostics.count { it.isError() },
        warningCount = diagnostics.count { it.isWarning() },
        infoCount = diagnostics.count { it.isInfo() },
        hasErrors = diagnostics.any { it.isError() },
        mostSevere = diagnostics.maxByOrNull { it.severity.ordinal }?.severity
    )
}

data class DiagnosticSummary(
    val errorCount: Int,
    val warningCount: Int,
    val infoCount: Int,
    val hasErrors: Boolean,
    val mostSevere: ScriptDiagnostic.Severity?
)

Install with Tessl CLI

npx tessl i tessl/maven-org-jetbrains-kotlin--kotlin-scripting-common

docs

error-handling.md

host-integration.md

index.md

repl-system.md

script-annotations.md

script-compilation.md

script-evaluation.md

source-code.md

type-system.md

tile.json