Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/elfrask/cls/llms.txt

Use this file to discover all available pages before exploring further.

CLS never shows a bare error message and stops. Every error produced at runtime or during parsing comes with a full traceback: the chain of imports that led to the failing file, the numbered call stack with one source-context line per frame, and a caret pointing at the exact column where the error occurred. This is not optional — the rule is enforced at the architecture level: the interpreter only exposes format_error (which always renders the full report), not a raw message getter.

ClsError Variants

All errors in CLS are variants of ClsError, defined in cls-core/src/error/mod.rs:
#[derive(Error, Debug)]
pub enum ClsError {
    #[error("Error de compilación: {0}")]
    CompileError(String),

    #[error("Error de runtime: {0}")]
    RuntimeError(String),

    #[error("Error de tipo: {0}")]
    TypeError(String),

    #[error("Error de sintaxis: {0}")]
    SyntaxError(String),

    #[error("Error de sintaxis: {0}")]
    SyntaxErrorAt(String, Span),

    #[error("Error de IO: {0}")]
    IoError(#[from] std::io::Error),

    #[error("Error de configuración: {0}")]
    ConfigError(String),
}
VariantWhen used
SyntaxError(String)Legacy variant; span is embedded in the message text as (línea N, columna M). Kept for backward compatibility.
SyntaxErrorAt(String, Span)Modern structured variant. Message is clean; the Span carries start_line, start_col, end_line, end_col separately.
RuntimeError(String)Error thrown during tree-walking interpretation (division by zero, undefined variable, etc.).
TypeError(String)Type mismatch detected by the interpreter or type checker.
CompileError(String)Error emitted during compilation or code generation phases.
IoError(std::io::Error)File read/write failure; automatically converted from std::io::Error via #[from].
ConfigError(String)Invalid or missing project configuration.
ClsResult<T> is a type alias for Result<T, ClsError> used throughout cls-core and cls-runtime.

Syntax Error Factory

New syntax errors should always be created via the centralised factory:
ClsError::syntax_at("message", &span)   // → SyntaxErrorAt(message, span)
// Alias:
ClsError::with_span("message", &span)   // identical behaviour
Both methods create a SyntaxErrorAt with a clean message — no location embedded in the string. The Span carries the position so the formatter can render it uniformly regardless of the output format. The legacy extract_line_col helper is only used as a fallback to parse (línea N, columna M) out of pre-existing RuntimeError strings. It is not a public API to reach for in new code.

ErrorReport — The Full Context Object

The formatter never operates on a bare ClsError. It always receives an ErrorReport:
pub struct ErrorReport {
    pub error: ClsError,
    pub span: Option<Span>,
    pub stack: Vec<StackFrame>,
    pub import_trace: Vec<ImportFrame>,
    pub source_file: String,
    pub source: Option<String>,   // in-memory source, avoids re-reading file
}
There are three constructors:
ConstructorUse case
ErrorReport::from_runtime(error, stack, import_trace, source_file)Runtime errors from the interpreter
ErrorReport::from_syntax(error, source, source_file)Parse/lex errors where the source string is already in memory
ErrorReport::from_config(error)Configuration errors with no file context
Each StackFrame holds a function name, an optional Span, and the source file path. Each ImportFrame holds the module name, file, and the line/col of the import statement.

ErrorFormat — Output Formats

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ErrorFormat {
    Plain,    // plain text, no decorators
    Console,  // ANSI colour codes for terminal output
    Html,     // HTML string wrapped in <pre class="cls-error">
    Json,     // structured JSON (for tooling / machines)
}

Plain

Human-readable text with no terminal escape codes. Suitable for log files and CI output where ANSI is not rendered.

Console

ANSI-coloured output using codes from cls_core::ansi. Frame numbers in cyan, arrows in yellow, error labels in magenta, carets in red.

Html

Output wrapped in <pre class="cls-error">. Inline style attributes carry colours matching the Console palette. Suitable for web playgrounds.

Json

Fully structured JSON containing error, message, file, span, stack, and imports arrays. Designed for editor integrations and language servers.

API Functions

// Core entry point — the node chooses format and where to print
pub fn format_error(report: &ErrorReport, format: &ErrorFormat) -> String

// Typed wrappers (delegate to format_error)
pub fn format_runtime_error(report: &ErrorReport, format: &ErrorFormat) -> String
pub fn format_syntax_error(
    error: ClsError,
    source: &str,
    source_file: &str,
    format: &ErrorFormat,
) -> String

// Compatibility helpers — print to stderr in Console format
pub fn show_runtime_error(report: &ErrorReport)
pub fn show_syntax_error(error: ClsError, source: &str, source_file: &str)
Prefer format_error when you control where output goes (e.g., writing to a log, sending over a socket, or capturing for tests). The show_* helpers are convenience wrappers that always print to stderr in Console format.

Runtime Traceback Format

When a runtime error occurs, format_error with ErrorFormat::Console (or Plain) renders this structure:
Error de ejecución:

1. → main (main.clsx)
2. En main.clsx:10:20 → outer
  10 |     return inner(y);
     |                    ^
3. En main.clsx:2:17 [Runtime Error]
  2 |     return x / 0;
    |                 ^
  Error: División por cero
The format rules are:
  • Line 1: header — Error de ejecución: for runtime errors, Error en 'file': for syntax errors.
  • Numbered frames: one per entry, in order: import chain first, then call stack, then the error site.
    • Import frame: N. En file:line:col
    • Call frame with location: N. En file:line:col → functionName
    • Call frame without location: N. → functionName (file)
    • Error frame: N. En file:line:col [Error Label]
  • Source context: immediately below the frame header, if the source line is available:
      <line> | <source text>
      <pad>  | <caret>
    
    The caret (^) is aligned to the column, accounting for tab expansion (tabs count as 4 spaces).
  • Final line: Error: <clean message> — the message with the Error de X: prefix stripped.
The call stack is not popped when an error propagates — it is preserved intact so the full traceback can be rendered. A try/catch block restores the stack depth after catching.

Type Checker Output Format (clx check)

The type checker produces Diagnostic values with [ERROR] or [WARN] severity. The output format is single-level — no import trace, no call stack:
[ERROR] Operador + no soportado entre String y Int (2:38)
  2 |     return "Hello, " + name + "!" + 2;
    |                                      ^
  • [ERROR] is rendered in red; [WARN] in yellow; a clean pass prints a green success message.
  • The (line:col) position appears in grey next to the message.
  • The caret is coloured to match the severity.
The clx check diagnostic format is intentionally minimal. Do not use format_runtime_error for type-checker output — it would emit a misleading “Error de ejecución:” header and a spurious numbered call stack.

Rules by Context

  • Shows single-level diagnostics only: file:line:col + source line + caret.
  • No import trace.
  • No numbered call stack.
  • Severity prefix: [ERROR] (red) or [WARN] (yellow).
  • A file with no errors prints a green “OK” line.
The full traceback is mandatory. These rules are enforced:
  1. Always include the import trace (even if empty — the outer frame is still printed).
  2. Always include the numbered call stack with one source-context block per frame.
  3. Always include the error site frame with caret.
  4. Never show only the error message.
Using only show_runtime_error (which calls format_error internally with the full ErrorReport) is sufficient to comply.

JSON Error Structure

ErrorFormat::Json produces a JSON object suitable for editor integrations:
{
  "error": "RuntimeError(\"División por cero\")",
  "message": "División por cero",
  "file": "main.clsx",
  "span": {
    "line": 2,
    "col": 17,
    "end_line": 2,
    "end_col": 17
  },
  "stack": [
    { "function": "outer", "file": "main.clsx", "span": { "line": 10, "col": 20 } },
    { "function": "inner", "file": "main.clsx", "span": { "line": 2, "col": 17 } }
  ],
  "imports": []
}
The error field contains the Debug representation of the ClsError variant. message contains only the clean user-facing message (prefix stripped).

In-Language Error Handling

CLS exposes throw and try/catch/finally directly in the language:
// Throwing an error
throw("Something went wrong");

// Catching an error
try {
    let result = riskyOperation();
} catch (e) {
    // e is a String — the error message
    print("Caught: " + e);
} finally {
    // always runs, whether or not an error was thrown
    cleanup();
}
The caught value e is a String containing the error message. The call stack depth is restored to the level it was at before the try block when the catch clause runs — frames pushed inside the try block are discarded from the stack (but were used to build the traceback before the catch occurred).
// Rethrowing
try {
    parse(input);
} catch (e) {
    if (!e.contains("expected")) {
        throw(e);   // rethrow if it's not a parse error
    }
}

Build docs developers (and LLMs) love