# 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/