OriLang LLM Writing Kit — Syntax Reference, Grammar, Operator Rules

Self-contained OriLang reference for AI models: the maintained syntax quick reference, the full EBNF grammar, and the operator rules in one document.

# OriLang

> Ori is a statically-typed, expression-based compiled programming language with Hindley-Milner type inference, value semantics, ARC memory management (no garbage collector, no borrow checker), capability-based effects, and first-class testing. It compiles to native binaries via LLVM. Ori is not in LLM training data — this file is the self-contained writing kit: the maintained syntax reference, the full grammar (EBNF), and the operator rules, in one fetch.

---

# Ori Syntax Quick Reference

> Condensed syntax and prelude reference for the Ori programming language, generated from the compiler team's maintained cheat sheet. The specification (https://raw.githubusercontent.com/upstat-io/ori-lang/master/docs/ori_lang/v2026/spec/) and grammar.ebnf are authoritative.

**Syntax family: Rust-like.** Statements terminate with `;` (including every `let` in a block); the closing `}` of an expression-bodied declaration or block-ending-statement is the only place `;` is omitted. Default to `;` — ML/Haskell/Gleam newline-as-terminator instincts do NOT apply.

## Declarations

**Functions**: `@name (p: T) -> R = expr;` | `@name (p: T) -> R = { ... }` (no `;`) | `pub @name` | `@name<T>` | `@name<T: Trait>` | `@name<T: A + B>` | `where T: Clone` | `uses Capability` | `(x: int = 10)` defaults
**Variadics**: `@sum (nums: ...int) -> int` | receives as `[T]` | call: `sum(1, 2, 3)` | spread: `sum(...list)` | trait objects: `...Printable` | empty calls need explicit type for generics
**Clauses**: `@f (0: int) -> int = 1` then `@f (n) = n * f(n-1)` | `if guard` | exhaustive, top-to-bottom
**Constants**: `let $name = value;` | `pub let $name` | module-level must be `$`
**Const Functions**: `$name (p: T) -> R = expr` — pure, comptime, limits: 1M steps/1000 depth/100MB/10s
**Types**: `type N = { f: T }` struct | `A | B | C(f: T)` sum | `type N = Existing` newtype | `type N<T>` | `#derive(Eq)` | `pub type`
**Newtypes**: `type UserId = int` | construct: `UserId(42)` | `.inner` (always public) | no trait/method inheritance | `#derive(Eq, Clone)` required | zero cost
**Traits**: `trait N { @m (self) -> T }` | `@m (self) -> T = default` | `type Item` assoc | `type Output = Self` default | `trait C: P` | `@m () -> Self` assoc fn | `trait N<T = Self>` default type param
**Impls**: `impl T { @m }` inherent | `impl T: Trait` | `impl<T: B> C<T>: Trait` | `self` (mutable in methods — mutations propagate to caller) / `Self`
**Method generics**: `impl<T> Box<T> { @map<U> (self, f: T -> U) -> Box<U> = ... }` | `<U: Bound>` bounded | `where U: Trait` clause | duplicate binder `<T, T>` rejected (`E1002`) | def-impl methods may not declare `uses` (stateless contract) | non-object-safe traits cannot include methods with `<...>` (object-safety §Object Safety)
**Associated Functions**: `impl T { @new () -> T }` — no `self` | call: `Type.method()` | `Self` in return | generics: `Option<int>.some(v:)`
**Default Impls**: `pub def impl Trait { @m }` — stateless, one per trait/module, auto-bound, override with `with`
**Extensions**: `extend Type { @m (self) -> T }` | `extend<T: Bound> [T]` | `extend T where T: Bound` | `pub extend` | no statics/fields/override
**Resolution**: Diamond=single impl; Inherent>Trait>Extension; qualified: `Trait.method(v)`, `Type::Trait::Assoc`; extensions: `module.Type.method(v)`
**Object Safety**: No `Self` return/param (except receiver), no generic methods; safe: `Printable`, `Debug`, `Hashable`; unsafe: `Clone`, `Eq`, `Iterator`
**Tests**: `@t tests @fn () -> void` | `@name tests _ () -> void` floating | `tests @a tests @b` multi | `#skip("r")` | `#compile_fail("e")` | `#fail("e")`

## Conditional Compilation

**Target**: `#target(os: "linux")` | `arch:` | `family:` | `any_os:` | `not_os:` | file-level: `#!target(...)`
**Config**: `#cfg(debug)` | `release` | `feature:` | `any_feature:` | `not_debug` | `not_feature:`
**Constants**: `$target_os`, `$target_arch`, `$target_family`, `$debug`, `$release` — false branch not type-checked

## Types

**Primitives**: `int` (i64), `float` (f64), `bool`, `str` (UTF-8), `char`, `byte`, `void`, `Never`
**Special**: `Duration` (`100ns`/`us`/`ms`/`s`/`m`/`h`), `Size` (`100b`/`kb`/`mb`/`gb`/`tb`)
**Collections**: `[T]` list, `[T, max N]` fixed-capacity, `{K: V}` map, `Set<T>`
**Compound**: `(T, U)` tuple (access: `.0`, `.1`), `()` unit, `(T) -> U` fn, `Trait` object, `impl Trait` existential
**Generic**: `Option<T>`, `Result<T, E>`, `Range<T>`, `Ordering`
**Const Generics**: `$N: int` | `@f<T, $N: int>` | `$B: bool` | `where N > 0` | `where N > 0 && N <= 100`
**Const Bounds**: comparison (`==`/`!=`/`<`/`<=`/`>`/`>=`), logical (`&&`/`||`/`!`), arithmetic (`+`/`-`/`*`/`/`/`%`), bitwise (`&`/`|`/`^`/`<<`/`>>`) | multiple `where` = AND
**Channels**: `Producer<T>`, `Consumer<T>`, `CloneableProducer<T>`, `CloneableConsumer<T>` (`T: Sendable`)
**Concurrency**: `Nursery`, `NurseryErrorMode` (`CancelRemaining | CollectAll | FailFast`)
**FFI**: `CPtr` (C opaque), `JsValue` (JS handle), `JsPromise<T>` (JS async)
**Rules**: No implicit conversions; overflow panics; `str[i]` → single-codepoint `str`

### Duration & Size

**Duration**: 64-bit nanoseconds; suffixes `ns`/`us`/`ms`/`s`/`m`/`h`; decimal syntax (`0.5s`=500ms, `1.5s`=1500ms)
**Size**: 64-bit bytes (non-negative); suffixes `b`/`kb`/`mb`/`gb`/`tb`; SI units (1000-based); decimal syntax (`1.5kb`=1500 bytes)
**Decimal literals**: Compile-time sugar using integer arithmetic (no floats); must result in whole base unit; `1.5ns`/`0.5b` = error
**Arithmetic**: `+`/`-`/`*`/`/`/`%`, unary `-` (Duration only; Size `-` panics if negative, unary `-` = compile error)
**Methods**: `.nanoseconds()`/`.microseconds()`/`.milliseconds()`/`.seconds()`/`.minutes()`/`.hours()` | `.bytes()`/`.kilobytes()`/`.megabytes()`/`.gigabytes()`/`.terabytes()` → `int`
**Factory**: `Duration.from_nanoseconds(ns:)`... | `Size.from_bytes(b:)`...
**Traits**: `Eq`, `Comparable`, `Hashable`, `Clone`, `Debug`, `Printable`, `Default` (`0ns`/`0b`), `Sendable`

### Never

Bottom type (uninhabited); coerces to any `T`
**Producers**: `panic(msg:)`, `todo()`, `unreachable()`, `break`, `continue`, `expr?` on Err/None, infinite `loop`
**Generics**: `Result<Never, E>` = always Err | `Result<T, Never>` = always Ok | `Option<Never>` = always None
**Restrictions**: Cannot be struct field; may be sum variant payload (unconstructable)

### Fixed-Capacity Lists

`[T, max N]` — inline-allocated, compile-time max N, dynamic length 0..N | `[T, max N] <: [T]`
**Methods**: `.capacity()`, `.is_full()`, `.remaining()`, `.push()` (panics), `.try_push()` → `bool`, `.push_or_drop()`, `.push_or_oldest()`, `.to_dynamic()`
**Conversion**: `.to_fixed<$N>()` panics | `.try_to_fixed<$N>()` → `Option`

### Existential Types (`impl Trait`)

`impl Trait where Assoc == Type` — opaque return type; concrete type hidden from callers
**Position**: return only | argument position: use generics instead
**Syntax**: `@f () -> impl Iterator where Item == int` | `impl A + B` multi-trait
**Where clause**: type-local (constraints on associated types, not type params)
**Dispatch**: static (monomorphized) — no vtable overhead
**Rules**: all return paths must yield same concrete type
**vs Trait objects**: `impl Trait` (static/single type) vs `Trait` (dynamic/any type at runtime)

## Literals

`42`, `1_000_000`, `0xFF`, `0b1010` | `3.14`, `2.5e-8` | `"hello"` (escapes: `\\\"\n\t\r\0\xHH\u{H}`) | `` `{name}` `` | `'a'`, `'\x41'` (escapes: `\\\'\n\t\r\0\xHH\u{H}`, `\xHH` restricted to `\x00`–`\x7F`) | `b'x'`, `b'\xFF'` (byte literal, escapes: `\\\'\n\t\r\0\xHH`, full `\x00`–`\xFF`, no `\u{}` or `\"`) | `true`/`false` | duration/size literals | `[1, 2]`, `[...a, ...b]` | `{key: v}`, `{"key": v}`, `{[expr]: v}`, `{...a, ...b}` | `Point { x, y }`, `{ ...p, x: 10 }`

## Operators (precedence high→low)

1. `.` `[]` `()` `?` `as` `as?` — 2. `**` (right) — 3. `!` `-` `~` — 4. `*` `/` `%` `div` `@` — 5. `+` `-` — 6. `<<` `>>` — 7. `..` `..=` (with optional `by` step modifier) — 8. `<` `>` `<=` `>=` — 9. `==` `!=` — 10. `&` — 11. `^` — 12. `|` — 13. `&&` — 14. `||` — 15. `??` (right) — 16. `|>` (pipe)

**Unary**: `!` (Not), `-` (Neg), `~` (BitNot) | **Bitwise**: `&`/`|`/`^` (BitAnd/Or/Xor), `<<`/`>>` (Shl/Shr)
**Shift overflow**: negative count panics; count ≥ bit width panics; `1 << 63` panics
**Operator traits**: desugar to trait methods; user types implement for operator support
**Compound assignment**: `x op= y` desugars to `x = x op y` (parser-level) | `+=` `-=` `*=` `/=` `%=` `**=` `@=` `&=` `|=` `^=` `<<=` `>>=` `&&=` `||=` | statement, not expression | target must be mutable (no `$`) | `&&=`/`||=` preserve short-circuit
**Pipe**: `x |> f(a: v)` fills single unspecified param | `x |> .method()` calls method on piped value | `x |> (a -> expr)` lambda fallback | prec 16 (lowest) | left-assoc | desugars to let-binding + call in type checker | "unspecified" = no value AND no default

## Expressions

**Conditionals**: `if c then e else e` | `if c then e` (void)
**Bindings**: `let x = v` mutable | `let $x` immutable | `let x: T` | shadowing OK | `let { x, y }` | `let { x: px }` | `let (a, b)` | `let [..t]` / `let [..$t]` rest-only (irrefutable) — refutable list shapes (`[a, b, c]`, `[head, ..tail]`, `[only]`) are illegal in `let` (E2001), bind via `match` (per 15-patterns.md)
**Indexing**: `list[0]`, `list[# - 1]` (`#`=length, panics OOB) | `map["k"]` → `Option<V>`
**Index/Field Assignment**: `list[i] = x` → `list = list.updated(key: i, value: x)` | `state.field = x` → `state = { ...state, field: x }` | mixed chains: `state.items[i] = x`, `list[i].name = x` | compound: `list[i] += 1` | root must be mutable (non-`$`)
**Access**: `v.field`, `v.0` (tuple), `v.method(arg: v)` — named args required except: fn variables, single-param with inline lambda
**Argument Punning**: `f(x:)` = `f(x: x)` when variable matches param name | `f(x:, y: 42)` mixed | trailing `:` distinguishes from positional `f(x)`
**Lambdas**: `x -> x + 1` | `(a, b) -> a + b` | `() -> 42` | `(x: int) -> x * 2` (typed param, inferred return) | `(x: int) -> int = x * 2` (explicit return) — capture by value
**Ranges**: `0..10` excl | `0..=10` incl | `0..10 by 2` | descending: `10..0 by -1` | infinite: `0..`, `0.. by -1` | int only
**Blocks**: `{ let $x = 1; x + 2 }` — `;` terminates statements, last expression (no `;`) is value | all `;` = void block | `ori fmt` enforces blank line before result | empty `{ }` = empty map
**Loops**: `while c do e` | `for i in items do e` | `for x in items yield x * 2` | `for x in items if g yield x` | nested `for` | `loop { body }` + `break`/`continue` | `break value` | `continue value`
**While**: `while condition do body` — sugar for `loop { if !condition then break; body }` | type: `void` | no `while...yield` | `break value` error (E0860) | `continue value` error (E0861)
**Loop body**: block expression; `loop { a \n b \n c }` for sequences | type: `void` (break no value), inferred (break value), `Never` (no break) | `continue value` error (E0861)
**Yield control**: `continue` skips | `continue value` substitutes | `break` stops | `break value` adds final | `{K: V}` from `(K, V)` tuples
**Labels**: `loop:name` | `for:name` | `while:name` | `block:name` | `break:name` | `continue:name` | no shadowing | `continue:name value` in yield → outer
**Labeled blocks**: `block:name { body }` — early exit via `break:name value` | type = unified exit paths | bare `break` is loop-only (not block) | `continue:block_label` = error | transparent to `break:loop_label`/`continue:loop_label`
**Spread**: `[...a, ...b]` | `{...a, ...b}` | `P { ...orig, x: 10 }` — later wins, literal contexts only | `fn(...list)` into variadic only

## Block expressions

**Semicolons**: Rust-style — `;` terminates statements; last expression (no `;`) is block value; all `;` = void block
**Semicolon rule**: Ends with `}`? No `;`. Everything else: `;`. Applies to `use`, `let $`, functions, types, methods.
**Blocks**: `{ let $x = 1; let $y = 2; x + y }` — `;` on statements, no `;` on result
**Match**: `match expr { P1 -> e1, P2 -> e2 }` — scrutinee before block, comma-separated arms (trailing comma optional)
**Try**: `try { let $x = f()?; Ok(x) }` — error-propagating block
**Contracts**: `pre(condition)` | `pre(condition | "message")` | `post(r -> condition)` — on function declaration, between signature and `=`
**function_exp**: `recurse(condition:, base:, step:, memo:, parallel:)` | `parallel(tasks:, max_concurrent:, timeout:)` → `[Result]` | `spawn(tasks:, max_concurrent:)` → `void` | `timeout(op:, after:)` | `cache(key:, op:, ttl:)` | `with(acquire:, action:, release:)` | `for(over:, match:, default:)` | `catch(expr:)` → `Result<T, str>` | `nursery(body:, on_error:, timeout:)`
**Channels**: `channel<T>(buffer:)` → `(Producer, Consumer)` | `channel_in` | `channel_out` | `channel_all`
**Conversions**: `42 as float` infallible | `"42" as? int` fallible → `Option`
**Match patterns**: literal | `x` | `_` | `Some(x)` | `{ x, y }` | `[a, ..rest]` | `1..10` | `A | B` | `x @ pat` | `x if guard` | variant punning: `Circle(radius:)` = `Circle(radius: radius)`, `Some(value:)` = `Some(value: value)`
**Exhaustiveness**: match exhaustive; guards need `_`; `let` patterns irrefutable

## Imports

**Relative**: `use "./math" { add };` | `"../utils"` | `"./http/client"`
**Module**: `use std.math { sqrt };` | `use std.net.http as http;`
**Private**: `use "./m" { ::internal };` | **Alias**: `{ add as plus }` | **Re-export**: `pub use`
**Without default**: `use "m" { Trait without def };` — import without `def impl`
**Extensions**: `extension std.iter.extensions { Iterator.count }` — method-level, no wildcards | `pub extension`

## FFI

**Native (C)**: `extern "c" from "lib" { @_sin (x: float) -> float as "sin" }` | `from` specifies library | `as` maps name
**JavaScript**: `extern "js" { @_sin (x: float) -> float as "Math.sin" }` | `extern "js" from "./utils.js"`
**C Variadics**: `extern "c" { @printf (fmt: CPtr, ...) -> c_int }` — untyped, requires `unsafe`, platform va_list ABI
**Types**: `CPtr` opaque | `Option<CPtr>` nullable | `JsValue` handle | `JsPromise<T>` async
**C Types**: `c_char`, `c_short`, `c_int`, `c_long`, `c_longlong`, `c_float`, `c_double`, `c_size`
**Layout**: `#repr("c")` C-compatible | `#repr("packed")` no padding | `#repr("transparent")` same as single field | `#repr("aligned", N)` minimum alignment (power of two) | struct types only; newtypes implicitly transparent
**Unsafe**: `unsafe { ptr_read(...) }` | **Capability**: `uses Unsafe` (marker, like `Suspend` — cannot be bound via `with...in`)
**Async WASM**: `JsPromise<T>` implicitly resolved at binding sites | **Compile Error**: `compile_error("msg")`

### Deep FFI (opt-in annotations on extern blocks)

**Error Protocols**: `extern "c" from "lib" #error(errno) { ... }` — block-level; `#error(none)` per-function opt-out
**Error Variants**: `#error(errno | nonzero | null | negative | success: N | none)` — auto-generates `Result<T, FfiError>`
**FfiError**: `use std.ffi { FfiError }` — `{ code: int, message: str, source: str }`
**Out Params**: `@f (name: str, db: out CPtr) -> c_int` — `out` params folded into return type
**Ownership**: `owned` / `borrowed` on params/returns | str returns default to `borrowed` (copy, don't free)
**Free**: `#free(fn)` on block or per-function — auto-generates `Drop` impl for `owned CPtr`
**[byte] Elision**: `[byte]` in extern generates adjacent `(ptr, len)` C args | `mut [byte]` generates `(ptr, &len)`
**Parametric FFI**: `uses FFI("sqlite3")` per-library | `uses FFI` shorthand for all | each `from "lib"` is distinct capability
**Mocking**: `with FFI("lib") = handler { fn: (...) -> T = ..., } in { ... }` — handler-based mock; stateless is sugar for `handler(state: ())`

## Capabilities

**Declare**: `@f (...) -> T uses Http = ...` | `uses FileSystem, Suspend`
**Provide**: `with Http = RealHttp { } in expr` | `with Http = mock, Cache = mock in expr`
**Stateful Handlers**: `with Cap = handler(state: init) { op: (s) -> (s', val), ... } in expr` — state replaces `self`; returns `(S, R)` tuple; frame-local mutable state; `with...in` returns body type only
**Handler Rules**: context-sensitive keyword; single state value (compose via structs); all trait methods required (defaults used if omitted); no `self`; errors E1204-E1207
**Resolution**: with...in > imported `def impl` > module-local `def impl`
**Suspend**: `uses Suspend` = may suspend; no `uses` = sync; concurrency via `parallel(...)`
**Standard**: `Http`, `FileSystem`, `Clock`, `Random`, `Crypto`, `Cache`, `Print` (default), `Logger`, `Env`, `Intrinsics`, `Suspend`, `FFI`
**Intrinsics**: Generic SIMD/bit ops; `Intrinsics.simd_add(a:, b:)` (monomorphized by `[T, max N]`), `count_ones(value:)`, `cpu_has_feature(feature:)`; comparisons return `Mask<$N>` (methods: `bits`, `any`, `all`, `count`, `first_set`; operators: `&`, `|`, `~`)
**Capsets**: `capset Net = Http, Dns, Tls` — transparent alias, expanded in `uses` before type checking; `@f uses Net` expands to `@f uses Http, Dns, Tls`; capsets can include other capsets; not a trait (no `impl`, no `with`, no `def impl`)

## Comments

`// comment` — own line only | Doc: `// Desc` | `// * name:` | `// ! Error:` | `// > expr -> result`

## Formatting

4 spaces, 100 char limit, trailing commas multi-line only | `;` terminates statements in blocks, `use`, `let $`, expression-bodied declarations; block body `}` = no `;` | Space around: binary ops, arrows, colons/commas, `pub`, all braces `{ }`, `as`/`by`/`|`/`with`/`+`, `=` in `<T = Self>`, `??`, compound `+=` | No space: parens/brackets, `.`/`..`/`?`/`...`, empty delimiters, before `;`, labels `:`, punning `name:` | Break at 100; blocks 4-space indent; blank line before result in setup+result blocks; `match`/`try`/`recurse`/`parallel`/`spawn`/`nursery` always stacked; `timeout`/`cache`/`catch` width-based | Params/args/generics/where/fields/variants one-per-line; chains break at `.method()` (all-or-nothing); binary break before op; `if...then` together, `else` newline; chained `else if` each on own line; `for...yield`/`do` inline if fits | File order: file attrs → imports (stdlib→relative, sorted alpha) → constants → user-ordered rest | Attrs canonical order: `#target`/`#cfg` → `#repr` → `#derive` → `#skip`/`#compile_fail`/`#fail` | Traits: assoc types → required methods → defaults | Impls: assoc types → methods in trait order | Parens always preserved; never removed by formatter

## Keywords

**Reserved (36)**: `as break continue def div do else extend extension extern false for if impl in let loop match Never pub self Self suspend tests then trait true type unsafe use uses void where while with yield`
**Reserved (future)**: `asm inline static union view` (reserved for future low-level features)
**Context-sensitive (type names, 5)**: `bool byte float int str`
**Context-sensitive (patterns, 9)**: `cache catch handler nursery parallel recurse spawn timeout try`
**Context-sensitive (blocks, 1)**: `block` (before `:` only — labeled block early exit)
**Context-sensitive (pattern args, 10)**: `body buffer default expr map on_error over pre post state`
**Context-sensitive (imports, 2)**: `from` (extern blocks), `without` (import items, before `def`)
**Context-sensitive (other, 3)**: `args` (@main params), `by` (after range), `max` (fixed-capacity lists)
**Context-sensitive (embed, 2)**: `embed` (file embedding), `has_embed` (file existence check)
**Built-in constructors (4)**: `channel channel_all channel_in channel_out`
**Built-in names**: `len is_empty is_some is_none is_ok is_err compare min max print panic todo unreachable dbg compile_error hash_combine repeat is_cancelled drop_early`

## Prelude

**Types**: `Option<T>` (`Some`/`None`), `Result<T, E>` (`Ok`/`Err`), `Error`, `TraceEntry`, `Ordering`, `PanicInfo`, `CancellationError`, `CancellationReason`, `FormatSpec`, `Alignment`, `Sign`, `FormatType`
**Traits**: `Eq`, `Comparable`, `Hashable`, `Printable`, `Formattable`, `Debug`, `Clone`, `Default`, `Drop`, `Len`, `IsEmpty`, `Iterator`, `DoubleEndedIterator`, `Iterable`, `Collect`, `Into`, `Traceable`, `Index`, `Sendable`, `Value`

**Built-ins**: `print(msg:)`, `len(collection:)`, `is_empty(collection:)`, `is_some/is_none(option:)`, `is_ok/is_err(result:)`, `panic(msg:)`→`Never`, `todo()`/`todo(reason:)`→`Never`, `unreachable()`/`unreachable(reason:)`→`Never`, `dbg(value:)`/`dbg(value:, label:)`→`T`, `compare(left:, right:)`→`Ordering`, `min/max(left:, right:)`, `hash_combine(seed:, value:)`→`int`, `repeat(value:)`→iter (`T: Clone`), `is_cancelled()`→`bool`, `compile_error(msg:)`, `drop_early(value:)`, `embed(path)`→type-driven (`str`/`[byte]`), `has_embed(path)`→`bool`
**Testing (`std.testing`, import required)**: `assert(cond:)`, `assert_eq(actual:, expected:)`, `assert_ne(actual:, unexpected:)`, `assert_some/none(opt:)`, `assert_ok/err(result:)`, `assert_panics(f:)`, `assert_panics_with(f:, msg:)`. Import with `use std.testing { assert, assert_eq }`.

**Option**: `.map(transform:)`, `.unwrap()`, `.unwrap_or(default:)`, `.expect(msg:)`, `.ok_or(err:)`, `.and_then(then:)`, `.flat_map(f:)`, `.or(alt:)`, `.filter(predicate:)`
**Result**: `.map(transform:)`, `.map_err(transform:)`, `.unwrap()`, `.unwrap_err()`, `.unwrap_or(default:)`, `.expect(msg:)`, `.expect_err(msg:)`, `.ok()`, `.err()`, `.and_then(then:)`, `.or_else(f:)`, `.trace()`→`str`, `.trace_entries()`→`[TraceEntry]`, `.has_trace()`
**Error**: `.trace()`, `.trace_entries()`, `.has_trace()`
**Ordering**: `Less | Equal | Greater` — `.is_less/equal/greater()`, `.is_less_or_equal/greater_or_equal()`, `.reverse()`, `.then(other:)`, `.then_with(f:)`; default `Equal`; order `Less < Equal < Greater`; impls Eq, Comparable, Clone, Debug, Printable, Hashable, Default

**Printable**: `@to_str (self) -> str` — required for `` `{x}` ``; all primitives impl
**Formattable**: `@format (self, spec: FormatSpec) -> str` — blanket for Printable; spec: `[[fill]align][sign][#][0][width][.precision][type]`; align `<>^`; sign `+ - `; types `bxXoeEf%`; `#` prefix; `0` pads
**Debug**: `@debug (self) -> str` — escaped strings, derivable | **Clone**: `@clone (self) -> Self` — all primitives/collections, derivable
**Iterator**: `type Item; @next (self) -> (Option<Self.Item>, Self)` — fused, copy elision, lazy
**DoubleEndedIterator**: `trait: Iterator { @next_back (self) -> (Option<Self.Item>, Self) }`
**Iterable**: `type Item; @iter (self) -> impl Iterator` | **Collect**: `@from_iter (iter: impl Iterator) -> Self`
**Iterator methods**: `.map`, `.filter`, `.fold`, `.find`, `.for_each`, `.collect`, `.count`, `.any`, `.all`, `.take`, `.skip`, `.enumerate`, `.zip`, `.chain`, `.flatten`, `.flat_map`, `.cycle`, `.join`
**DoubleEnded methods**: `.rev`, `.last`, `.rfind`, `.rfold`
**Infinite**: `repeat(value:)`, `(0..).iter()` — bound with `.take(count:)` before `.collect()`
**Into**: `@into (self) -> T` — lossless, explicit `.into()`, standard: str→Error, int→float, Set<T>→[T]; no identity/chaining
**Traceable**: `@with_trace`, `@trace`→`str`, `@trace_entries`→`[TraceEntry]`, `@has_trace`
**TraceEntry**: `{ function, file, line, column: int }` — `@` prefix; most recent first
**PanicInfo**: `{ message, location: TraceEntry, stack_trace: [TraceEntry], thread_id: Option<int> }`
**Drop**: `@drop (self) -> void` — refcount zero; not async; panic during unwind aborts
**Index**: `@index (self, key: Key) -> Value` — `x[k]`→`x.index(key: k)`; return `T`/`Option<T>`/`Result<T, E>`; `#` built-in only; multiple impls per type OK: `impl Index<int, V>` + `impl Index<str, V>` disambiguated by key type at compile time
**Eq**: `@equals (self, other: Self) -> bool` — reflexive/symmetric/transitive; derives `==`/`!=`
**Comparable**: `trait: Eq { @compare (self, other: Self) -> Ordering }` — total order; derives `<`/`<=`/`>`/`>=`; NaN > all; `None < Some`; `Ok < Err`
**Hashable**: `trait: Eq { @hash (self) -> int }` — `a == b` ⇒ same hash; +0.0/-0.0 same; use `hash_combine`
**Operator traits**: `Add`/`Sub`/`Mul`/`Div`/`FloorDiv`/`Rem`/`Pow<Rhs = Self>` — binary; `MatMul<Rhs = Self>` — matrix multiply (`@`); `Neg`/`Not`/`BitNot` — unary; `BitAnd`/`BitOr`/`BitXor<Rhs = Self>`, `Shl`/`Shr<Rhs = int>` — bitwise; `As<T>`/`TryAs<T>` — conversion (`as`/`as?`); all default `type Output = Self`
**Operator methods**: `add`/`subtract`/`multiply`/`divide`/`floor_divide`/`remainder`/`power` — arithmetic; `matrix_multiply` — matmul (`@`); `negate`/`not`/`bit_not` — unary; `bit_and`/`bit_or`/`bit_xor`/`shift_left`/`shift_right` — bitwise; `as`/`try_as` — conversion
**Sendable**: marker trait, auto-derived by compiler; all fields must be `Sendable`, no interior mutability, no non-Sendable captures; required for channel types `T: Sendable`; cannot be implemented manually
**Value**: `trait Value: Clone, Eq` — marker trait; inline storage, bitwise copy, no ARC, no Drop; all fields must be `Value`; cannot be implemented manually; auto-satisfies `Clone` + `Sendable`; warning >256 bytes, error >512 bytes; primitives (`int`/`float`/`bool`/`char`/`byte`/`void`/`Duration`/`Size`/`Ordering`) implicitly `Value`; `str`/`[T]`/`{K:V}`/`Set<T>` never `Value`; syntax: `type Point: Value, Eq = { x: float, y: float }`
**List methods**: `.map`/`.filter`/`.fold(initial:, op:)`/`.reduce(op:)`/`.find(where:)`/`.any(pred:)`/`.all(pred:)`/`.for_each(f:)`/`.flat_map(f:)`/`.flatten()`/`.first()`/`.last()`/`.get(index:)`/`.take(count:)`/`.take_while(pred:)`/`.skip(count:)`/`.skip_while(pred:)`/`.slice(start:, end:)`/`.chunk(size:)`/`.window(size:)`/`.enumerate()`/`.zip(other:)`/`.concat(other:)`/`.append(value:)`/`.prepend(value:)`/`.push(value:)`/`.pop()`/`.insert(index:, value:)`/`.remove(index:)`/`.set(index:, value:)`/`.reverse()`/`.sort()`/`.sort_by(cmp:)`/`.sort_stable()`/`.sorted()`/`.unique()`/`.partition(pred:)`/`.group_by(key:)`/`.count()`/`.min()`/`.max()`/`.min_by(key:)`/`.max_by(key:)`/`.sum()`/`.product()`/`.join(sep:)`/`.iter()`/`.contains(value:)`/`.len()`/`.length()`/`.is_empty()` (sort/min/max require `T: Comparable`; contains requires `T: Eq`)
**String methods**: `.split(sep:)`, `.trim()`/`.trim_start()`, `.substring(start:, end:)`/`.slice(start:, end:)`, `.to_lowercase()`, `.starts_with(prefix:)`, `.ends_with(suffix:)`, `.contains(substr:)`, `.last_index_of(substr:)`, `.replace(old:, new:)`, `.repeat(count:)`, `.pad_start(width:, fill:)`/`.pad_end(width:, fill:)`, `.concat(other:)`, `.chars()`/`.iter()`/`.lines()`, `.parse_int()`/`.parse_float()`→`Option<int|float>`, `.escape()`, `.len()`/`.length()`, `.is_empty()`, `.as_bytes()`→`[byte]` (zero-copy), `.to_bytes()`→`[byte]` (copy), `.byte_len()`→`int`
**Char methods**: `.is_alpha()`, `.is_digit()`, `.is_whitespace()`, `.is_uppercase()`, `.is_lowercase()`, `.is_ascii()`, `.to_lowercase()`, `.to_uppercase()`, `.to_byte()`→`byte`, `.to_int()`→`int`, `.to_str()`→`str`
**Byte methods**: `.is_ascii()`, `.is_ascii_alpha()`, `.is_ascii_digit()`, `.is_ascii_whitespace()`, `.to_char()`→`char`, `.to_int()`→`int`, `.to_str()`→`str`; arithmetic: `+`/`-`/`*`/`/`/`%` via `add`/`sub`/`mul`/`div`/`rem`; bitwise: `&`/`|`/`^`/`~`/`<<`/`>>` via `bit_and`/`bit_or`/`bit_xor`/`bit_not`/`shl`/`shr`
**Compile-Time Reflection**: `fields_of(T)`→`[$FieldMeta]`, `variants_of(T)`→`[$VariantMeta]`, `name_of(T)`→`str` — zero-cost intrinsics, no opt-in; `$FieldMeta { name: str, index: int }`, `$VariantMeta { name: str, index: int, fields: [$FieldMeta] }` — compiler-internal types; `$for field in fields_of(T) yield/do body` — compile-time expansion; `$if const_cond then expr else expr` — dead-branch elimination; `value.[field]` — splice access; `is_struct(T)`, `is_enum(T)`, `is_primitive(T)`, `is_collection(T)`, `is_option(T)`, `is_result(T)`, `is_tuple(T)` — type classification (accept type param or expression)

---

# Grammar (EBNF) — syntax single source of truth

```ebnf
// ============================================================================
// Ori Language Grammar
// Version: 2026
//
// This is the unified formal grammar for the Ori programming language.
// All productions are authoritative and take precedence over prose descriptions.
//
// Notation:
//   production = expression .     Production definition
//   "keyword"                     Literal token
//   |                             Alternation
//   [ ]                           Optional (0 or 1)
//   { }                           Repetition (0 or more)
//   ( )                           Grouping
//   /* comment */                 Informative note
//
// Cross-references to detailed explanations are provided in comments.
// ============================================================================


// ============================================================================
// LEXICAL GRAMMAR
// See: 06-source-code.md, 07-lexical-elements.md
// ============================================================================

// --- Characters ---
// See: 06-source-code.md § 6.1 Characters, § 6.1.2 Letters and digits

unicode_char  = /* any Unicode code point except NUL (U+0000) */ .
letter        = 'A' … 'Z' | 'a' … 'z' .
digit         = '0' … '9' .
hex_digit     = digit | 'A' … 'F' | 'a' … 'f' .
bin_digit     = '0' | '1' .
newline       = /* U+000A */ .
whitespace    = ' ' | '\t' | '\r' | newline .

// --- Tokens ---

token = identifier | keyword | literal | operator | delimiter .

// --- Comments ---
// See: 07-lexical-elements.md § 7.1 Comments

comment      = "//" { unicode_char - newline } newline .
doc_comment  = "//" [ " " ] [ doc_marker ] { unicode_char - newline } newline .
doc_marker   = "*" | "!" | ">" .
member_doc   = "//" " " "*" " " identifier ":" [ " " { unicode_char - newline } ] .
warning_doc  = "//" " " "!" " " { unicode_char - newline } .
example_doc  = "//" " " ">" " " { unicode_char - newline } .

// --- Identifiers ---
// See: 07-lexical-elements.md § 7.2 Identifiers

identifier = ( letter | "_" ) { letter | digit | "_" } .

// --- Keywords ---
// See: 07-lexical-elements.md § 7.3 Keywords
//
// Reserved (36): as, break, continue, def, div, do, else, extend, extension, extern,
//           false, for, if, impl, in, let, loop, match, Never, pub, self, Self, suspend,
//           tests, then, trait, true, type, unsafe, use, uses, void, where, while, with, yield
// Reserved (future, 5): asm, inline, static, union, view
// Context-sensitive (patterns, 9): cache, catch, handler, nursery, parallel, recurse, spawn,
//           timeout, try
// Context-sensitive (blocks, 1): block (before ":" only — labeled block early exit)
// Context-sensitive (pattern args, 10): body, buffer, default, expr, map, on_error, over,
//           pre, post, state
// Context-sensitive (imports, 2): from (extern blocks), without (import items, before "def")
// Context-sensitive (other, 3): args (@main params), by (after range), max (fixed-capacity lists)
// Context-sensitive (embed, 2): embed (file embedding), has_embed (file existence check)
// Context-sensitive (type names, 5): bool, byte, float, int, str
// Built-in constructors (4): channel, channel_all, channel_in, channel_out

// --- Operators ---
// See: 07-lexical-elements.md § 7.4 Operators

arith_op  = "+" | "-" | "*" | "/" | "%" | "div" | "**" .
comp_op   = "==" | "!=" | "<" | ">" | "<=" | ">=" .
logic_op  = "&&" | "||" | "!" .
bit_op    = "&" | "|" | "^" | "~" | "<<" | ">>" .
unary_op  = "!" | "-" | "~" .
other_op  = ".." | "..=" | "??" | "?" | "->" | "=>" | "|>" .

// --- Delimiters ---

delimiter = "(" | ")" | "[" | "]" | "{" | "}"
          | "," | ":" | "." | "@" | "$" | ";" .

// --- Literals ---
// See: 07-lexical-elements.md § 7.7 Literals

literal = int_literal | float_literal | string_literal | template_literal | char_literal
        | byte_literal | bool_literal | duration_literal | size_literal .

// Integer literals
// See: 07-lexical-elements.md § 7.7.1 Integer literals
int_literal    = decimal_lit | hex_lit | bin_lit .
decimal_lit    = "0" | non_zero_digit { [ "_" ] digit } .
non_zero_digit = "1" … "9" .
hex_lit        = "0" ( "x" | "X" ) hex_digit { [ "_" ] hex_digit } .
bin_lit        = "0" ( "b" | "B" ) bin_digit { [ "_" ] bin_digit } .

// Float literals
// See: 07-lexical-elements.md § 7.7.2 Float literals
float_literal   = decimal_digits "." decimal_digits [ exponent ]
                | decimal_digits exponent .
decimal_digits  = digit { [ "_" ] digit } .
exponent        = ( "e" | "E" ) [ "+" | "-" ] decimal_digits .

// String literals
// See: 07-lexical-elements.md § 7.7.3 String literals
string_literal  = '"' { string_char | escape_seq } '"' .
string_char     = unicode_char - ( '"' | '\' | newline ) .
escape_seq      = '\' ( '"' | '\' | 'n' | 't' | 'r' | '0' )
                | unicode_escape
                | hex_escape .
unicode_escape  = '\' 'u' '{' hex_digit { hex_digit } '}' .  /* 1-6 hex digits */
hex_escape      = '\' 'x' hex_digit hex_digit .               /* \x00-\xFF */

// Template string literals (with interpolation)
// See: 07-lexical-elements.md § 7.7.4 Template strings
template_literal = '`' { template_char | template_escape | unicode_escape | template_brace | interpolation } '`' .
template_char    = unicode_char - ( '`' | '\' | '{' | '}' ) .
template_escape  = '\' ( '`' | '\' | 'n' | 't' | 'r' | '0' ) .
template_brace   = "{{" | "}}" .
interpolation    = '{' expression [ ':' format_spec ] '}' .

// Format specifiers for template strings
// See: 07-properties-of-types.md § Format Spec Syntax
// Syntax: [[fill]align][sign][#][0][width][.precision][type]
format_spec      = [ [ fill ] align ] [ sign ] [ alt_form ] [ zero_pad ] [ width ] [ '.' precision ] [ format_type ] .
fill             = unicode_char - ( align | sign ) .
align            = '<' | '>' | '^' .
sign             = '+' | '-' | ' ' .
alt_form         = '#' .
zero_pad         = '0' .
width            = decimal_lit .
precision        = decimal_lit .
format_type      = 'b' | 'o' | 'x' | 'X' | 'e' | 'E' | 'f' | '%' .

// Character literals
// See: 07-lexical-elements.md § 7.7.5 Character literals
char_literal = "'" ( char_char | char_escape ) "'" .
char_char    = unicode_char - ( "'" | '\' | newline ) .
char_escape  = '\' ( "'" | '\' | 'n' | 't' | 'r' | '0' )
             | unicode_escape
             | char_hex_escape .
char_hex_escape = '\' 'x' hex_digit hex_digit .  /* \x00-\x7F only; \x80-\xFF is an error */

// Byte literals
// See: 07-lexical-elements.md § 7.7.6 Byte literals
byte_literal = "b'" ( byte_char | byte_escape ) "'" .
byte_char    = ascii_char - ( "'" | '\' ) .      /* U+0020-U+007E, excluding ' and \ */
byte_escape  = '\' ( "'" | '\' | 'n' | 't' | 'r' | '0' )
             | hex_escape .                       /* \x00-\xFF; no \u{} or \" */
ascii_char   = '\x20' … '\x7E' .                 /* printable ASCII */

// Boolean literals
bool_literal = "true" | "false" .

// Duration literals
// See: 07-lexical-elements.md § 7.7.8 Duration literals
// Decimal syntax (e.g., 0.5s) is compile-time sugar computed via integer arithmetic
duration_literal = duration_number duration_unit .
duration_number  = decimal_lit | decimal_lit "." digit { digit } .
duration_unit    = "ns" | "us" | "ms" | "s" | "m" | "h" .

// Size literals
// See: 07-lexical-elements.md § 7.7.9 Size literals
// Decimal syntax (e.g., 1.5kb) is compile-time sugar computed via integer arithmetic
size_literal = size_number size_unit .
size_number  = decimal_lit | decimal_lit "." digit { digit } .
size_unit    = "b" | "kb" | "mb" | "gb" | "tb" .


// ============================================================================
// SOURCE STRUCTURE
// See: 06-source-code.md, 18-modules.md
// ============================================================================

source_file = [ file_attribute ] { import | reexport | extension_import } { declaration } .

// File-level attribute (conditional compilation)
// See: 24-conditional-compilation.md § File-Level Conditions
file_attribute = "#!" identifier "(" [ attribute_arg { "," attribute_arg } ] ")" .

// --- Imports ---
// See: 12-modules.md § Imports

import      = "use" import_path [ import_list | "as" identifier ] ";" .
import_path = string_literal | identifier { "." identifier } .
import_list = "{" import_item { "," import_item } "}" .
import_item = [ "::" ] identifier [ "without" "def" ] [ "as" identifier ] | "$" identifier .

// --- Re-exports ---

reexport = "pub" "use" import_path import_list ";" .

// --- Extensions ---
// See: 12-modules.md § Extensions

extension_def    = "extend" [ generics ] type [ where_clause ] "{" { method } "}" .
extension_import = [ "pub" ] "extension" import_path "{" extension_item { "," extension_item } "}" .
extension_item   = identifier "." identifier .

// --- FFI (Foreign Function Interface) ---
// See: spec/24-ffi.md

extern_block  = [ "pub" ] "extern" string_literal [ "from" string_literal ]
                { block_attribute } "{" { extern_item } "}" .
extern_item   = "@" identifier extern_params "->" [ ownership ] type
                [ "as" string_literal ]
                { item_attribute } .
extern_params = "(" [ extern_param { "," extern_param } ] [ c_variadic ] ")" .
extern_param  = [ param_modifier ] identifier ":" [ ownership ] type .
c_variadic    = "," "..." .  /* C-style variadic - only valid in extern "c" blocks */

// Deep FFI annotations (see: proposals/approved/deep-ffi-proposal.md)
param_modifier  = "out" | "mut" .
ownership       = "owned" | "borrowed" .
block_attribute = "#" identifier "(" { attribute_arg } ")" .  /* #error(...), #free(...) */
item_attribute  = "#" identifier "(" { attribute_arg } ")" .  /* per-function overrides */

// Parametric FFI capability
ffi_capability  = "FFI" [ "(" string_literal ")" ] .


// ============================================================================
// DECLARATIONS
// See: 08-declarations.md
// ============================================================================

declaration = { attribute } [ "pub" ] ( function | type_def | trait_def | impl_block | extension_def | test | constant_decl | extern_block | capset_decl ) .

// --- Attributes ---
// See: 08-declarations.md § Attributes, 24-conditional-compilation.md
// Item-level: #derive(...), #skip(...), #target(...), #cfg(...)

attribute      = "#" identifier [ "(" [ attribute_arg { "," attribute_arg } ] ")" ] .
attribute_arg  = expression | identifier ":" expression | array_literal .
array_literal  = "[" [ string_literal { "," string_literal } ] "]" .

// --- Functions ---
// See: 08-declarations.md § Functions

function      = "@" identifier [ generics ] clause_params "->" type [ uses_clause ] [ where_clause ] [ guard_clause ] { contract } "=" expression [ ";" ] .
/* Semicolon rule: ";" is required when the body expression does not end with "}".
   When the body is a block_expr (ending with "}"), ";" is omitted — same as Rust's fn. */
clause_params = "(" [ clause_param { "," clause_param } ] ")" .
clause_param  = match_pattern [ ":" type ] [ "=" expression ] .  /* pattern with optional type and default */
guard_clause  = "if" expression .

// --- Generics ---
// See: 06-types.md § Const Generic Parameters

generics      = "<" generic_param { "," generic_param } ">" .
generic_param = type_param | const_param .
type_param    = identifier [ ":" bounds ] [ "=" type ] .
const_param   = "$" identifier ":" const_type [ "=" const_expr ] .
const_type    = "int" | "bool" .
bounds        = type_path { "+" type_path } .
where_clause  = "where" constraint { "," constraint } .
constraint    = type_constraint | const_constraint .
type_constraint = identifier ":" bounds .
const_constraint = const_bound_expr .

// Const bound expressions (for where clauses)
// See: 06-types.md § Const Bounds
const_bound_expr = const_or_expr .
const_or_expr    = const_and_expr { "||" const_and_expr } .
const_and_expr   = const_not_expr { "&&" const_not_expr } .
const_not_expr   = "!" const_not_expr | const_cmp_expr .
const_cmp_expr   = const_expr comparison_op const_expr
                 | "(" const_bound_expr ")" .
comparison_op    = ">" | "<" | ">=" | "<=" | "==" | "!=" .

// --- Capabilities ---
// See: 14-capabilities.md

uses_clause  = "uses" identifier { "," identifier } .
capset_decl  = "capset" identifier "=" identifier { "," identifier } ";" .

// --- Type Definitions ---
// See: 08-declarations.md § Types, 06-types.md § User-Defined Types

type_def    = "type" identifier [ generics ] [ where_clause ] "=" type_body [ ";" ] .
/* Semicolon rule: ";" required for sum types and newtypes (no "}"); omitted for struct types (end with "}") */
type_body   = struct_body | sum_body | type .
struct_body = "{" [ field { "," field } ] "}" .
sum_body    = variant { "|" variant } .
variant     = identifier [ "(" [ field { "," field } ] ")" ] .
field       = identifier ":" type .

// --- Traits ---
// See: 08-declarations.md § Traits

trait_def      = "trait" identifier [ generics ] [ ":" bounds ] "{" { trait_item } "}" .
trait_item     = method_sig | default_method | assoc_type .
method_sig     = "@" identifier params "->" type ";" .
default_method = "@" identifier params "->" type "=" expression [ ";" ] .
/* Semicolon rule: same as function — ";" required unless body ends with "}" */
assoc_type     = "type" identifier [ ":" bounds ] [ "=" type ] .
params         = "(" [ param { "," param } ] ")" .
param          = identifier ":" type | variadic_param .
variadic_param = identifier ":" "..." type .

// --- Implementations ---
// See: 08-declarations.md § Implementations

impl_block    = inherent_impl | trait_impl | def_impl .
inherent_impl = "impl" [ generics ] type_path [ where_clause ] "{" { method } "}" .
trait_impl    = "impl" [ generics ] type ":" type_path [ where_clause ] "{" { method } "}" .
def_impl      = "def" "impl" identifier "{" { def_impl_method } "}" .
method        = "@" identifier params "->" type [ uses_clause ] "=" expression [ ";" ] .
def_impl_method = "@" identifier params "->" type "=" expression [ ";" ] .  /* no self, no uses */
/* Semicolon rule: same as function — ";" required unless body ends with "}" */

// --- Tests ---
// See: 13-testing.md

test         = "@" identifier "tests" test_targets "()" "->" "void" "=" expression [ ";" ] .
/* Semicolon rule: same as function — ";" required unless body ends with "}" */
test_targets = "_" | test_target { "tests" test_target } .
test_target  = "@" identifier .

// --- Constants (Immutable Bindings) ---
// See: 04-constants.md

constant_decl = "let" "$" identifier [ ":" type ] "=" expression ";" .


// ============================================================================
// TYPES
// See: 06-types.md
// ============================================================================

type          = type_path [ type_args ]
              | trait_object_bounds            /* Printable + Hashable */
              | list_type | fixed_list_type | map_type | tuple_type | function_type
              | impl_trait_type .
type_path     = identifier { "." identifier } .

// --- Bounded Trait Objects ---
// See: 06-types.md § Bounded Trait Objects
// Multiple trait bounds as a type: `@store (item: Printable + Hashable) -> void`
trait_object_bounds = type_path "+" type_path { "+" type_path } .

// --- Existential Types (impl Trait) ---
// See: 06-types.md § Existential Types

impl_trait_type   = "impl" trait_bounds [ impl_where_clause ] .
trait_bounds      = type_path { "+" type_path } .
impl_where_clause = "where" assoc_constraint { "," assoc_constraint } .
assoc_constraint  = identifier "==" type .
type_args     = "<" type_or_const { "," type_or_const } ">" .
type_or_const = type | const_expr .
list_type     = "[" type "]" .
fixed_list_type = "[" type "," "max" const_expr "]" .
map_type      = "{" type ":" type "}" .
tuple_type    = "(" type { "," type } ")" | "()" .
function_type = "(" [ type { "," type } ] ")" "->" type .
/* const_expr is defined in § CONSTANT EXPRESSIONS below */


// ============================================================================
// EXPRESSIONS
// See: 09-expressions.md
// ============================================================================

expression = with_expr | let_expr | if_expr | for_expr | while_expr | loop_expr | labeled_block | lambda | break_expr | continue_expr | unsafe_expr | block_expr | match_expr | try_expr | binary_expr .

// --- Primary Expressions ---

primary       = literal | identifier | "self" | "Self"
              | "(" expression ")"
              | "#"                                   /* length in index context */
              | list_literal | map_literal | struct_literal
              | block_expr                            /* { expr \n expr \n result } */
              | match_expr                            /* match expr { arms } */
              | try_expr                              /* try { block_body } */
              | pattern_expr                          /* parallel, spawn, etc. */
              | unsafe_expr
              | embed_expr | has_embed_expr .

// --- Block Expression ---
// See: proposals/approved/block-expression-syntax.md
// Amended by: proposals/approved/optional-semicolon-after-block-expressions-proposal.md
// Semicolons terminate statements inside blocks. The last expression without ";"
// is the block's value. A block where every expression has ";" returns void.
// Semicolons are optional after expression statements whose last token is "}".

block_expr  = "{" { statement } [ expression ] "}" .
statement   = let_expr ";"
            | assignment ";"
            | block_ending_expression [ ";" ]
            | expression ";" .

// An expression whose last token is "}" — semicolon is optional when used as a statement.
// The rule is purely syntactic: check whether the last token is "}".
block_ending_expression = for_do_expr | while_do_expr | loop_expr | if_expr
                        | match_expr | unsafe_expr | labeled_block | block_expr .

// --- Labeled Block ---
// See: 16-control-flow.md § Labeled Blocks
// "block" is a context-sensitive keyword, recognized only before ":".
// break:label exits the block with a value; continue:label targeting a block is an error.

labeled_block = "block" label block_expr .

// --- Unsafe Expression ---
// See: spec/24-ffi.md § Unsafe Blocks

unsafe_expr = "unsafe" block_expr .

// --- Embed Expressions ---
// See: 11-built-in-functions.md § embed, § has_embed
// See: proposals/approved/embed-expression-proposal.md

embed_expr     = "embed" "(" expression ")" .
has_embed_expr = "has_embed" "(" expression ")" .

// List literals with spread support
// See: 09-expressions.md § Spread Operator
list_literal   = "[" [ list_element { "," list_element } ] "]" .
list_element   = "..." expression | expression .

// Map literals with spread support
// See: computed-map-keys-proposal.md for key semantics
map_literal    = "{" [ map_element { "," map_element } ] "}" .
map_element    = "..." expression | map_entry .
map_entry      = map_key ":" expression .
map_key        = "[" expression "]"       /* computed key: evaluates expression */
               | identifier               /* literal string key: "foo" from foo */
               | string_literal .         /* literal string key */

// Struct literals with spread support
struct_literal  = type_path "{" [ struct_element { "," struct_element } ] "}" .
struct_element  = "..." expression | field_init .
field_init      = identifier [ ":" expression ] .

// --- Postfix Expressions ---
// See: 09-expressions.md § Postfix Expressions

postfix_expr   = primary { postfix_op } .
postfix_op     = "." member_name [ call_args ]       /* field/method access */
               | "." match_method                    /* method-style match */
               | "[" expression "]"                  /* index access */
               | call_args                           /* function call */
               | "?"                                 /* error propagation */
               | "as" type                           /* infallible type conversion */
               | "as?" type .                        /* fallible type conversion */
member_name    = identifier | keyword | int_literal .  /* keywords/ints valid after "." (tuple: t.0) */
match_method   = "match" "(" match_arm { "," match_arm } ")" .
call_args      = "(" [ call_arg { "," call_arg } ] ")" .
call_arg       = named_arg | positional_arg | spread_arg .
named_arg      = identifier ":" [ expression ] .  /* punned when expression omitted: f(x:) = f(x: x) */
positional_arg = expression .
spread_arg     = "..." expression .  /* spread into variadic position only */

// --- Unary Expressions ---
// See: 09-expressions.md § Unary Expressions

unary_expr = [ "!" | "-" | "~" ] power_expr .

// --- Power Expression ---
// See: operator-rules.md § Power
// ** binds tighter than unary: -x ** 2 = -(x ** 2)

power_expr = postfix_expr [ "**" power_expr ] .  /* right-associative */

// --- Binary Expressions ---
// See: 09-expressions.md § Binary Expressions
// Precedence (lowest to highest): |>, ??, ||, &&, |, ^, &, ==, cmp, range, shift, add, mul, unary, power

binary_expr   = pipe_expr .
pipe_expr     = coalesce_expr { "|>" pipe_step } .
pipe_step     = "." member_name [ call_args ]    /* method on piped value */
              | postfix_expr [ call_args ]        /* function call with implicit fill */
              | lambda .                          /* expression-level operation */
coalesce_expr = or_expr [ "??" coalesce_expr ] .  /* right-associative */
or_expr       = and_expr { "||" and_expr } .
and_expr      = bit_or_expr { "&&" bit_or_expr } .
bit_or_expr   = bit_xor_expr { "|" bit_xor_expr } .
bit_xor_expr  = bit_and_expr { "^" bit_and_expr } .
bit_and_expr  = eq_expr { "&" eq_expr } .
eq_expr       = cmp_expr { ( "==" | "!=" ) cmp_expr } .
cmp_expr      = range_expr { ( "<" | ">" | "<=" | ">=" ) range_expr } .
range_expr    = shift_expr [ ( ".." | "..=" ) [ shift_expr ] [ "by" shift_expr ] ] .
shift_expr    = add_expr { ( "<<" | ">>" ) add_expr } .
add_expr      = mul_expr { ( "+" | "-" ) mul_expr } .
mul_expr      = unary_expr { ( "*" | "/" | "%" | "div" | "@" ) unary_expr } .

// --- With Expression ---
// See: 09-expressions.md § With Expression, 14-capabilities.md § Providing Capabilities

with_expr           = "with" capability_binding { "," capability_binding } "in" expression .
capability_binding  = identifier "=" ( handler_expr | expression ) .

// --- Handler Expression (Stateful Effect Handlers) ---
// See: 14-capabilities.md § Stateful Handlers, proposals/approved/stateful-mock-testing-proposal.md
// `handler` is context-sensitive: valid only in the expression position of a capability_binding.

handler_expr        = "handler" "(" "state" ":" expression ")" "{" handler_operations "}" .
handler_operations  = handler_operation { "," handler_operation } .
handler_operation   = identifier ":" expression .

// --- Let Binding ---
// See: 09-expressions.md § Let Binding, 05-variables.md

let_expr = "let" binding_pattern [ ":" type ] "=" expression .
assignment        = assignment_target "=" expression
                  | assignment_target compound_op expression .
assignment_target = identifier { "[" expression "]" | "." identifier } .
compound_op       = "+=" | "-=" | "*=" | "/=" | "%=" | "**=" | "@="
                  | "&=" | "|=" | "^=" | "<<=" | ">>="
                  | "&&=" | "||=" .
binding           = let_expr | assignment .  /* convenience grouping; not currently referenced */

// --- Conditional ---
// See: 09-expressions.md § Conditional

if_expr = "if" expression "then" expression
          { "else" "if" expression "then" expression }
          [ "else" expression ] .

// --- For Expression ---
// See: 09-expressions.md § For Expression, 19-control-flow.md § Labeled Loops

for_expr       = "for" [ label ] binding_pattern "in" expression [ "if" expression ] { for_clause } ( "do" | "yield" ) expression .
for_clause     = "for" binding_pattern "in" expression [ "if" expression ] .

// --- Loop Expression ---
// See: 09-expressions.md § Loop Expression, 19-control-flow.md § Labeled Loops

loop_expr = "loop" [ label ] block_expr .

// --- While Expression ---
// See: 16-control-flow.md § While Loop
// Desugars to: loop { if !condition then break; body }

while_expr = "while" [ label ] expression "do" expression .

// --- Labels ---
// See: 19-control-flow.md § Labeled Loops
label = ":" identifier .  /* no space around colon */

// --- Lambda ---
// See: 09-expressions.md § Lambda

lambda        = simple_lambda | typed_lambda .
simple_lambda = lambda_params "->" expression .
typed_lambda  = "(" [ typed_param { "," typed_param } ] ")" "->" type "=" expression .
lambda_params = identifier | "(" [ identifier { "," identifier } ] ")" .
typed_param   = identifier ":" type .

// --- Control Flow ---
// See: 19-control-flow.md

break_expr    = "break" [ label ] [ expression ] .
continue_expr = "continue" [ label ] [ expression ] .


// ============================================================================
// PATTERNS (COMPILER CONSTRUCTS)
// See: 10-patterns.md
// ============================================================================

// --- Pattern Categories ---

pattern_expr = function_exp | function_val | channel_expr | for_pattern | catch_expr | nursery_expr .
function_exp = pattern_name "(" pattern_arg { "," pattern_arg } ")" .
pattern_name = "recurse" | "parallel" | "spawn" | "timeout" | "cache" | "with" .  /* nursery has explicit nursery_expr */
pattern_arg  = identifier ":" expression .

// Type conversion patterns (call position only)
function_val = ( "int" | "float" | "str" | "byte" ) "(" expression ")" .

// --- Block-Based Expressions ---
// See: proposals/approved/block-expression-syntax.md

// match: Pattern matching with scrutinee before block
match_expr = "match" expression "{" match_arms "}" .
match_arms = [ match_arm { "," match_arm } [ "," ] ] .
match_arm  = match_pattern [ "if" expression ] "->" expression .

// try: Error-propagating block (returns early on Err)
try_expr = "try" block_expr .

// --- Function-Level Contracts ---
// See: proposals/approved/block-expression-syntax.md § Function-Level Contracts
// Contracts sit between the return type and the "=" in function declarations.

contract       = pre_contract | post_contract .
pre_contract   = "pre" "(" check_expr ")" .
post_contract  = "post" "(" postcheck_expr ")" .
check_expr     = expression [ "|" string_literal ] .
postcheck_expr = lambda_params "->" check_expr .

// for pattern: First-match iteration
// See: 10-patterns.md § for Pattern
for_pattern = "for" "(" for_pattern_args ")" .
for_pattern_args = "over" ":" expression "," "match" ":" match_pattern "->" expression "," "default" ":" expression
                 | "over" ":" expression "," "map" ":" expression "," "match" ":" match_pattern "->" expression "," "default" ":" expression .

// catch: Panic recovery
// See: 20-errors-and-panics.md § Catching Panics
catch_expr = "catch" "(" "expr" ":" expression ")" .

// nursery: Structured concurrency
// See: 10-patterns.md § Concurrency
nursery_expr = "nursery" "(" nursery_args ")" .
nursery_args = "body" ":" lambda "," "on_error" ":" expression [ "," "timeout" ":" expression ] .

// --- Channel Constructors ---
// See: 06-types.md § Channel Types
channel_expr = channel_constructor "(" "buffer" ":" expression ")" .
channel_constructor = "channel" [ type_args ] | "channel_in" [ type_args ] | "channel_out" [ type_args ] | "channel_all" [ type_args ] .

// --- Match Patterns ---
// See: 10-patterns.md § Match Patterns

match_pattern = literal_pattern
              | identifier_pattern
              | wildcard_pattern
              | variant_pattern
              | struct_pattern
              | tuple_pattern
              | list_pattern
              | range_pattern
              | or_pattern
              | at_pattern .

literal_pattern     = [ "-" ] int_literal | string_literal | char_literal | byte_literal | bool_literal .
identifier_pattern  = identifier .
wildcard_pattern    = "_" .
variant_pattern     = type_path [ "(" [ variant_field { "," variant_field } ] ")" ] .
variant_field       = identifier ":" [ match_pattern ]   /* named; punned if pattern omitted */
                    | match_pattern .                     /* positional */
struct_pattern      = [ type_path ] "{" [ field_pattern { "," field_pattern } ] [ ".." ] "}" .
field_pattern       = identifier [ ":" match_pattern ] .
tuple_pattern       = "(" [ match_pattern { "," match_pattern } ] ")" .
list_pattern        = "[" [ list_pattern_elems ] "]" .
list_pattern_elems  = match_pattern { "," match_pattern } [ "," ".." [ identifier ] ]
                    | ".." [ identifier ] .
range_pattern       = const_pattern ( ".." | "..=" ) const_pattern .
const_pattern       = literal_pattern | "$" identifier .
or_pattern          = match_pattern "|" match_pattern .
at_pattern          = identifier "@" match_pattern .

// --- Binding Patterns ---
// See: 05-variables.md § Destructuring
// The "$" prefix marks immutable bindings; without "$", bindings are mutable.

binding_pattern = [ "$" ] identifier
                | "_"
                | "{" [ field_binding { "," field_binding } ] "}"
                | "(" [ binding_pattern { "," binding_pattern } ] ")"
                | "[" [ binding_pattern { "," binding_pattern } [ ".." [ "$" ] identifier ] ] "]" .
field_binding   = [ "$" ] identifier [ ":" binding_pattern ] .


// ============================================================================
// CONSTANT EXPRESSIONS
// See: 04-constants.md, 21-constant-expressions.md
// ============================================================================

const_expr = literal
           | "$" identifier
           | const_expr ( arith_op | comp_op | "&&" | "||" | "&" | "|" | "^" | "<<" | ">>" ) const_expr
           | unary_op const_expr
           | "(" const_expr ")" .


// ============================================================================
// PROGRAM ENTRY
// See: 18-program-execution.md
// ============================================================================

main_function = "@main" main_params "->" main_return "=" expression [ ";" ] .
main_params   = "()" | "(" "args" ":" "[" "str" "]" ")" .
main_return   = "void" | "int" | "Never" .


// ============================================================================
// END OF GRAMMAR
// ============================================================================
```

---

---
title: "Operator Rules"
description: "Ori Language Specification — Operator typing and evaluation rules"
order: 101
section: "Annexes"
---

# Operator Rules

Formal typing and evaluation rules for Ori operators.

## Legend

```
NOTATION
────────
T, U, E         type variables
v, v1, v2       values
e, e1, e2       expressions
env             type environment
|-              "entails" (type judgment)
->              type-level transformation
=>              evaluation (reduces to)
─────           inference rule separator (premises above, conclusion below)
[cond]          side condition
x               type product (left x right)

TYPE RULES
──────────
    premise1    premise2
    ────────────────────    RULE-NAME
         conclusion

READ AS: "if premise1 and premise2 hold, then conclusion holds"

EVALUATION RULES
────────────────
pattern => result [condition]

READ AS: "pattern evaluates to result when condition holds"

ASSOCIATIVITY
─────────────
assoc=left      left-to-right grouping: a op b op c = (a op b) op c
assoc=right     right-to-left grouping: a op b op c = a op (b op c)

MAINTENANCE
───────────
- Add new operators: copy existing block, modify rules
- Modify behavior: update relevant => rules
- Type changes: update -> rules and inference rules
- Keep in sync with: grammar.ebnf, ori_types/src/infer/expr/operators.rs, ori_eval/src/interpreter/mod.rs
```

---

## Pipe `|>`

```
assoc=left
prec=16 (lowest binary)

TYPE RULES
──────────
    e1 : T    f : (P: T, ...) -> U    [P is single unspecified param of f]
    ─────────────────────────────────────────────────────────────────────    PIPE-FILL
                             e1 |> f(...) : U

    e1 : T    method : (self: T, ...) -> U
    ──────────────────────────────────────    PIPE-METHOD
              e1 |> .method(...) : U

    e1 : T    g : (T) -> U
    ────────────────────────    PIPE-LAMBDA
         e1 |> g : U

UNSPECIFIED PARAMETER
─────────────────────
A parameter is "unspecified" when:
  (a) not provided in the call arguments, AND
  (b) has no default value

Parameters with defaults are treated as filled for pipe resolution.

COMPILE ERRORS
──────────────
Zero unspecified params  => "all parameters already specified; nothing for pipe to fill"
2+ unspecified params    => "ambiguous pipe target; specify all parameters except one"

DESUGARING
──────────
e1 |> f(a: v)            => { let $__pipe = e1; f(<unspecified>: __pipe, a: v) }
e1 |> .method(a: v)      => { let $__pipe = e1; __pipe.method(a: v) }
e1 |> (x -> expr)        => { let $__pipe = e1; (x -> expr)(__pipe) }
e1 |> f(a: v)?           => { let $__pipe = e1; f(<unspecified>: __pipe, a: v)? }

LEFT-TO-RIGHT: a |> f |> g |> h = h(g(f(a)))
```

---

## Coalesce `??`

```
assoc=right
prec=15

TYPE RULES
──────────
e1 : Option<T>    e2 : T
────────────────────────    COALESCE-UNWRAP
      e1 ?? e2 : T

e1 : Option<T>    e2 : Option<T>
────────────────────────────────    COALESCE-CHAIN
      e1 ?? e2 : Option<T>

e1 : Result<T,E>    e2 : T
──────────────────────────    COALESCE-RESULT-UNWRAP
      e1 ?? e2 : T

e1 : Result<T,E>    e2 : Result<T,E>
────────────────────────────────────    COALESCE-RESULT-CHAIN
      e1 ?? e2 : Result<T,E>

e1 : Never    e2 : T    [Never unifies with Option<T>]
────────────────────────────────────────────────────    COALESCE-NEVER-LEFT
                  e1 ?? e2 : T

e1 : Option<T>    e2 : Never
────────────────────────────    COALESCE-NEVER-RIGHT
      e1 ?? e2 : T

EVALUATION
──────────
Some(v) ?? e2 => v         [type(e1) != type(e1 ?? e2)]
Some(v) ?? e2 => Some(v)   [type(e1) = type(e1 ?? e2)]
None ?? e2 => eval(e2)
Ok(v) ?? e2 => v           [type(e1) != type(e1 ?? e2)]
Ok(v) ?? e2 => Ok(v)       [type(e1) = type(e1 ?? e2)]
Err(_) ?? e2 => eval(e2)

SHORT-CIRCUIT: e2 not evaluated when e1 is Some/Ok
```

---

## Arithmetic `+` `-` `*` `/` `%` `div`

```
assoc=left
prec=4 (* / % div @), prec=5 (+ -)

TYPE RULES
──────────
e1 : int    e2 : int
────────────────────    ARITH-INT
    e1 op e2 : int

e1 : float    e2 : float
────────────────────────    ARITH-FLOAT
     e1 op e2 : float

e1 : str    e2 : str
────────────────────    CONCAT
    e1 + e2 : str

e1 : Duration    e2 : Duration
──────────────────────────────    DURATION-ADD-SUB
     e1 +|- e2 : Duration

e1 : Duration    e2 : int
─────────────────────────    DURATION-MUL-DIV
    e1 *|/ e2 : Duration

e1 : int    e2 : Duration
─────────────────────────    DURATION-MUL-REV
     e1 * e2 : Duration

e1 : Duration    e2 : Duration
──────────────────────────────    DURATION-MOD
      e1 % e2 : Duration

e1 : Size    e2 : Size
──────────────────────    SIZE-ADD-SUB
    e1 +|- e2 : Size

e1 : Size    e2 : int
─────────────────────    SIZE-MUL-DIV
    e1 *|/ e2 : Size

e1 : int    e2 : Size
─────────────────────    SIZE-MUL-REV
     e1 * e2 : Size

e1 : Size    e2 : Size
──────────────────────    SIZE-MOD
     e1 % e2 : Size

EVALUATION
──────────
n1 + n2 => sum           [overflow -> panic]
n1 - n2 => diff          [overflow -> panic]
n1 * n2 => product       [overflow -> panic]
n1 / n2 => quotient      [n2 = 0 -> panic, truncates toward zero]
n1 % n2 => remainder     [n2 = 0 -> panic]
n1 div n2 => floor_quot  [n2 = 0 -> panic, floor toward -inf]
s1 + s2 => concat
```

---

## Power `**`

```
assoc=right
prec=2 (tighter than unary, looser than postfix)

TYPE RULES
──────────
e1 : int    e2 : int
────────────────────    POW-INT
    e1 ** e2 : int

e1 : float    e2 : float
──────────────────────────    POW-FLOAT
     e1 ** e2 : float

e1 : float    e2 : int
─────────────────────────    POW-FLOAT-INT
     e1 ** e2 : float

e1 : int    e2 : float
─────────────────────────    POW-INT-FLOAT
     e1 ** e2 : float

EVALUATION
──────────
n1 ** n2 => int_power    [n1 : int, n2 : int, n2 >= 0]
n1 ** n2 => panic        [n1 : int, n2 : int, n2 < 0, "negative exponent on integer"]
n1 ** 0 => 1             [for all n1, including 0 ** 0]
f1 ** f2 => libm_pow     [delegates to libm pow()]

OVERFLOW
────────
int ** int follows standard overflow behavior (panic in debug)

TRAIT DISPATCH
──────────────
** -> Pow -> power(self, rhs:)
```

---

## Comparison `==` `!=` `<` `<=` `>` `>=`

```
assoc=left
prec=8 (< <= > >=), prec=9 (== !=)

TYPE RULES
──────────
e1 : T    e2 : T    T : Eq
──────────────────────────    EQ
     e1 ==|!= e2 : bool

e1 : T    e2 : T    T : Comparable
──────────────────────────────────    ORD
      e1 <|<=|>|>= e2 : bool

EVALUATION
──────────
v == v => true
v1 == v2 => false        [v1 != v2]
v != v => false
v1 != v2 => true         [v1 != v2]
v1 < v2 => compare(v1, v2) = Less
v1 <= v2 => compare(v1, v2) != Greater
v1 > v2 => compare(v1, v2) = Greater
v1 >= v2 => compare(v1, v2) != Less
```

---

## Logical `&&` `||`

```
assoc=left
prec=13 (&&), prec=14 (||)

TYPE RULES
──────────
e1 : bool    e2 : bool
──────────────────────    AND
     e1 && e2 : bool

e1 : bool    e2 : bool
──────────────────────    OR
     e1 || e2 : bool

EVALUATION
──────────
false && e2 => false     [e2 not evaluated]
true && e2 => eval(e2)
true || e2 => true       [e2 not evaluated]
false || e2 => eval(e2)
```

---

## Bitwise `&` `|` `^` `<<` `>>`

```
assoc=left
prec=10 (&), prec=11 (^), prec=12 (|), prec=6 (<< >>)

TYPE RULES
──────────
e1 : int    e2 : int
────────────────────────    BITWISE-INT
  e1 &|^|<<|>> e2 : int

e1 : byte    e2 : byte
──────────────────────────    BITWISE-BYTE
    e1 &|^ e2 : byte

e1 : byte    e2 : int
─────────────────────────    SHIFT-BYTE
   e1 <<|>> e2 : byte

EVALUATION
──────────
n1 & n2 => bitwise_and
n1 | n2 => bitwise_or
n1 ^ n2 => bitwise_xor
n1 << n2 => shift_left   [n2 < 0 -> panic, n2 >= width -> panic]
n1 >> n2 => shift_right  [n2 < 0 -> panic, n2 >= width -> panic]

CONSTRAINTS
───────────
int width = 64 bits (valid shift: 0..63)
byte width = 8 bits (valid shift: 0..7)
```

---

## Range `..` `..=`

```
assoc=left
prec=7

TYPE RULES
──────────
e1 : int    e2 : int
────────────────────────    RANGE
   e1 ..|..= e2 : Range<int>

e1 : int
────────────────────    RANGE-OPEN
  e1 .. : Range<int>

e1 : int    e2 : int    e3 : int
────────────────────────────────    RANGE-STEP
   e1 ..|..= e2 by e3 : Range<int>
```

---

## Unary `-` `!` `~`

```
prec=3 (between power and multiplicative)

TYPE RULES
──────────
e : int
───────────    NEG-INT
  -e : int

e : float
─────────────    NEG-FLOAT
  -e : float

e : Duration
────────────────    NEG-DURATION
  -e : Duration

e : bool
────────────    NOT
  !e : bool

e : int
───────────    BITNOT-INT
  ~e : int

e : byte
────────────    BITNOT-BYTE
  ~e : byte

CONSTRAINTS
───────────
-Size -> compile error (Size cannot be negative)
```

---

## Type Conversion `as` `as?`

```
prec=1 (postfix)

TYPE RULES
──────────
e : T    T converts to U (infallible)
──────────────────────────────────────    AS-INFALLIBLE
            e as U : U

e : T    T converts to U (fallible)
────────────────────────────────────    AS-FALLIBLE
         e as? U : Option<U>

INFALLIBLE CONVERSIONS
──────────────────────
int -> float
byte -> int
char -> int

FALLIBLE CONVERSIONS
────────────────────
str -> int      (parse)
str -> float    (parse)
int -> byte     (range check)
float -> int    (truncate, range check)
```

---

## Try `?`

```
prec=1 (postfix)

TYPE RULES
──────────
e : Option<T>    enclosing returns Option<U>
────────────────────────────────────────────    TRY-OPTION
                   e? : T

e : Result<T,E>    enclosing returns Result<U,E>
────────────────────────────────────────────────    TRY-RESULT
                    e? : T

EVALUATION
──────────
Some(v)? => v
None? => return None
Ok(v)? => v
Err(e)? => return Err(e)
```

---

## Never

```
UNIFICATION
───────────
unify(Never, T) = Ok    for all T
unify(T, Never) = Ok    for all T

COERCION
────────
e : Never
─────────    NEVER-COERCE
  e : T      for all T

SOURCES
───────
panic(msg:) : Never
todo() : Never
todo(reason:) : Never
unreachable() : Never
unreachable(reason:) : Never
break : Never               [in loop]
continue : Never            [in loop]
loop { e } : Never          [no break in e]
e? : Never                  [early return path when e is None/Err]
```

---

## Precedence Table

```
PREC  OPERATORS              ASSOC   DESCRIPTION
────  ─────────              ─────   ───────────
1     . [] () ? as as?       left    postfix
2     **                     right   power
3     ! - ~                  right   unary
4     * / % div @            left    multiplicative
5     + -                    left    additive
6     << >>                  left    shift
7     .. ..= [by]            left    range (by is step modifier)
8     < > <= >=              left    comparison
9     == !=                  left    equality
10    &                      left    bitwise and
11    ^                      left    bitwise xor
12    |                      left    bitwise or
13    &&                     left    logical and
14    ||                     left    logical or
15    ??                     RIGHT   coalesce
```

---

## Trait Dispatch

```
OPERATOR -> TRAIT -> METHOD
───────────────────────────
+    -> Add      -> add(self, other:)
-    -> Sub      -> subtract(self, other:)
*    -> Mul      -> multiply(self, other:)
/    -> Div      -> divide(self, other:)
div  -> FloorDiv -> floor_divide(self, other:)
%    -> Rem      -> remainder(self, other:)
**   -> Pow      -> power(self, rhs:)
@    -> MatMul   -> matrix_multiply(self, rhs:)
-    -> Neg      -> negate(self)
!    -> Not      -> not(self)
~    -> BitNot   -> bit_not(self)
&    -> BitAnd   -> bit_and(self, other:)
|    -> BitOr    -> bit_or(self, other:)
^    -> BitXor   -> bit_xor(self, other:)
<<   -> Shl      -> shift_left(self, rhs:)
>>   -> Shr      -> shift_right(self, rhs:)
==   -> Eq       -> equals(self, other:)
<    -> Comparable -> compare(self, other:)

RESOLUTION ORDER
────────────────
1. Primitive type -> direct evaluation
2. User type -> trait method lookup
```

---

## Compound Assignment

```
DESUGARING
──────────
x op= y  =>  x = x op y    [parser-level rewrite]

SUPPORTED OPERATORS (TRAIT-BASED)
─────────────────────────────────
+=   desugars via  Add
-=   desugars via  Sub
*=   desugars via  Mul
/=   desugars via  Div
%=   desugars via  Rem
**=  desugars via  Pow
@=   desugars via  MatMul
&=   desugars via  BitAnd
|=   desugars via  BitOr
^=   desugars via  BitXor
<<=  desugars via  Shl
>>=  desugars via  Shr

SUPPORTED OPERATORS (LOGICAL)
─────────────────────────────
&&=  desugars to  x = x && y    [bool-only, short-circuit preserved]
||=  desugars to  x = x || y    [bool-only, short-circuit preserved]

CONSTRAINTS
───────────
- Left-hand side shall be a mutable binding (no `$` prefix)
- Compound assignment is a statement, not an expression
- Target expression is duplicated in AST (pure: no side effects)
```

---

## Deeper material

- [llms-reference.txt](https://ori-lang.com/llms-reference.txt): link catalog — every spec clause, guide chapter, curated example program, and standard-library source
- [llms-full.txt](https://ori-lang.com/llms-full.txt): the complete specification, grammar, and example programs inlined into a single document
- [GitHub repository](https://github.com/upstat-io/ori-lang) | [Playground](https://ori-lang.com/playground) | [Roadmap](https://ori-lang.com/roadmap/)
- Specification source: https://raw.githubusercontent.com/upstat-io/ori-lang/master/docs/ori_lang/v2026/spec/