zpl_toolchain_diagnostics 0.1.6

Diagnostic codes and structured error reporting for the ZPL toolchain
Documentation
# Examples

## Emit a diagnostic (recommended: use `codes::` constants)
```rust
use zpl_toolchain_diagnostics::{Diagnostic, codes};

// Preferred: use compile-time constants for typo detection and IDE autocomplete
let d = Diagnostic::error(codes::ARITY, "too many arguments", None);
println!("{}: {}", d.id, d.message);

// With a span:
use zpl_toolchain_diagnostics::Span;
let d = Diagnostic::warn(codes::REDUNDANT_STATE, "redundant state override", Some(Span::new(10, 25)));
```

## Emit a diagnostic (string literals — discouraged)
```rust
use zpl_toolchain_diagnostics::Diagnostic;

// Works, but prefer codes:: constants to catch typos at compile time:
let d = Diagnostic::error("ZPL1101", "too many arguments", None);
```

## Display formatting
```rust
use zpl_toolchain_diagnostics::{Diagnostic, codes};

let d = Diagnostic::error(codes::ARITY, "too many arguments", None);
println!("{}", d);  // "error[ZPL1101]: too many arguments"
```

## Explain a diagnostic
```rust
use zpl_toolchain_diagnostics::{Diagnostic, codes};

// From a Diagnostic instance (convenience method):
let d = Diagnostic::error(codes::ARITY, "too many arguments", None);
if let Some(desc) = d.explain() {
    println!("  help: {}", desc);
}

// Or via the free function:
let desc = zpl_toolchain_diagnostics::explain(codes::PROFILE_CONSTRAINT).unwrap_or("(no explanation)");
println!("{} => {}", codes::PROFILE_CONSTRAINT, desc);
```