Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Grammar

The Nazm grammar in EBNF, as committed in docs/grammar.ebnf.

(* The Nazm grammar.
 *
 * This file is an artefact, not a description: `crates/nazm-syntax/tests/grammar.rs`
 * reads it and checks three things against the real implementation.
 *
 *   1. Every terminal written here is a real token, and every token the lexer has is
 *      written here. A keyword added to the lexer and not to the grammar fails the test.
 *   2. Every nonterminal referenced is defined, and every nonterminal defined is
 *      reachable from `program`. A rule nobody uses is a rule nobody maintains.
 *   3. Every rule carries at least one `@example`, and every example is fed to the real
 *      parser and must parse with no diagnostics. A grammar whose examples the parser
 *      rejects is describing a language that does not exist.
 *
 * What the test does *not* do is prove the parser accepts exactly this language. That
 * would need a generated parser, and this one is written by hand — deliberately, for the
 * diagnostics. So: the terminals are exact, the examples are executable, and the
 * structure is a claim checked by review. `docs/guide.md` is generated from this file.
 *
 * Notation: `=` defines, `|` alternates, `{ x }` is zero or more, `[ x ]` is optional,
 * `( )` groups, quoted text is a terminal, UPPERCASE is a token class.
 *)

(* @example fn main() -> Int { 0 } *)
(* @example use "other.nz"; fn main() -> Int { 0 } *)
(* @example struct Point { x: Int, } fn main() -> Int { Point(x: 1).x } *)
(* @example enum State { Ready, } fn main() -> Int { match State.Ready() { State.Ready() => 0, } } *)
(* @example fn identity[T](value: T) -> T { value } fn main() -> Int { identity(7) } *)
(* @example trait Show { fn show(self: Self) -> Str; } impl Show for Int { fn show(self: Int) -> Str { int_to_str(self) } } fn main() -> Int { str_len(7.show()) } *)
(* @example const SIZE: Int = 4; fn main() -> Int { SIZE } *)
(* @example @cfg(os = "linux") fn f() -> Int { 1 } @cfg(not(os = "linux")) fn f() -> Int { 0 } fn main() -> Int { f() } *)
program = { use_item } , { { attribute } , ( function | foreign_function | record | foreign_struct | enumeration | trait_item | impl_item | constant ) } ;

(* An attribute (Gate 2): `@` and a name from a closed vocabulary — `cfg`, `test`, `bench`,
 * `fuzz`, `deprecated` — before a top-level declaration, never before a `use`. Which names
 * exist and what each takes is the checker's (`N0619`), not the grammar's. See
 * `docs/spec.md`, *Attributes* and *Conditional compilation*.
 *)
(* @example @test fn checks() -> Int { 0 } fn main() -> Int { 0 } *)
(* @example @cfg(all(os = "macos", any(arch = "aarch64", arch = "x86_64"))) fn f() -> Int { 0 } fn main() -> Int { 0 } *)
attribute = "@" , IDENT , [ "(" , [ attribute_arg , { "," , attribute_arg } , [ "," ] ] , ")" ] ;

(* @example @deprecated("use g") fn f() -> Int { 0 } fn main() -> Int { 0 } *)
(* @example @test(fails) fn f() -> Int { 0 } fn main() -> Int { 0 } *)
attribute_arg = STRING
              | IDENT , [ "=" , STRING | "(" , [ attribute_arg , { "," , attribute_arg } , [ "," ] ] , ")" ] ;

(* A constant (Gate 2): a value the checker computes from literals, other constants,
 * operators and numeric conversions. `const` is a word only here, before a name and a `:`,
 * so it remains an ordinary name everywhere else. See `docs/spec.md`, *Constants*.
 *
 * A static (Gate 3) is written the same way with `static`: storage with one address, a
 * number or a `Bool` read-only, or an `Atomic` started by `atomic_new` of a constant. `static`
 * is a word only where `const` is. See `docs/spec.md`, *Statics*.
 *)
(* @example const MASK: UInt8 = 0xF0; fn main() -> Int { Int(MASK) } *)
(* @example static TICKS: Atomic = atomic_new(0); fn main() -> Int { atomic_add(TICKS, 1) } *)
constant = [ visibility ] , ( "const" | "static" ) , IDENT , ":" , type , "=" , expression , ";" ;

(* A trait (N78): a named set of methods a type may implement. Each method is a signature
 * ended by `;` — there are no default bodies — whose first parameter is `self: Self`. A trait
 * is in the type namespace and is not a type: it is written as a type parameter's bound,
 * `[T: Show]`, and never as the type of a value. See `docs/spec.md`, *Traits and methods*.
 *)
(* @example pub trait Show { fn show(self: Self) -> Str; fn shout(self: Self, n: Int) -> Str ! {}; } fn main() -> Int { 0 } *)
trait_item = [ visibility ] , "trait" , IDENT , "{" , { trait_method } , "}" ;

(* @example trait Size { fn size(self: Self) -> Int; } fn main() -> Int { 0 } *)
trait_method = "fn" , IDENT , "(" , [ parameters ] , ")" , "->" , type , [ effect_set ] , ";" ;

(* `impl Trait for Type`: every method of the trait, once, with `Self` written as the type.
 * `for` is a word here and nowhere else. At most one impl of a trait for a type, in the
 * trait's module or the type's. *)
(* @example trait Size { fn size(self: Self) -> Int; } struct P { x: Int, } impl Size for P { fn size(self: P) -> Int { 1 } } fn main() -> Int { 0 } *)
impl_item = "impl" , type , IDENT , type , "{" , { function } , "}" ;

(* @example use "lib/helpers.nz"; fn main() -> Int { 0 } *)
(* `as NAME` imports the module under a name (N49): its exports are written `NAME::item`
 * and are not brought into scope. `as` is a word here and nowhere else. See `docs/spec.md`,
 * *Qualified names*.
 *)
(* @example use "other.nz" as other; fn main() -> Int { 0 } *)
(* `pub use` re-exports (N103): every name the module offers, or the names in braces, each
 * optionally offered under another name with the word `as`. A re-export is also an ordinary
 * import, and is never under a name: `pub use "PATH" as m;` is refused. See `docs/spec.md`,
 * *`pub use` offers another module's definitions*.
 *)
(* @example pub use "shapes.nz"; fn main() -> Int { 0 } *)
(* @example pub use "shapes.nz" { double, Sq as Square }; fn main() -> Int { 0 } *)
use_item = "use" , STRING , [ IDENT , IDENT ] , ";"
         | visibility , "use" , STRING , [ "{" , [ reexport_name , { "," , reexport_name } , [ "," ] ] , "}" ] , ";" ;

(* @example pub use "shapes.nz" { Sq as Square }; fn main() -> Int { 0 } *)
reexport_name = IDENT , [ IDENT , IDENT ] ;

(* `NAME ::` before the name of a definition: a function, a record, an enum. Nazm has no
 * module-level values, so a qualified name is never a variable.
 *)
(* @example use "geometry.nz" as g; fn main() -> Int { g::area(g::Point(x: 1, y: 2)) } *)
(* @example use "shapes.nz" as s; fn f(x: s::Shape) -> Int { match x { s::Shape.Dot() => 0, } } fn main() -> Int { 0 } *)
qualifier = IDENT , "::" ;

(* @example fn main() -> Int { 0 } *)
(* @example fn add(a: Int, b: Int) -> Int { a + b } fn main() -> Int { add(1, 2) } *)
(* @example pub fn add(a: Int, b: Int) -> Int { a + b } fn main() -> Int { add(1, 2) } *)
(* @example fn first[A, B](a: A, b: B) -> A { a } fn main() -> Int { first(1, "x") } *)
function = [ visibility ] , "fn" , IDENT , [ type_parameters ] , "(" , [ parameters ] , ")" ,
           "->" , type , [ effect_set ] , { contract } , block ;

(* A contract clause (N87): `requires` is checked as the function is entered, `ensures` as it
 * returns, on every path, with `result` the value returned. Both are IDENTs recognised only
 * here, between the signature and the body; every `requires` comes before every `ensures`. A
 * clause is a `Bool` of literals, names, operators, field reads and calls of pure functions.
 * See `docs/spec.md`, *Contracts*.
 *)
(* @example fn half(n: Int) -> Int ! {} requires n >= 0 ensures result * 2 <= n { n / 2 } fn main() -> Int { half(8) } *)
contract = ( "requires" | "ensures" ) , expression ;

(* A foreign function (N42): a C function this program calls, declared by its signature and
 * its C symbol, with no body. `extern` is not a keyword — it is recognised only where a
 * declaration starts, before a string — so it is an IDENT here, and the string before `fn`
 * is the ABI, which must be `"C"`. Only `Int` and `Bool` cross; no type parameters and no
 * written effect set: calling one is always the effect `foreign`, and needs a `ForeignCap`.
 * `nazm run` refuses a program that calls one; `nazm build --link FILE` links it. See
 * `docs/spec.md`, *Foreign functions*.
 *)
(* @example extern "C" fn c_add(a: Int, b: Int) -> Int = "c_add"; fn main() -> Int { 0 } *)
(* @example pub extern "C" fn is_even(n: Int) -> Bool = "c_is_even"; fn main() -> Int { 0 } *)
foreign_function = [ visibility ] , IDENT , STRING , "fn" , IDENT , "(" , [ parameters ] , ")" ,
                   "->" , type , "=" , STRING , ";" ;

(* The effects a function declares it may exercise: after the return type, a `!` and a
 * set in braces. `! {}` is the empty set — the function is pure, and its body may call
 * nothing that is not. With no set written the checker infers one from the body, and
 * another module calling the function must assume every effect — so `fn f() -> Int` and
 * `fn f() -> Int ! {}` are not the same: only the second promises purity. A declared set
 * says what a function does, not what allows it: its body holds only the authority of
 * the capability values in its scope (`IoCap`, `SpawnCap`). The names live in their
 * own namespace: `io`, `spawn` and `foreign` are the only effects, a name that is not one is refused,
 * and so is one written twice. Order means nothing. See `docs/spec.md`, *Effects*.
 *)
(* @example fn show(io: IoCap, s: Str) -> Int ! { io } { print(s) } fn main(io: IoCap) -> Int { show(io, "hi") } *)
(* @example fn add(a: Int, b: Int) -> Int ! {} { a + b } fn main() -> Int { add(1, 2) } *)
(* @example fn w(c: Chan) -> Int { 0 } fn run(t: SpawnCap) -> Int ! { spawn } { let c = chan_new(1); scope { spawn w(c); } 0 } fn main(t: SpawnCap) -> Int { run(t) } *)
effect_set = "!" , "{" , [ effect_name , { "," , effect_name } ] , "}" ;

(* `spawn` is a keyword, and the effect of starting a task is named by it. *)
(* @example fn w(c: Chan) -> Int { 0 } fn run(io: IoCap, t: SpawnCap) -> Int ! { io, spawn } { let c = chan_new(1); scope { spawn w(c); } print("done") } fn main(io: IoCap, t: SpawnCap) -> Int { run(io, t) } *)
effect_name = IDENT | "spawn" ;

(* A generic declaration's parameters: at least one, no trailing comma. A parameter
 * is a **position** — renaming one changes nothing — and it is a type and nothing else.
 * Which names may be one (not a built-in type, not `Vec`, not twice) is the checker's
 * question. See `docs/spec.md`, *Generics*.
 *)
(* @example struct Pair[A, B] { first: A, second: B, } fn main() -> Int { 0 } *)
(* @example enum Maybe[T] { None, Some(value: T), } fn main() -> Int { 0 } *)
type_parameters = "[" , type_parameter , { "," , type_parameter } , "]" ;

(* `effects E` declares the function's effect parameter (N51): `effects` is a word only
 * here, before a name. At most one, only on a function that declares its effect set, and
 * never on a record or an enum (`N0388`); its name may then be written in the function's
 * effect sets. See `docs/spec.md`, *Effect parameters and captured authority*.
 *
 * A parameter may require a capability of every type it stands for: one name after a
 * `:`, and no list: `Equality`, which gives the parameter `==`, or a trait (N78), which
 * gives it the trait's methods. Only a function's parameter may require one. `Equality` is
 * not a type and nothing declares it. See `docs/spec.md`, *A type parameter may require
 * equality* and *Traits and methods*.
 *)
(* @example fn same[T: Equality](a: T, b: T) -> Bool { a == b } fn main() -> Int { if same(1, 1) { 1 } else { 0 } } *)
(* @example fn apply[effects E](f: fn() -> Int ! { E }) -> Int ! { E } { f() } fn main() -> Int { apply(fn() -> Int { 1 }) } *)
type_parameter = IDENT , [ ":" , IDENT ] | "effects" , IDENT ;

(* One bit, and one spelling for it. Absent means private to this module; `pub` exports
 * it to the modules that directly import this one. There is no `private` keyword,
 * because the default needs no word, and no package or friend visibility: a package offers
 * what its modules export, and nothing sits between. See `docs/spec.md`.
 *)
(* @example pub fn helper() -> Int { 1 } fn main() -> Int { helper() } *)
visibility = "pub" ;

(* A record: a nominal type whose fields are named. `struct` is the keyword; *record* is
 * what the semantics call the category. One concept, one spelling in each place — see
 * `docs/spec.md`, *Records*.
 *
 * Declaration order is written down and means nothing: construction names every field,
 * and reordering two fields changes neither the type, nor its interface fingerprint, nor
 * its native layout.
 *)
(* @example struct Point { x: Int, y: Int, } fn main() -> Int { Point(x: 1, y: 2).x } *)
(* @example pub struct User { name: Str, } fn main() -> Int { str_len(User(name: "a").name) } *)
(* @example struct Box[T] { value: T, } fn main() -> Int { Box[Int](value: 1).value } *)
record = [ visibility ] , "struct" , IDENT , [ type_parameters ] , "{" , [ fields ] , "}" ;

(* A struct C sees (N85): `extern "C" struct Name;` is an opaque handle — a C pointer only a
 * foreign function returns, never built, read or compared — and `extern "C" struct Name { … }`
 * a record laid out as C's struct, its fields in the order written, which here is meaning.
 * `extern` is an IDENT recognised before a string, as for a foreign function. See `docs/spec.md`,
 * *Foreign functions v3*.
 *)
(* @example extern "C" struct Db; fn main() -> Int { 0 } *)
(* @example extern "C" struct Point { x: Int, flag: Bool, y: Int } fn main() -> Int { Point(x: 1, flag: true, y: 2).y } *)
foreign_struct = [ visibility ] , IDENT , STRING , "struct" , IDENT , ( ";" | "{" , [ fields ] , "}" ) ;

(* @example struct P { x: Int, y: Int, } fn main() -> Int { P(x: 1, y: 2).y } *)
fields = field , { "," , field } , [ "," ] ;

(* @example struct P { x: Int, } fn main() -> Int { P(x: 7).x } *)
field = IDENT , ":" , type ;

(* An enum: a closed set of named variants, exactly one of which is active in any value.
 * `enum` is the keyword and *enum* is what the semantics call the category — unlike
 * `struct`/record there is no second word, because none was needed.
 *
 * Variant order is written down and means nothing: the discriminant is derived from the
 * names, so reordering two variants changes neither the type, nor its interface
 * fingerprint, nor its native representation. See `docs/spec.md`, *Enums*.
 *)
(* @example enum State { Ready, Done, } fn main() -> Int { match State.Ready() { State.Ready() => 1, State.Done() => 0, } } *)
(* @example pub enum E { V(x: Int), } fn main() -> Int { match E.V(x: 1) { E.V(x: n) => n, } } *)
(* @example enum Maybe[T] { None, Some(value: T), } fn main() -> Int { match Maybe[Int].Some(value: 1) { Maybe.None() => 0, Maybe.Some(value: v) => v, } } *)
enumeration = [ visibility ] , "enum" , IDENT , [ type_parameters ] , "{" , [ variants ] , "}" ;

(* @example enum E { A, B, } fn main() -> Int { match E.A() { E.A() => 1, E.B() => 0, } } *)
variants = variant , { "," , variant } , [ "," ] ;

(* A variant with no payload is written with **no parentheses**: there is no field list,
 * exactly as a record with no fields has none. Construction and patterns always write
 * them, because there the parentheses are what separates a variant from a projection.
 *)
(* @example enum E { A, } fn main() -> Int { match E.A() { E.A() => 0, } } *)
(* @example enum E { V(x: Int, y: Int), } fn main() -> Int { match E.V(x: 1, y: 2) { E.V(x: a, y: b) => a + b, } } *)
variant = IDENT , [ "(" , payload , ")" ] ;

(* @example enum E { V(x: Int,), } fn main() -> Int { match E.V(x: 1) { E.V(x: n) => n, } } *)
payload = field , { "," , field } , [ "," ] ;

(* @example fn f(a: Int, b: Str) -> Int { str_len(b) + a } fn main() -> Int { f(1, "x") } *)
parameters = parameter , { "," , parameter } ;

(* @example fn f(n: Int) -> Int { n } fn main() -> Int { f(1) } *)
parameter = IDENT , ":" , type ;

(* A name, applied to type arguments or not. Which names are types — `Int`, `Bool`,
 * `Str`, `Ints`, `Strs`, `Chan` (and `Chan[T]`, N53), the seven capabilities (`IoCap`, `OutCap`, `SpawnCap`, `ForeignCap`, `VouchCap`, `TimeCap`, `MmioCap`), `Vec`, a
 * declared record or enum, a type parameter in scope — is a *checking* question, not a grammatical one: the parser accepts any
 * identifier here and the checker reports `N0305` for one that is not a type. A grammar
 * that listed them would be claiming the parser rejects `fn f(x: Widget)`, which it does
 * not — it parses it and then says what is wrong with it, which is how one mistake stays
 * one error. How many arguments a name takes is the checker's too (`N0351` – `N0353`).
 *)
(* @example fn f(c: Chan) -> Int { 0 } fn main() -> Int { f(chan_new(1)) } *)
(* @example fn f(c: Chan[Str]) -> Bool { chan_send_of(c, "hi") } fn main() -> Int { if f(chan_new_of[Str](1)) { 0 } else { 1 } } *)
(* @example fn f(xs: Vec[Vec[Int]]) -> Int { vec_len(xs) } fn main() -> Int { f(vec_new[Vec[Int]]()) } *)
(* @example fn say(io: IoCap, s: Str) -> Int ! { io } { print(s) } fn main(io: IoCap) -> Int { say(io, "hi") } *)
(* @example fn f(xs: [Int; 4]) -> Int { xs[0] } fn main() -> Int { f([1, 2, 3, 4]) } *)
type = function_type | array_type | [ qualifier ] , IDENT , [ type_arguments ] ;

(* A fixed-size array type (Gate 2): its element type and its length, an integer literal or a
 * constant's name. See `docs/spec.md`, *Arrays*.
 *)
(* @example const N: Int = 3; fn f(xs: [UInt8; N]) -> Int { Int(xs[2]) } fn main() -> Int { f([UInt8(1), 2, 3]) } *)
array_type = "[" , type , ";" , ( INTEGER | IDENT ) , "]" ;

(* A function type (N50): its parameters' types, its result's, and the effects a call
 * performs — none when unwritten. Structural: two are one type exactly when all three are
 * equal. See `docs/spec.md`, *Function values and closures*.
 *)
(* @example fn twice(f: fn(Int) -> Int, x: Int) -> Int { f(f(x)) } fn main() -> Int { 0 } *)
(* @example fn run(c: IoCap, f: fn(IoCap) -> Int ! { io }) -> Int ! { io } { f(c) } fn main() -> Int { 0 } *)
function_type = "fn" , "(" , [ type , { "," , type } ] , ")" , "->" , type , [ effect_set ] ;

(* Square brackets, and one spelling: there are no angle brackets and no indexing, so
 * `name[` can only begin type arguments. Empty brackets parse — `Vec[]` is a type written
 * with the wrong number of arguments, which is `N0353` rather than a syntax error.
 *)
(* @example struct Pair[A, B] { a: A, b: B, } fn f(p: Pair[Int, Str]) -> Int { p.a } fn main() -> Int { f(Pair[Int, Str](a: 1, b: "x")) } *)
type_arguments = "[" , [ type , { "," , type } ] , "]" ;

(* @example fn main() -> Int { let a = 1; a } *)
(* @example fn main() -> Int { 1 } *)
block = "{" , { statement } , [ expression ] , "}" ;

(* @example fn main() -> Int { let a = 1; a } *)
statement = let_statement
          | assignment
          | while_statement
          | return_statement
          | break_statement
          | continue_statement
          | scope_statement
          | spawn_statement
          | expression_statement ;

(* @example fn main() -> Int { let a = 1; a } *)
(* @example fn main() -> Int { let mut a = 1; a = 2; a } *)
let_statement = "let" , [ "mut" ] , IDENT , "=" , expression , ";" ;

(* The left-hand side is a **place**: a binding, then a path of fields through it.
 * Mutability is checked at the binding, so `p.x = 2` needs `let mut p` — see
 * `docs/spec.md`, *Binding mutability reaches every field*.
 *)
(* @example fn main() -> Int { let mut a = 1; a = 2; a } *)
(* @example struct P { x: Int, } fn main() -> Int { let mut p = P(x: 1); p.x = 2; p.x } *)
assignment = place , "=" , expression , ";" ;

(* @example struct I { n: Int, } struct O { i: I, } fn main() -> Int { let mut o = O(i: I(n: 1)); o.i.n = 2; o.i.n } *)
(* @example fn main() -> Int { let mut g = [[0; 2]; 2]; g[1][0] = 5; g[1][0] } *)
place = IDENT , { "." , IDENT | "[" , expression , "]" } ;

(* @example fn main() -> Int { let mut i = 0; while i < 3 { i = i + 1; } i } *)
while_statement = "while" , expression , block ;

(* @example fn f() -> Int { return 1; } fn main() -> Int { f() } *)
return_statement = "return" , expression , ";" ;

(* @example fn main() -> Int { let mut i = 0; while true { break; } i } *)
break_statement = "break" , ";" ;

(* @example fn main() -> Int { let mut i = 0; while i < 3 { i = i + 1; continue; } i } *)
continue_statement = "continue" , ";" ;

(* @example fn w(c: Chan) -> Int { 0 } fn main(t: SpawnCap) -> Int { let c = chan_new(1); scope { spawn w(c); } 0 } *)
scope_statement = "scope" , block ;

(* @example fn w(c: Chan, n: Int) -> Int { 0 } fn main(t: SpawnCap) -> Int { let c = chan_new(1); scope { spawn w(c, 1); } 0 } *)
spawn_statement = "spawn" , IDENT , "(" , [ arguments ] , ")" , ";" ;

(* @example fn main(out: OutCap) -> Int { print("hi"); 0 } *)
expression_statement = expression , ";" ;

(* @example fn main() -> Int { 1 + 2 * 3 } *)
expression = disjunction ;

(* `||` and `&&` (N49): `Bool` operands, left-associative, and short-circuit — the right
 * operand is evaluated only when the left does not decide. `||` binds loosest. Each is the
 * `if` it lowers to; see `docs/spec.md`, *Logical operators*.
 *)
(* @example fn main() -> Int { if 1 < 2 || 2 < 1 { 1 } else { 0 } } *)
disjunction = conjunction , { "||" , conjunction } ;

(* @example fn main() -> Int { if 1 < 2 && 2 < 3 { 1 } else { 0 } } *)
conjunction = comparison , { "&&" , comparison } ;

(* Each operator gets an example. Listing six and demonstrating one would be a grammar
 * that is right about the alternatives and silent about five of them, which the
 * examples exist to prevent.
 *)
(* @example fn main() -> Int { if 1 < 2 { 1 } else { 0 } } *)
(* @example fn main() -> Int { if 1 == 1 { 1 } else { 0 } } *)
(* @example fn main() -> Int { if 1 != 2 { 1 } else { 0 } } *)
(* @example fn main() -> Int { if 1 <= 2 { 1 } else { 0 } } *)
(* @example fn main() -> Int { if 2 > 1 { 1 } else { 0 } } *)
(* @example fn main() -> Int { if 2 >= 2 { 1 } else { 0 } } *)
comparison = bit_or , { ( "==" | "!=" | "<" | "<=" | ">" | ">=" ) , bit_or } ;

(* The bit operators (Gate 2): two integers of one type, or for a shift an integer and an
 * `Int` amount. They bind tighter than comparison — `a & m == 0` is `(a & m) == 0`, not C's
 * reading — and looser than arithmetic. See `docs/general-purpose.md` §3.
 *)
(* @example fn main() -> Int { 6 | 1 } *)
bit_or = bit_xor , { "|" , bit_xor } ;

(* @example fn main() -> Int { 6 ^ 3 } *)
bit_xor = bit_and , { "^" , bit_and } ;

(* @example fn main() -> Int { 6 & 3 } *)
bit_and = shift , { "&" , shift } ;

(* @example fn main() -> Int { 1 << 4 >> 2 } *)
shift = sum , { ( "<<" | ">>" ) , sum } ;

(* @example fn main() -> Int { 1 + 2 - 3 } *)
sum = product , { ( "+" | "-" ) , product } ;

(* @example fn main() -> Int { 2 * 3 / 4 % 5 } *)
product = unary , { ( "*" | "/" | "%" ) , unary } ;

(* `!` is logical negation, as tight as `-`: `!a && b` is `(!a) && b`. It is never the `!` of
 * an effect set, which follows a result type, where no expression is.
 *)
(* `~` is the bit complement of an integer (Gate 2). *)
(* @example fn main() -> Int { -1 } *)
(* @example fn main() -> Int { if !false { 1 } else { 0 } } *)
(* @example fn main() -> Int { ~0 } *)
unary = [ "-" | "!" | "~" ] , primary ;

(* @example fn main() -> Int { (1 + 2) * 3 } *)
(* @example fn main() -> Int { if true { 1 } else { 0 } } *)
(* @example fn main() -> Int { if false { 1 } else { 0 } } *)
(* @example fn main() -> Int { str_len("a name") } *)
(* @example struct P { x: Int, } fn main() -> Int { P(x: 1).x } *)
(* `?` is a postfix beside projection, in any order and any number: `r?`, `make()?.x`,
 * `r??`. It binds tighter than negation, so `-r?` is `-(r?)`. Whether the operand is a
 * `Result` — and the core prelude's one — is the checker's question, not the grammar's.
 * See `docs/spec.md`, *Propagation*.
 *)
(* @example fn f(r: Result[Int, Str]) -> Result[Int, Str] { Result[Int, Str].Ok(value: r? + 1) } fn main() -> Int { 0 } *)
(* @example struct P { x: Int, } fn f(r: Result[P, Str]) -> Result[Int, Str] { Result[Int, Str].Ok(value: -r?.x) } fn main() -> Int { 0 } *)
(* `.name(…)` after an operand is a method call (N78): `p.show()`, `make().size()`. With a
 * trait's name as the operand, `Show.show(p)`, the trait chooses the method and the first
 * argument is the receiver. *)
(* @example trait Size { fn size(self: Self) -> Int; } fn f[T: Size](x: T) -> Int { x.size() + Size.size(x) } fn main() -> Int { 0 } *)
(* `[index]` after an operand reads an array's element (Gate 2): `xs[i]`, `grid[r][c]`,
 * `points[i].x`. After a name, a `[` followed by types and then `(` is type arguments instead,
 * as it always was: `vec_new[Int]()`; a method call on an element is written `(xs[i]).m()`.
 *)
(* @example fn main() -> Int { let xs = [1, 2, 3]; xs[1] } *)
primary = atom , { "." , IDENT , [ "(" , [ arguments ] , ")" ] | "?" | "[" , expression , "]" } ;

(* A `FLOAT` is digits, `.` and digits, and/or an exponent: `1.5`, `2e9` (Gate 2). An
 * `INTEGER` may be written `0x`, `0o` or `0b`, with `_` between digits.
 *)
(* @example fn main() -> Int { 1 } *)
(* @example fn main() -> Int { Int(2.5e1) + 0xff + 0b1_0 + 0o7 } *)
atom = INTEGER
     | FLOAT
     | STRING
     | "true"
     | "false"
     | IDENT
     | call
     | construction
     | variant_construction
     | if_expression
     | match_expression
     | closure
     | array
     | "(" , expression , ")" ;

(* An array (Gate 2): its elements, or one value and a count. *)
(* @example fn main() -> Int { let a = [1, 2, 3]; let b = [0; 4]; a[2] + b[3] } *)
array = "[" , expression , ( { "," , expression } , [ "," ] | ";" , expression ) , "]" ;

(* A closure (N50): a function written where a value is, its parameters and result in
 * full, its effects declared or none. Its body may name the bindings around it, each
 * copied in when the closure is made; a `let mut` binding may not be (`N0386`). A
 * capability may be (N51): the closure holds it, and its type says what it does.
 *)
(* @example fn main() -> Int { let k = 2; let f = fn(x: Int) -> Int { x * k }; f(3) } *)
closure = "fn" , "(" , [ parameters ] , ")" , "->" , type , [ effect_set ] , block ;

(* Type arguments are written where inference cannot find them from the arguments —
 * `vec_new[Int]()` — or where a reader wants them visible. The expected result type
 * never supplies one.
 *)
(* @example fn main() -> Int { str_len("abc") } *)
(* @example fn identity[T](v: T) -> T { v } fn main() -> Int { identity[Int](7) } *)
call = [ qualifier ] , IDENT , [ type_arguments ] , "(" , [ arguments ] , ")" ;

(* Named, never positional, so field order is never an implicit API. Parenthesised rather
 * than `Point { x: 1 }` because `IDENT "{"` is exactly what an `if` whose condition is a
 * bare name looks like, and no amount of parser lookahead makes that a decision rather
 * than a guess. See `docs/spec.md`, *Why construction is parenthesised*.
 *
 * Told apart from `call` by two tokens: `IDENT "(" IDENT ":"`. No argument expression can
 * begin with a name followed by a colon, so the two forms cannot be confused.
 *)
(* @example struct P { x: Int, y: Int, } fn main() -> Int { P(x: 1, y: 2).x } *)
(* @example struct Box[T] { value: T, } fn main() -> Int { Box[Int](value: 7).value } *)
construction = [ qualifier ] , IDENT , [ type_arguments ] , "(" , initialisers , ")" ;

(* @example struct P { x: Int, } fn main() -> Int { P(x: 1,).x } *)
initialisers = initialiser , { "," , initialiser } , [ "," ] ;

(* @example struct P { x: Int, } fn main() -> Int { P(x: 1 + 1).x } *)
initialiser = IDENT , ":" , expression ;

(* Always qualified by the enum, and always parenthesised — including for a variant with
 * no payload, because `E.V` alone is exactly the shape of a field projection. Told apart
 * from one by three tokens, `IDENT "." IDENT "("`. Since N78 a method call has that shape
 * too: `x.m(…)` with an unlabelled argument is always a call, and `x.m()` is a call when the
 * checker finds `x` names a value rather than an enum — an enum keeps every meaning it had.
 * See `docs/spec.md`, *Variants are named by their enum* and *Traits and methods*.
 *)
(* @example enum E { A, } fn main() -> Int { match E.A() { E.A() => 0, } } *)
(* @example enum E { V(x: Int), } fn main() -> Int { match E.V(x: 1 + 1) { E.V(x: n) => n, } } *)
(* @example enum Maybe[T] { None, Some(value: T), } fn main() -> Int { match Maybe[Int].None() { Maybe.None() => 0, Maybe.Some(value: v) => v, } } *)
variant_construction = [ qualifier ] , IDENT , [ type_arguments ] , "." , IDENT , "(" , [ initialisers ] , ")" ;

(* @example fn main() -> Int { ints_set(ints_new(), 0, 1) } *)
arguments = expression , { "," , expression } ;

(* @example fn main() -> Int { if true { 1 } else { 2 } } *)
(* @example fn main() -> Int { let mut n = 0; if true { n = 1; } n } *)
if_expression = "if" , expression , block , [ "else" , ( block | if_expression ) ] ;

(* The one elimination form for an enum. An expression, so it composes wherever one may
 * appear, and its arms reuse the existing block and completion rules rather than
 * introducing a second set.
 *
 * Every variant gets exactly one arm — there is no `_` arm, deliberately, so that adding
 * a variant breaks the matches that believed they had handled the whole enum. See
 * `docs/spec.md`, *Exhaustiveness*.
 *)
(* @example enum E { A, B(x: Int), } fn main() -> Int { match E.A() { E.A() => 1, E.B(x: n) => n, } } *)
(* @example enum E { A(text: Str), } fn main() -> Int { match E.A(text: "hi") { E.A(text: s) => { let n = str_len(s); n }, } } *)
match_expression = "match" , expression , "{" , [ match_arms ] , "}" ;

(* @example enum E { A, B, } fn main() -> Int { match E.A() { E.A() => 1, E.B() => 0, } } *)
match_arms = match_arm , { "," , match_arm } , [ "," ] ;

(* A pattern names the enum and never its type arguments: the value being matched already
 * has one concrete type, and `Maybe.Some(value: v)` matches a `Maybe[Int]` and a
 * `Maybe[Str]` alike.
 *)
(* @example enum E { V(x: Int), } fn main() -> Int { match E.V(x: 1) { E.V(x: n) => n, } } *)
match_arm = [ qualifier ] , IDENT , "." , IDENT , "(" , [ pattern_fields ] , ")" , "=>" , expression ;

(* @example enum E { V(x: Int, y: Int), } fn main() -> Int { match E.V(x: 1, y: 2) { E.V(x: a, y: _) => a, } } *)
pattern_fields = pattern_field , { "," , pattern_field } , [ "," ] ;

(* A payload field is bound to a name, or discarded with `_`. `_` declines to name the
 * value; it does not mean the field is absent and does not mean it is not released.
 *)
(* @example enum E { V(x: Int), } fn main() -> Int { match E.V(x: 1) { E.V(x: _) => 0, } } *)
pattern_field = IDENT , ":" , IDENT ;