# The l Programming Language Specification

This document is the normative specification of the `l` programming language. It defines source syntax, program
organization, types, evaluation, runtime behavior, and the language ABI. A program is valid only when it satisfies every
applicable rule in this document.

Except where stated otherwise, declarative text, grammar productions, and tables are normative. `must` and `must not`
state requirements; `may` states permission. `Invalid` and `error` require rejection before executable code is produced.
**Implementation-defined** behavior is valid behavior whose choice must be documented. **Undefined behavior** imposes no
requirements after the operation occurs. **No defined result** means that an operation produces no result value while
all other execution requirements continue to apply. A term is defined where it appears in bold.

Examples are non-normative. They illustrate rules but neither add exceptions nor define behavior. This specification
describes the language, not compiler commands, options, artifact formats, or implementation architecture beyond the
required compilation boundaries.

## Compilation Steps

The compilation order is fixed:

```text
Source File(s) -> Lexer -> Token Stream -> Parser -> HIR -> Reducer -> MIR -> Checker -> LIR -> Emitter -> Target Output
```

Target output may be object code, **LLVM IR** (LLVM's external intermediate representation), or another representation.
LIR is always an internal language representation and must never be identified with LLVM IR.

### Stage contracts

Each compilation stage is defined by its contract:

| Stage       | Input → output              | Sole responsibilities                                                                                                                                     |
| ----------- | --------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **lexer**   | source files → token stream | Validate UTF-8 lexical structure and produce tokens with exact lexemes and origins.                                                                       |
| **parser**  | token stream → HIR          | Validate HIR grammar and build one package tree; it performs no reduction or type checking.                                                               |
| **reducer** | HIR → MIR                   | Expand macros, eliminate every syntactic sugar, and validate rules needed specifically for those reductions.                                              |
| **checker** | MIR → LIR                   | Resolve names and semantic identities, check and infer types, and enforce all target-independent core-language rules. It performs no syntactic reduction. |
| **emitter** | LIR → target output         | Apply the selected ABI, layout, and target representability rules. It receives only checked input.                                                        |

Macro expansion is the sole exception to the general query boundary: the reducer may resolve only the names, aliases,
types, and ABI facts required by a predefined macro. Those queries neither check unrelated HIR nor produce checked MIR.

The parser leaves each `use` without its interface; the implementation supplies every interface into HIR before
reduction, as specified under [Libraries](#libraries).

Each stage may rely on every invariant guaranteed by an earlier stage. A later stage must not reinterpret an earlier
stage's grammar, repeat its validation, or construct an error that cannot occur for valid input to that stage.

The relation among language levels is a construct-subset relation:

```text
LIR ⊆ MIR ⊆ HIR
```

No later level introduces a language construct absent from an earlier level. The reducer may generate nodes only from
constructs already available in HIR. Resolution targets, inferred types, source provenance, and other annotations are
metadata, not language constructs. The relation permits MIR and LIR to have the same tree shape; LIR is still the subset
that has passed checking and carries checked facts, including every type the checker infers under
[Literal typing](#literal-typing).

### Language representations

<a id="high-level-intermediate-representation"></a>

**HIR**, the high-level intermediate representation, is the parsed form of a complete package and contains every
source-language construct. It preserves source forms, item origins, and source ranges, but not whitespace or comments.
It may contain macros, `Self`, anonymous functions, and omitted/defaulted forms listed under
[Syntactic Sugars and Macros](#syntactic-sugars-and-macros).

**MIR**, the mid-level intermediate representation, is desugared HIR. It contains only the **core language**: the
construct set shared by MIR and LIR after all syntactic reduction. Every function result, jump operand, block result,
branch, loop alternative, and enum ID that HIR permits to be implicit is explicit in MIR. No macro invocation, `Self`,
or anonymous function reaches MIR. Type-dependent expressions—including eager operators other than `&&` and `||`,
compound assignments, applications that may be calls or conversions, contextual aggregate construction, loops, switches,
and `unsafe`—are core constructs rather than checker rewrites.

**LIR**, the low-level intermediate representation, is checked and inferred MIR. It uses only MIR constructs and records
their resolved symbols, types, operation meanings, control-flow targets, and ABI-relevant facts. In LIR, every `let` has
a type and every numeric literal has the type given under [Literal typing](#literal-typing). The checker may reject or
annotate a node but must not replace it with different syntax.

### Diagnostics

An invalid program is rejected by the first applicable stage boundary, independent of how many diagnostics an
implementation chooses to report:

| Stage   | Error class                                                                                                                                                                                         |
| ------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| lexer   | Invalid encoding, token spelling, literal spelling, or unrecognized character.                                                                                                                      |
| parser  | Input outside the HIR grammar.                                                                                                                                                                      |
| reducer | Unknown or invalid macro, expansion-limit violation, invalid `Self`, mixed omitted and written enum IDs, an anonymous function in a static initializer, or another impossible HIR-to-MIR reduction. |
| checker | Invalid identifiers surviving expansion, duplicate or unresolved names, invalid types, operations, control flow, visibility, or static semantics.                                                   |
| emitter | A checked value, layout, symbol, or target-width constant not representable under the selected ABI, or an item whose symbol conflicts under [Linkage](#linkage).                                    |

An array length, written enum ID, and tuple index accept a numeric literal syntactically; positivity, integrality,
range, and bounds restrictions belong to the checker, except target-width representability belongs to the emitter. The
reducer rejects mixed omitted and written enum IDs before inserting omitted IDs.

Every diagnostic must identify the originating source file and range when one is known. A generated node inherits the
range of the source construct reduced into it. A macro-generated node uses the complete invocation range; a surviving
macro argument retains its own range. Expanded text need not be displayed. Successful checking is not memory-safety
validation.

## Modules and Packages

### Packages and modules

A **package** is the complete compilation and distribution unit. It contains exactly one root module and can be used as
a library. A public root `main` additionally gives it an entry point. A **module** is one item scope; the root and each
namespace are modules. A **namespace** is a named module nested in another module. Package metadata, including an
optional package name, is external to source text; source cannot determine its own package name or revision.

A **source file** is one named unit of source text belonging to a package. A source entry is either one source file
supplying the root module, or a directory interpreted recursively:

- Every `.l` file directly in a directory contributes items to that directory's one module. Files do not introduce
  names, and private items are shared across those files.
- A subdirectory containing an `.l` file at any depth introduces a namespace named after the subdirectory and
  recursively contains its files and child namespaces. A subdirectory with no `.l` descendant is ignored.
- A directory namespace name must be a valid non-keyword, non-predefined identifier. A source file name is not a
  language name; only its `.l` extension is significant.
- Source ordering does not affect name visibility or runtime initialization.

A root source-entry directory containing no `.l` file at any depth is invalid.

`namespace Name { items }` declares an inline namespace. A namespace is declared exactly once: repeated inline
declarations and an inline declaration colliding with a directory namespace are duplicate items. Every module item may
appear in a namespace body, including another namespace.

Directory composition joins source files; paths name visible items directly. Another package is reached only through
`use`; see [Libraries](#libraries).

An optional package name has one or more slash-separated segments. Each segment starts with an ASCII letter, continues
with ASCII letters, digits, or interior `-`, and ends with an ASCII letter or digit. It surrounds the root module for
linkage without changing source name resolution. Package naming is specified further under [Linkage](#linkage).

### Libraries

A **library** is a package another package uses, named by a one-segment package name. `use name;` declares that the
package depends on the library `name` and declares in the enclosing module a namespace `name` holding the library's
interface. `use` appears only before the items of a source file or inline namespace body. The namespace shares the
module's item scope, so a second `use` of one name in a module, even from another file, is a duplicate item.

The **interface** of a library is the part a package using it sees: its root module reduced to its aliases, its `use`s,
its public function and static declarations, its public function and static definitions as the same declarations without
body or initializer, the public functions of its `impl` blocks reduced likewise, and each namespace whose own interface
is nonempty. Every other item, and every `impl` block left empty, is omitted. The interface of each `use` inside it is
supplied the same way. Every `use` of one library reaches one interface, so its `impl` blocks place their functions
once.

The interface namespace is the root module of the library's own paths: an absolute path written inside it starts at that
namespace, and the ancestor rule of [Names and scope](#names-and-scope) keeps it from selecting items outside it. Its
items link as the library's package; see [Linkage](#linkage). Every library a package uses, directly or through another
library, is a link dependency of the package.

Locating a library's source is implementation-defined. Before reduction, the implementation rejects a `use` whose
library it cannot locate, whose name is not a package name segment, or that reaches its own library through the `use`s
of the libraries it names.

### Names and scope

Functions, statics, type aliases, and namespaces share one item scope in each module. No item may repeat, including a
second declaration followed by a definition. An `impl` block introduces no module-scope name; its functions occupy their
target type's namespace.

Items are visible throughout their module regardless of source order. Functions may recurse mutually, aliases may refer
forward, and static initializers may contain valid forward symbol relocations. Visibility is checked after path
resolution and is independent of `mut` and `volatile`.

Namespaces and type aliases are path-visible without `pub`. Functions and statics require `pub` when selected from
another module.

| Form                       | Lookup                                                                                                 |
| -------------------------- | ------------------------------------------------------------------------------------------------------ |
| Unqualified value          | Lexical parameters and bindings, inner to outer, then current-module statics and functions.            |
| One-segment named type     | Current module, then predefined names.                                                                 |
| Relative item path         | Current module; its first segment is a child namespace, except a one-segment item.                     |
| Absolute item path         | Root module of the enclosing package, per [Libraries](#libraries); lexical names never shadow it.      |
| Enum constructor path      | Resolve the prefix as a type, then the final segment as its variant before associated-function lookup. |
| Associated expression path | Resolve the prefix as a type, then find the function globally on that type, subject to visibility.     |

A child module cannot select an item owned by an ancestor, even with an absolute path; it may use an absolute path
through the root to a non-ancestor module. A path prefix that is not the required namespace or type is unresolved.

A local binding may shadow another binding, a parameter, or an unqualified module item without changing it. A binding is
not visible in its own initializer. Lexical names do not shadow qualified enum constructors or associated paths. Named
and anonymous functions require unique parameter names; labels in function-reference types need not be unique.

An identifier surviving macro expansion is invalid if it contains adjacent underscores. This applies to item,
associated-function, parameter, function-type label, binding, field, variant, path-segment, and macro names. A macro
argument consumed during expansion need not survive for this check.

### Module items

A **declaration** introduces an entity's name and type or signature. A **definition** is a declaration that also
supplies a function body or static storage. A function signature ending in `;` is a declaration. A signature followed by
a body is a definition. A static without an initializer is a declaration of externally supplied storage; a static with
an initializer is a definition. Omission never implies zero initialization. `extern` may mark a declaration outside an
`impl` block, which selects its symbol under [Linkage](#linkage); a definition is never `extern`.

`pub` grants cross-module source visibility. On a definition it also requests exported linkage; a private definition has
internal linkage. A declaration has external linkage whether or not it is public, because another object supplies its
entity. These rules apply equally to functions and statics.

A function body's result and every `return` operand must be compatible with its declared result type.

### Associated functions

An associated function is an ordinary function in a type's namespace, with no receiver or method-call syntax. Statics
and aliases cannot be associated.

`impl T { ... }` may appear at module or namespace level. The block takes no `pub`; each contained function is a
declaration or definition with ordinary visibility. Its target may be any type expression after macro expansion and
alias resolution except `void` or a `mut`- or `volatile`-qualified type. A recursive alias is valid.

Each resolved structural type owns one global associated namespace, independent of packages and modules. Implementations
for aliases and inline spellings of the same type merge. Duplicate function names are invalid, and an enum variant and
an associated function cannot share a name. `T::f` requires `T` to be a predefined name or visible alias path and
denotes an ordinary function value. A public associated function is callable from any module; a private one only from
the module containing its `impl`. An associated function named `main` is not an entry point.

### Statics

A static name has exactly its annotated resolved type; no pointer is added implicitly. Its type must expose storage:

| Exposed type                                        | Eligible | Named region                                       |
| --------------------------------------------------- | -------- | -------------------------------------------------- |
| Qualified or unqualified `*T`, valid non-`void` `T` | Yes      | One stored `T` representation.                     |
| Fixed array, struct, or enum, optionally qualified  | Yes      | The aggregate backing itself.                      |
| Scalar, tuple, slice, or function-reference type    | No       | Use a raw pointer to a slot holding that value.    |
| `void` or qualified or unqualified `*void`          | No       | `void` has no loadable or storable representation. |

A raw-pointer static's pointee may be any valid non-`void` type. A top-level aggregate definition must describe its own
backing with matching aggregate or variant syntax rather than name another aggregate reference.

<a id="static-initializers"></a>

A **static initializer** is a compile-time description of static data, relocations, and nested backing objects. After
macro expansion, it permits only the following forms, recursively:

| Form                                             | Restriction                                                            |
| ------------------------------------------------ | ---------------------------------------------------------------------- |
| Numeric, character, and Boolean literals         | Exact expected type and valid range.                                   |
| String and C-string literals                     | Expected type accepts immutable `[u8]` or `*u8`, respectively.         |
| Unary negation of a numeric or character literal | Normal literal and pre-negation range rules.                           |
| Conversion `T(n)` of a numeric literal `n`       | `n` has type `T` under [Literal typing](#literal-typing).              |
| Tuple expression                                 | At least two recursively valid elements.                               |
| Array or nonempty struct syntax                  | Exact expected aggregate type and complete recursively valid contents. |
| Qualified enum constructor                       | Exact variant and recursively valid optional payload.                  |
| Named static, function, or associated function   | A visible, compatible symbol relocation, including a predefined one.   |

Grouping is transparent. Calls, anonymous functions, runtime loads, projections, indexing, slicing, assignments, control
flow, sequences, local bindings, `unsafe`, other conversions, `null`, and computation other than literal negation are
invalid. Macros expand before this whitelist, so a macro result is allowed when the resulting form is allowed.

Each allowed form is checked against its expected type with ordinary outer qualifier conversion; a numeric literal takes
that type. Pre-negation range checking makes signed minima unavailable; character negation wraps at 32 bits and need not
remain a Unicode scalar.

Top-level raw-pointer slots are initialized against their pointee type. Aggregate members use their exact declared type.
Symbol relocations may refer forward, to the containing static, or form cycles through compatible reference-valued
members. A mutable reference may lose outer `mut` or gain outer `volatile`; no deeper capability changes are implicit.

Nested aggregate syntax creates distinct static backing for each child and stores a relocation to it. Static
initialization performs no runtime call or runtime allocation. An unqualified or only-`volatile` definition provides
read-only storage; outer `mut` provides writable storage. Unsafe retyping cannot make read-only storage writable. Each
separately backed child uses its own declared outer qualifier to determine writability. An implementation does not
guarantee that externally supplied storage actually has the declared layout, duration, or writability.

### Entry point

A package need not have an entry point. If the root module defines `pub fn main`, its exact resolved type must be
`fn () i32`; a result alias resolving to `i32` is accepted. Only that root definition is an entry point. Private,
nested, declared-only, and associated functions named `main` are ordinary functions. Its result is the program's exit
status where the platform defines one. A package with an entry point is source-executable and usable as a library;
exposing the platform entry symbol additionally requires the linkage rule under [Linkage](#linkage).

## Types and Values

### Types

The fifteen primitive types are:

| Family                         | Types                     |
| ------------------------------ | ------------------------- |
| Fixed-width unsigned integers  | `u8`, `u16`, `u32`, `u64` |
| Pointer-width unsigned integer | `usize`                   |
| Fixed-width signed integers    | `i8`, `i16`, `i32`, `i64` |
| Pointer-width signed integer   | `isize`                   |
| Floating point                 | `f32`, `f64`              |
| Unicode character              | `char`                    |
| Boolean                        | `bool`                    |
| Unit                           | `void`                    |

The integer types are fixed- and pointer-width integers; integral types add `char`; numeric types add `f32` and `f64`.
`bool`, `void`, pointers, and function references are not numeric. `usize` and `isize` use the selected ABI's pointer
width. `char` stores a 32-bit unsigned value. `f32` and `f64` use IEEE 754 binary32 and binary64.

An unsigned `N`-bit integer ranges from 0 through 2<sup>N</sup> - 1. A signed `N`-bit integer ranges from
-2<sup>N-1</sup> through 2<sup>N-1</sup> - 1.

`void` has exactly one value, `null`; all `void` values compare equal. It may be returned, sequenced, aliased, or bound
by a `let`. A parameter, field, array element, slice element, or tuple element cannot resolve directly to `void`; static
storage cannot contain it; and `*void` cannot expose a static slot.

Numeric literals are untyped; each takes the type given under [Literal typing](#literal-typing).

### Value representation

A **value** is an immutable typed semantic entity, independent of its machine representation. A **reference** is a value
designating storage or a callable function. Values use two language-level representation categories:

| Category                 | Types                                                         | Representation carried by an expression |
| ------------------------ | ------------------------------------------------------------- | --------------------------------------- |
| Direct                   | Primitives, raw pointers, function references, tuples, slices | The complete value.                     |
| Address-valued aggregate | Fixed arrays, structs, enums                                  | One reference to backing storage.       |

The reference an address-valued aggregate carries is its **backing reference**. Aggregate equality compares backing
addresses. A raw pointer to aggregate `A` designates a slot containing an `A` backing reference. Aggregate-valued fields
and elements hold such a backing reference and have separate backing; direct members are stored inline.

### Mutable reference types

A **storage-accessing reference** is a raw pointer, fixed array, struct, enum, or slice reference through which storage
can be accessed. Every unqualified one is immutable at its outer level. `mut R` grants write capability only through
that level. It is not binding mutability, ownership, exclusivity, a runtime flag, or an ABI change.

| Resolved family                           | Accepts `mut` | Capability                                        |
| ----------------------------------------- | ------------- | ------------------------------------------------- |
| Raw pointer                               | Yes           | Replace the designated slot.                      |
| Fixed array                               | Yes           | Reconstruct backing or replace element slots.     |
| Struct                                    | Yes           | Reconstruct backing or replace field slots.       |
| Enum                                      | Yes           | Reconstruct tag and payload.                      |
| Slice                                     | Yes           | Replace viewed element slots; not the descriptor. |
| Function reference, tuple, scalar, `void` | No            | These forms provide no writable storage level.    |

Qualifiers apply at exactly the written level after alias resolution. Repetition is idempotent, including through an
alias, and structural identity compares normalized qualifiers at every level.

| Projection                                              | Result                                                                        |
| ------------------------------------------------------- | ----------------------------------------------------------------------------- |
| Direct field or element of type `T`                     | `mut *T` from a mutable base, otherwise `*T`; retain base `volatile`.         |
| Aggregate field or element of type `A`                  | Automatically load exact `A`; the load is volatile when the base is volatile. |
| Raw-pointer dereference                                 | Load the exact pointee type; volatile when the pointer is volatile.           |
| Tuple projection, `for` binding, switch payload binding | Exact declared element or payload type.                                       |

### Volatile reference types

`volatile R` requires volatile accesses through that reference level; a store additionally requires `mut`. Volatility is
valid exactly where mutability is valid and changes no representation or ABI property. Repetition is idempotent, and
`volatile mut R` equals `mut volatile R`.

A control-flow join retains outer `mut` only when both inputs have it and outer `volatile` when either input has it.
Neither qualifier moves inward. Volatile access is observable but neither atomic nor synchronization; unqualified access
is non-volatile. A volatile access need not be one access of its slot's width.

### Raw pointer types

`*T` permits a load from a slot containing `T`; outer `mut` also permits a store and outer `volatile` makes those
accesses volatile. A load produces exact `T` without changing nested qualifiers. Raw pointers support only `==` and
`!=`, which compare addresses.

`*void` and `mut *void` are opaque pointers. They may be passed, compared, converted, and constructed from pointer-width
integers, but not dereferenced or assigned through because `void` has no stored representation.

### Function reference types

A **function-reference type** is callable and is not a raw pointer. Parameter labels do not participate in identity;
only ordered parameter types and the result type do. A function name is a value of its declared function-reference type.

A function reference occupies one pointer-sized direct value. It supports equality and inequality by function identity,
but no ordering, arithmetic, dereference, or conversion to or from raw pointers or integers. Calling a null or otherwise
invalid function reference is undefined behavior. Calls require exact arity, positional compatible arguments, and yield
the declared result type.

`mut *fn (value: i32) i32` is a mutable slot containing a function reference; dereference the slot before calling its
contents. Qualifiers within parameter and result types remain part of those types.

### Tuple types

A tuple is an ordered structural direct value with at least two non-`void` elements. Identity is positional and
structural after alias resolution. Projection uses an in-bounds zero-based integer literal that must decode without
overflow to `u64`. Projection yields the selected value, never an assignable slot.

Tuple equality recursively compares direct elements; address-valued aggregate elements compare backing addresses and
slices compare descriptors. Tuple ordering is undefined.

### Fixed array types

`[T; N]` is address-valued backing for `N` contiguous slots of non-`void` `T`. `N` is a numeric literal that must decode
to a positive integer representable by `u64` and fit target `usize` when used by generated iteration. Names and
expressions are not lengths.

An array initializer supplies exactly `N` comma-separated elements without a trailing comma. Elements are evaluated and
stored left to right. Indexing accepts `u8`, `u16`, `u32`, `u64`, or `usize` and follows the projection rules. A valid
index's target-width value is less than `N`; invalid indexing is undefined behavior. Array type identity requires equal
resolved element types and lengths.

### Slice types

`[T]` is a direct descriptor of contiguous non-`void` element storage: an element storage reference followed by a
`usize` element count. The descriptor is copied by value. `.length` returns its count as `usize`; equality compares both
descriptor fields.

Slicing a fixed array or slice yields `[T]`, preserves the base's outer `mut` and `volatile`, and neither copies
elements nor extends storage duration. Bounds are converted to pointer width. For source count `N`:

| Form               | Count         | Validity                   |
| ------------------ | ------------- | -------------------------- |
| `base[start..end]` | `end - start` | `start <= end <= N`        |
| `base[..end]`      | `end`         | `end <= N`                 |
| `base[start..]`    | `N - start`   | `start <= N`               |
| `base[..]`         | `N`           | Always, including `N = 0`. |

Bounds may use any accepted array index type. Element access uses the same index types and projection rules. Invalid
bounds or indexes are undefined behavior; no check is required.

A slice element type must not reach a recursive alias cycle, including through an otherwise valid aggregate. This rule
applies both to written slice types and slices produced by range syntax.

### Struct types

A struct is an anonymous ordered structural address-valued type with at least one uniquely named non-`void` field.
Identity includes field names, order, resolved types, and whether the struct is `packed`. A struct initializer names
every field exactly once in any order; evaluation and storage follow initializer source order. Selection requires a
struct reference and follows the projection rules.

### Enum types

An enum is an anonymous ordered structural discriminated union with unique variants. Each variant has zero or one
payload; an omitted or `void` payload is a unit variant. Identity includes variant names, order, resolved payload types,
and effective IDs.

Variant IDs are either omitted for every variant or written for every variant. Omitted IDs are zero-based source
positions; mixing omitted and written IDs is invalid before insertion. A written ID must be a unique integer literal
fitting `u64` and target pointer width.

An **enum constructor** is qualified enum-variant syntax through a visible alias path naming its enum: `Event::Offline`
or `Event::Reading(value)`. The prefix alone determines the enum type; expected context supplies only outer qualifiers,
unless the prefix alias itself is qualified, which then fixes them. A structural enum without an alias cannot be
constructed. A unit variant takes no argument and a payload variant exactly one. As an expression, an enum constructor
is a runtime aggregate initializer; as the right side of an aggregate assignment, it is a constructor that reconstructs
existing backing. Equality compares backing addresses.

### Type aliases

`let Name: Type = T;` declares a transparent module-level alias. `Type` is accepted only in this annotation and is not a
type expression. Aliases have no `pub`, are visible throughout their module, and may refer forward.

A recursive alias cycle is valid only when at least one alias in the cycle has a fixed-array, struct, enum, or
function-reference type as its direct right-hand side, optionally with eligible outer `mut` or `volatile` qualification.
Pure alias cycles, cycles crossing only raw pointers, and cycles through slice elements are invalid. No recursive cycle
may be reachable from a slice element type.

### Conversions

The only implicit conversions between distinct resolved types discard outer mutability and/or add outer volatility:

```text
R -> volatile R
mut R -> R
mut R -> mut volatile R
mut R -> volatile R
mut volatile R -> volatile R
```

`R` must be an eligible storage-accessing reference. No implicit conversion adds mutability, removes volatility, changes
nested qualifiers or function signatures, or performs numeric, Boolean, character, or deep reference conversion. These
conversions apply to bindings, arguments, results, assignments, equality, and control-flow joins.

Explicit conversion is allowed only for pairs in this table after alias resolution:

| Source                      | Target                                                          | Safe | Meaning                                                 |
| --------------------------- | --------------------------------------------------------------- | ---- | ------------------------------------------------------- |
| Any type                    | Same resolved type                                              | Yes  | No operation.                                           |
| Integer                     | Integer                                                         | Yes  | Numeric integer conversion.                             |
| Integer                     | `f32` or `f64`                                                  | Yes  | Convert numeric value.                                  |
| `f32` or `f64`              | Integer                                                         | Yes  | Truncate toward zero.                                   |
| `f32` or `f64`              | `f32` or `f64`                                                  | Yes  | Convert at target precision.                            |
| `char`                      | Integer                                                         | Yes  | Convert its 32-bit unsigned numeric value.              |
| Storage-accessing reference | Same reference with outer `mut` removed and/or `volatile` added | Yes  | Preserve representation while restricting access.       |
| Raw pointer                 | `usize` or `isize`                                              | Yes  | Convert the address at pointer width.                   |
| `usize` or `isize`          | Raw pointer                                                     | No   | Construct a target pointer.                             |
| `usize` or `isize`          | Address-valued aggregate                                        | No   | Construct a backing address.                            |
| Raw pointer                 | Another raw-pointer type                                        | No   | Preserve address while changing pointer type or access. |

Unsafe conversions require lexical `unsafe`. They do not validate alignment, lifetime, provenance, pointee type, or
writability. Retyping may add `mut`, remove `volatile`, or change nested pointer types, but it cannot make read-only
storage writable. No conversion turns immutable aggregate or slice access into mutable access. Explicit numeric
conversion uses values, never bit reinterpretation.

### Memory, bindings, and storage

**Storage** is a region with an address, size, alignment, duration, and contents capable of holding value
representations. Its **data** are the bytes it currently holds, not the source syntax that produced them. **Allocation**
creates a storage region with a distinct live identity. A **load** reads a stored value representation through a
reference; a **store** replaces data in existing storage through a writable reference.

A storage slot holds one value representation. Aggregate backing holds array elements, struct fields, or an enum tag and
payload. Copying a reference copies neither its region nor its data. The lifetime of a binding and the duration of
referenced storage are independent.

A **binding** is an immutable association between a name and a value within a scope. An **initializer** is an expression
or aggregate form supplying the initial value or contents of a binding or storage region. `let name: T = expression`
evaluates the expression once before the name enters scope, requires compatibility with `T`, then creates a binding of
type `T` to that value. `let name = expression` does the same with the expression's type. It performs no allocation by
itself. Binding an aggregate reference creates an alias without copying backing or adding capability.

A **runtime aggregate initializer** is array or nonempty struct syntax with an expected aggregate type, or an enum
constructor used as an expression. It allocates fresh backing at its execution site, constructs it, and yields the
expected aggregate reference, including outer qualifiers supplied by context; construction writes are volatile when that
reference is. Writable scalar slots come from aggregate storage or another storage reference; the language has no
address-of or local scalar allocator.

An **assignment** is a store or constructor application through existing writable access. A **constructor** is
destination-dependent aggregate syntax that writes an aggregate into existing backing without allocating the
destination:

| Destination               | Right side                     | Effect and result                                                   |
| ------------------------- | ------------------------------ | ------------------------------------------------------------------- |
| `mut *T`, non-`void` `T`  | Compatible value               | Store into the existing slot; yield stored `T`.                     |
| Mutable aggregate `mut A` | Matching aggregate syntax      | Apply a constructor in existing backing; yield `void`.              |
| Mutable aggregate `mut A` | Ordinary aggregate value       | Invalid; aggregate copy assignment does not exist.                  |
| `mut *A`                  | Matching aggregate initializer | Allocate fresh `A`, store its reference in the slot, and yield `A`. |

Aggregate syntax stays matching syntax when grouped, as an `unsafe` body, or as a block without entries. An assignment
never changes a binding or its destination reference. Aggregate construction preserves outer backing identity. Nested
aggregate syntax allocates separately backed children and stores their references; replacing a child reference does not
change an earlier alias to the old child. Selecting an aggregate child automatically loads its declared reference, so
applying a constructor to that selection updates the selected child's backing.

Initialization and constructor assignment are not atomic. If evaluation exits early, completed writes remain.

Runtime aggregate backing lasts until the allocating function returns. Each evaluation creates fresh backing, including
inside loops and nested constructor updates; leaving a block or iteration and replacing a child do not reclaim it.
Repeated loop allocation may therefore exhaust stack storage. Statics and literal strings have module runtime duration.

The language performs no ownership, exclusivity, provenance, alias, or lifetime analysis. Escaping a reference does not
extend storage duration.

### Numeric behavior

Integer and `char` addition, subtraction, multiplication, and negation wrap at their representation width; unsigned
negation is valid. Decimal floating literals and arithmetic round to nearest, ties to even; floating exceptions do not
trap.

Integer conversion uses destination width: narrowing keeps low bits, widening sign-extends a signed source and
zero-extends an unsigned source or `char`, and equal-width conversion yields the destination modular value.
Integer-to-float rounds to nearest, ties to even. Float-to-integer truncates toward zero and has no defined result for
NaN, infinity, or an out-of-range truncated value. `f32` to `f64` extends precision; `f64` to `f32` rounds and may
produce infinity. Integer-to-`char`, and numeric conversion to or from `bool`, do not exist.

Signed division truncates toward zero and remainder has the dividend's sign. Unsigned and `char` division use unsigned
values. Right shift is arithmetic for signed integers and logical for unsigned integers and `char`; left shift discards
high bits. A shift count must be nonnegative and less than the operand width. Integer or `char` division or remainder by
zero, signed minimum divided by or remainder by `-1`, and an invalid shift have no defined result and require no runtime
check.

Floating operations may produce infinities and NaNs. Floating remainder uses `fmod` semantics: a finite dividend modulo
an infinite divisor is the dividend; zero divisor, infinite dividend, or NaN operand produces NaN; otherwise a nonzero
result has the dividend's sign. Equality is false and inequality true when either operand is NaN; ordered comparisons
with NaN are false.

### Raw pointer and memory behavior

Packed-field pointers and raw-pointer loads and stores permit unaligned addresses. Index and range operands are
converted to pointer width by zero-extending narrower accepted unsigned types or discarding high bits of wider ones.
Slicing only constructs a descriptor.

Pointers, slices, and aggregate addresses may alias and escape. Conversions preserve only an address. Dereferencing an
invalid, null, dangling, or incorrectly typed pointer; writing read-only storage; using an invalid index or range; or
accessing an expired slice is undefined behavior. No access is atomic or synchronizing. There is no pointer arithmetic.

## Expressions and Control Flow

This section defines only MIR and LIR. Every optional or HIR-only form has already been reduced to the explicit core
language described here.

### Static typing

In the table below, `N` is one numeric type, `I` one integral type, `T` any valid type, and `A` one address-valued
aggregate. Repeated letters require equal resolved types, except for permitted outer reference-qualifier conversion.

| Expression                                     | Required types                     | Result |
| ---------------------------------------------- | ---------------------------------- | ------ |
| `-value`                                       | `N`                                | `N`    |
| `a + b`, `a - b`, `a * b`, `a / b`, `a % b`    | `(N, N)`                           | `N`    |
| `a & b`, `a \| b`, `a ^ b`, `a << b`, `a >> b` | `(I, I)`                           | `I`    |
| `~value`                                       | `I`                                | `I`    |
| `a < b`, `a > b`, `a <= b`, `a >= b`           | `(N, N)`                           | `bool` |
| `a == b`, `a != b`                             | Compatible `(T, T)`                | `bool` |
| `!value`                                       | `bool`                             | `bool` |
| `target += value`, `-=`, `*=`, `/=`, `%=`      | `target: mut *N`, `value: N`       | `N`    |
| `target &= value`, `\|=`, `^=`, `<<=`, `>>=`   | `target: mut *I`, `value: I`       | `I`    |
| `target &&= value`, `\|\|=`                    | `target: mut *bool`, `value: bool` | `bool` |

<a id="compiler-provided-functions-and-operator-desugaring"></a>

The eager operators listed here and compound assignments are core operations, not syntactic sugar. The checker resolves
each eager operator to the corresponding predefined operation for its exact operand type and records that resolution in
LIR; it does not rewrite the expression. User-associated functions never participate in operator resolution.

| Operator forms                              | Resolved predefined operations                                                 |
| ------------------------------------------- | ------------------------------------------------------------------------------ |
| `-a`, `!a`, `~a`                            | `T::neg(a)`, `bool::not(a)`, `T::bit_not(a)`                                   |
| `a + b`, `a - b`, `a * b`, `a / b`, `a % b` | `T::add(a, b)`, `T::sub(a, b)`, `T::mul(a, b)`, `T::div(a, b)`, `T::rem(a, b)` |
| `a & b`, `a \| b`, `a ^ b`                  | `T::bit_and(a, b)`, `T::bit_or(a, b)`, `T::bit_xor(a, b)`                      |
| `a << b`, `a >> b`                          | `T::shl(a, b)`, `T::shr(a, b)`                                                 |
| `a < b`, `a <= b`, `a > b`, `a >= b`        | `T::lt(a, b)`, `T::le(a, b)`, `T::gt(a, b)`, `T::ge(a, b)`                     |

Equality and inequality are primitive. They support compatible values whose types define equality: primitive values, raw
pointers, function references, tuples, slices, and address-valued aggregates. Assignment, dereference, conversion,
indexing, slicing, and projections are also primitive.

Compound Boolean assignment first evaluates and loads its target, conditionally evaluates the right operand, then stores
the selected Boolean result. As with `&&` and `||`, a `Never` right operand leaves its type `bool`.

### Literal typing

Numeric literals are untyped; the checker gives each a type. An integer literal takes its expected type when that is an
integer type, and a floating literal when that is `f32` or `f64`; otherwise an integer literal has type `i32` and a
floating literal `f32`. An integer literal never takes a floating or `char` type. An integer literal must denote a value
of its type; `usize` and `isize` literals are checked against their 64-bit carrier, and target width is checked by the
emitter. A floating literal must round to a finite value of its type. Unary `-` is not part of a literal, so a signed
minimum cannot be written as one literal.

An **untyped expression** is a numeric literal; `-` or `~` applied to an untyped expression; an eager arithmetic,
bitwise, or shift operation on two untyped expressions; a tuple expression of untyped elements; or one of these grouped,
as an `unsafe` body, or as a block without entries. An untyped expression therefore names nothing and cannot jump.
Besides the contexts under [Contextual initializers](#contextual-initializers), expected types reach operands as
follows:

| Position                                                       | Expected type                                                                          |
| -------------------------------------------------------------- | -------------------------------------------------------------------------------------- |
| Operand of prefix `-` or `~`                                   | When untyped, the operation's expected type if the operator accepts it.                |
| First checked operand of an eager binary operator              | When untyped, the operation's expected type if the operator accepts it.                |
| Second checked operand of an eager binary operator or ordering | The first operand's type.                                                              |
| Second checked operand of `==` or `!=`                         | When untyped, the first operand's type.                                                |
| Right operand of a compound assignment                         | The target's stored type.                                                              |
| Index or slice bound                                           | `usize` when untyped.                                                                  |
| Conversion argument                                            | When untyped, the target if numeric, or `usize` for a raw-pointer or aggregate target. |
| Conditional branch checked second, without expected type       | When untyped, the type of the branch checked first.                                    |
| Untyped switch arm, without expected type                      | The join of the arms checked before it.                                                |

A binary operator, ordering, or equality checks its right operand first when only the left is untyped, and otherwise its
left first; an ordering gives its first operand no expected type. When the first checked operand or an assignment target
is `Never`, the other side has no expected type. A conditional without an expected type checks its `else` branch first
when only its `if` branch is untyped, and a switch without one checks untyped arms after all others.

`let name = expression` checks its initializer without an expected type, and the binding has the initializer's type,
including outer qualifiers; a `Never` initializer is invalid. A type is inferred only where the value is written: a
later use of a binding never changes it, and `break` operands and loop alternatives take only the loop's expected type.

### Contextual initializers

Array and nonempty struct initializers require a known expected aggregate type. An enum constructor determines its own
type; context supplies only outer qualifiers. Expected types flow through exactly these contexts:

| Context                              | Expected type                                          |
| ------------------------------------ | ------------------------------------------------------ |
| `let name: T = expression`           | Written `T`; `let name = expression` supplies none.    |
| Function argument                    | Declared parameter type.                               |
| Assignment through `mut *T`          | Stored `T`, not the pointer type.                      |
| Aggregate constructor assignment     | Destination aggregate type.                            |
| Aggregate member or enum payload     | Exact declared member type.                            |
| Tuple with known matching tuple type | Corresponding element type.                            |
| Explicit `return` or function body   | Declared result type.                                  |
| Final block expression               | Surrounding result expectation.                        |
| `if` branches or switch arms         | Surrounding result expectation.                        |
| `while` or `for`                     | `break` operands and `else`, never the discarded body. |
| `loop`                               | `break` operands, never the discarded body.            |
| `unsafe` body or grouped expression  | Surrounding expectation.                               |

The checker does not infer an aggregate shape from initializer contents. A projection gives no expected type to its
base, and one branch provides context to another only under [Literal typing](#literal-typing). Context changes the type
of numeric literals alone.

### Blocks and bindings

Every MIR block has a final expression. In `a; b`, `a` is evaluated and discarded before `b`, whose result becomes the
block result. Semicolons occur only in blocks. `{ null }` is the canonical empty block and has type `void`; it is not an
aggregate initializer.

A `let` evaluates its initializer, creates its binding, then evaluates the remaining block under that binding. The
initializer must be compatible with a written type; without one the binding takes the type given under
[Literal typing](#literal-typing). If it does not complete, no runtime binding is created.

Earlier expressions and source following a jump are still resolved and checked. Their inability to run does not exempt
them from any static rule.

### Calls, constructors, and conversions

A call evaluates its callee and then its arguments left to right. Arity is exact; arguments are positional and must be
compatible with declared parameter types.

If the callee is `Never`, the call is `Never`. Every argument is still checked without parameter-provided expected type;
an argument requiring such context is invalid. Arity and parameter compatibility do not apply because no signature
exists.

A qualified enum variant path is resolved as an enum constructor before associated-function lookup. For any other
application whose callee is a path, lexical value lookup comes first. If the path names a value, the application is a
call. If it names no value but resolves as a type `T`, `T(value)` is an explicit conversion. Otherwise it remains an
ordinary call and must have a callable callee. A conversion target must be a type path; a complex type must first be
named by an alias.

A conversion takes exactly one evaluated value, whose numeric literals are typed under
[Literal typing](#literal-typing). Aggregate syntax is not a value with a source type and cannot be its argument. The
target is validated even when the argument cannot complete. Conversion permissions are defined under
[Conversions](#conversions).

A runtime aggregate initializer allocates fresh backing. Array and struct forms evaluate members in source order; an
enum constructor evaluates its payload, clears its destination, writes the tag, then stores the payload. A constructor
uses the same order in existing backing. A jump during construction leaves completed writes in place.

### Assignment

Simple assignment evaluates its destination once, then its right side, then performs the store or constructor. Its
result is defined under [Memory, bindings, and storage](#memory-bindings-and-storage).

The assignment target expression itself denotes the writable reference. Prefix `*` performs a load and is not used to
select the destination slot.

An eager compound assignment evaluates its target once and retains that writable reference, loads the stored value,
evaluates the right operand, applies the selected eager operation, stores the result, and yields it. A Boolean compound
assignment instead follows the conditional rule under [Static typing](#static-typing). On any path where an evaluated
operand does not complete, remaining work and the store are skipped.

### Unsafe blocks

`unsafe { body }` evaluates and yields `body`; it adds no runtime operation. Its lexical context permits only
conversions marked unsafe in the conversion table. It neither validates later access nor makes an unlisted conversion
valid. The context includes nested expressions but does not cross a lifted anonymous-function boundary. Dereference,
assignment through a writable pointer, and pointer-to-integer conversion do not themselves require `unsafe`.

### Control flow

Every control body is a block. A completed `if`, `while`, `loop`, `for`, or `switch` is an ordinary operand. There is no
special `else if` form; nesting places another `if` inside the `else` block.

#### Static non-yielding classification

`Never` is the internal bottom type of an expression with no normal completion; it cannot be written as a source type.
`return`, `break`, and `continue` have type `Never`.

A strict expression is `Never` when an operand that must complete before it can produce a value is `Never`. Strict forms
include prefix and eager binary operations, comparisons, calls and arguments, conversions, projections, assignments,
aggregate and tuple construction, a sequence's left operand, a binding initializer, and control conditions. All later
source is still checked. A `Never` switch scrutinee or `for` iterable is invalid because it provides no type required by
that construct.

Branch joins ignore `Never` arms. These rules are static propagation, not constant evaluation or general reachability
analysis. Merely containing a runtime jump does not make an enclosing expression `Never` when it also has a normal path.
A `break` is **reachable** unless, inside its target loop, it is checked after a `Never` operand that must complete
first; an unreachable `break` is still checked against the loop's expected type but does not contribute to its result.

#### Return

`return value` evaluates `value` and exits the current function. Every MIR return has an operand compatible with the
declared result type. Returning newly allocated stack-backed aggregate storage is type-correct but does not extend its
duration.

#### Conditional

`if condition { left } else { right }` requires a `bool` condition and evaluates only the selected branch. MIR always
has an `else`. Value-producing branches must have compatible types; one `Never` branch leaves the other's type, both
`Never` branches make the conditional `Never`, and a `Never` condition makes the whole conditional `Never`. A join keeps
outer `mut` only from both inputs and outer `volatile` from either.

#### Loops

`loop block` repeats unconditionally and discards each normally completed body value. Its result type is the common type
of reachable `break` operands; with no normally completing break it is `Never`. `continue` starts the next iteration.

`while condition block else alternative` requires a `bool` condition tested before each iteration. Body values are
discarded. A false condition evaluates `alternative`; `break value` exits without evaluating it. Every reachable break
and the normal alternative must be compatible. A `Never` condition provides no normal termination path.

`for name in iterable block else alternative` evaluates an array or slice once, fixing its count, then visits elements
in ascending index order. `name` is an immutable inferred binding of the exact element type and is scoped to the body;
it receives the element value, not its slot, loaded when its iteration starts. Outer access qualifiers of the iterable
do not move into the element type, though a volatile iterable makes each element load volatile. Normal exhaustion,
including an empty slice, evaluates the alternative. `continue` advances to the next element; `break` bypasses the
alternative. Result typing otherwise matches `while`. A `Never` iterable is invalid because it supplies no element type.

The body of `loop`, and the condition and body of `while`, are inside that loop's jump scope. A `for` body is inside its
scope; its iterable and every loop alternative are outside. Each `break` and `continue` targets the innermost enclosing
loop in the same function and is invalid without one.

#### Switch expressions

`switch` requires a non-`Never` enum scrutinee, evaluates its address once, and selects an arm by effective variant ID.
It loads the tag once and, on entering an arm that binds it, the payload once; both loads are volatile when the
scrutinee is. A case names a variant exactly once. A payload binding is optional, scoped to its arm, and has the exact
payload type; unit variants cannot bind a payload.

Without `default`, every variant must be covered. With `default`, variants may be omitted, but `default` is invalid
after all variants are named. Unknown or duplicate cases and duplicate defaults are invalid. A written default also
receives an invalid discriminator read from raw memory; an invalid discriminator without default is undefined behavior.

Only the selected arm runs. Value-producing arms use conditional compatibility and `Never` rules, and surrounding
expected type flows into every arm. The next `case`, `default`, or closing brace terminates an arm; no separator is
written.

### Evaluation order

| Form                         | Order                                                                 |
| ---------------------------- | --------------------------------------------------------------------- |
| Eager binary operator        | Left, then right.                                                     |
| Assignment                   | Target once, right side, then store or constructor.                   |
| Eager compound assignment    | Target, load, right side, operation, store.                           |
| Function call                | Callee, then arguments left to right.                                 |
| Tuple construction           | Elements left to right.                                               |
| Tuple projection             | Tuple value, then extraction.                                         |
| Block sequence               | Entries in order, then final expression.                              |
| `let`                        | Initializer, bind, then remaining block.                              |
| Explicit conversion          | Argument, then conversion.                                            |
| `unsafe`                     | Body.                                                                 |
| Dereference                  | Pointer, then load.                                                   |
| Field selection              | Base, then projection or load.                                        |
| Slice length                 | Descriptor, then count extraction.                                    |
| Aggregate initializer        | Allocate, construct contents, yield reference.                        |
| Array or struct construction | Members in source order.                                              |
| Enum construction            | Payload, destination initialization, tag, payload store.              |
| Indexing                     | Base, then index.                                                     |
| Slicing                      | Base, supplied start, supplied end.                                   |
| `if`                         | Condition, then selected branch.                                      |
| `switch`                     | Scrutinee, then selected arm.                                         |
| `while`                      | Condition before each body; alternative only when condition is false. |
| `loop`                       | Body repeatedly until a reachable break.                              |
| `for`                        | Iterable once, elements in index order, alternative on exhaustion.    |
| `&&=`, `\|\|=`               | Target and load, conditionally right, then store.                     |
| `return`                     | Operand, then function exit.                                          |
| `break`                      | Operand, then target-loop exit.                                       |
| `continue`                   | Advance to the target loop's next iteration.                          |

All source is checked regardless of runtime selection. Static initializers have no runtime evaluation order and may
refer forward.

## Syntactic Sugars and Macros

### HIR reductions

**Syntactic sugar** is an HIR construct whose meaning is defined by replacement with core-language constructs. The
reducer applies each syntactic replacement before producing MIR. Type and `Never` consequences shown in the table are
enforced later by the checker; the reducer does not determine them.

| HIR form                           | MIR form and type                                                                           |
| ---------------------------------- | ------------------------------------------------------------------------------------------- |
| Omitted function result            | Explicit `void`.                                                                            |
| Bare `return` or `break`           | The same jump with operand `null`; result remains `Never`.                                  |
| Empty block or block ending in `;` | Block ending in explicit `null`; type `void` unless an earlier strict entry is `Never`.     |
| Empty block entry `;`              | An explicit discarded `null;`.                                                              |
| `a && b`                           | `if a { b } else { false }`; both operands must be `bool`.                                  |
| `a \|\| b`                         | `if a { true } else { b }`; both operands must be `bool`.                                   |
| `if` without `else`                | `else { null }`; the written branch must be `void` or `Never`.                              |
| `while` or `for` without `else`    | `else { null }`; normal completion type `void`.                                             |
| Enum IDs omitted for every variant | Explicit zero-based source-position IDs; a mixed enum is rejected.                          |
| `Self`                             | The enclosing expanded `impl` target.                                                       |
| `Self::f`                          | `<target>::f`, requiring a path spelling for the target.                                    |
| Anonymous function                 | A private lifted function plus an ordinary function reference of the written function type. |
| Macro invocation                   | The expression or type HIR returned by the predefined macro, recursively reduced.           |

Generated names are deterministic and cannot collide with source names. Relative and absolute paths retain their
spelling and resolution context. Lifted anonymous functions join the enclosing module after `Self` replacement.

`Self` is valid only within a function contained by an `impl` block and is invalid in the block's target. Its
replacement is resolved in the containing module. `Self::f` is invalid when that target has no predefined-name or
alias-path spelling, although `Self` remains valid as a type there.

An anonymous function does not capture. Its body may use only its parameters, its own local bindings, and visible module
items. An enclosing `unsafe` context does not enter the lifted body.

Operators other than `&&` and `||`, compound assignments, calls or conversions, contextual aggregate forms, loops,
switches, and `unsafe` are not sugar. They remain core nodes from HIR through LIR, with semantic facts attached by the
checker.

For either short-circuit reduction, the left operand is evaluated first and the right only on the selected path. A
`Never` left operand makes the result `Never`; a `Never` right operand leaves the other branch as a completion path.

<a id="macro-invocations"></a>

### Compile-time macros

`@name(arguments)` is accepted only in expression and type contexts, never as an item. The language provides no syntax
for defining macros. The predefined macros are `@CType` and `@sizeOf`; every other name is invalid.

Expansion recursively replaces each invocation with HIR matching its context. Macro-specific argument validation and
macro-local name, alias, type, and ABI queries belong to the reducer; they do not constitute general MIR checking.
General name resolution and all core-language type checking remain exclusive to the checker. No invocation reaches MIR.

Expansion permits 32 invocations total along one path and rejects the 33rd. Counting starts independently for every
function body, parameter type, result type, alias definition, static annotation, static initializer, and `impl` target.
Nested arguments and generated invocations count; ordinary HIR nesting does not. An invocation used as a macro argument
is replaced by its result, type or expression, before the enclosing macro applies.

Macro arguments are not generally name-checked or type-checked before substitution. A complete qualified or absolute
path is stored as a type unless parenthesized. `Self`, `mut`, `volatile`, function, array, slice, struct, enum, and
packed struct forms force a type argument; a pointer is type-forcing when its pointee is, and a tuple when at least one
element is. Other arguments, including a bare relative name, are expressions. A type-oriented macro may reinterpret a
path expression, its dereference, or a tuple wholly composed of reinterpretable expressions as the corresponding type
form. A qualified or absolute path nested inside a tuple does not by itself make that tuple type-forcing.

#### `@CType`

`@CType("C declaration")` takes one string in a type context. It trims the decoded string, collapses each internal
whitespace run to one space, and matches case-sensitively. It maps supported C scalar and pointer declarations to an
ordinary `l` type according to the selected C ABI; this specification contains no machine-specific mapping table.

`char` and `unsigned char` map to `u8`, `signed char` to `i8`, `_Bool` to `bool`, `size_t` to `usize`, `ptrdiff_t` to
`isize`, `float` to `f32`, and `void` to `void`. The primitive each remaining spelling maps to is implementation-defined
per target; it must have the width, signedness, and floating representation the selected C ABI gives that C type. Where
plain C `char` is signed, `u8` agrees with it across calls only for values 0 through 127.

The accepted scalar spellings and portable pointer-declarator grammar are fixed. A pointer declarator is tokenized at
spaces and each `*`:

```text
c-scalar = "char" | "unsigned char" | "signed char" | "_Bool"
         | "short" | "short int" | "signed short" | "signed short int"
         | "unsigned short" | "unsigned short int"
         | "int" | "signed" | "signed int" | "unsigned" | "unsigned int"
         | "long" | "long int" | "signed long" | "signed long int"
         | "unsigned long" | "unsigned long int"
         | "long long" | "long long int" | "signed long long" | "signed long long int"
         | "unsigned long long" | "unsigned long long int"
         | "size_t" | "ptrdiff_t" | "float" | "double" | "void"
c-qualifier = "const" | "volatile"
scalar-word = /* one word in an accepted scalar spelling */
c-pointer-declarator = (c-qualifier | scalar-word)+ ("*" c-qualifier*)+
```

Removing qualifiers from the prefix and joining its scalar words with spaces must leave exactly one accepted scalar
spelling. Prefix qualifiers apply through the first pointer; qualifiers following a `*` apply when that pointer is
another pointer's pointee. At each pointee level, absence of `const` adds `mut`, `const` leaves access immutable, and
`volatile` adds `volatile`. Qualifiers after the final `*` have no type-level effect. Repeated qualifiers are
idempotent. The result carries no C-specific marker.

#### `@sizeOf`

`@sizeOf(T)` is expression-only and takes one type. The reducer expands nested macros, substitutes applicable `Self`,
resolves aliases in the invocation's module, and queries the selected ABI. It produces `usize(n)`, the conversion of an
integer literal `n` equal to the language value size of `T`.

`void` has size zero; qualifiers do not affect size; an aggregate measures its backing; an aggregate-valued member
measures one reference slot; and a raw pointer measures one pointer. Macro-local resolution rejects an unknown alias, an
invalid recursive alias cycle, an array length that is not a positive integer, and mixed omitted and written enum IDs;
the argument is otherwise unchecked because it never reaches MIR, while the resulting MIR is checked normally.

## Prelude

### Predefined names

The fifteen primitive names are predefined identifiers, not keywords:

```text
u8 u16 u32 u64 usize i8 i16 i32 i64 isize f32 f64 char bool void
```

Each is bound in every module and resolves as a one-segment type path. The binding does not participate in longer or
absolute paths. No item, associated function, parameter, function-type label, local binding, field, or variant may use a
predefined name, so these bindings cannot be shadowed.

### Predefined functions

The following associated functions exist in every module. Each occurrence of `T` in one signature is the same resolved
primitive type.

| Targets                                                  | Functions                                                                                            |
| -------------------------------------------------------- | ---------------------------------------------------------------------------------------------------- |
| `u8 u16 u32 u64 usize i8 i16 i32 i64 isize char f32 f64` | `neg(T) T`; `add(T, T) T`; `sub(T, T) T`; `mul(T, T) T`; `div(T, T) T`; `rem(T, T) T`                |
| `u8 u16 u32 u64 usize i8 i16 i32 i64 isize char f32 f64` | `lt(T, T) bool`; `le(T, T) bool`; `gt(T, T) bool`; `ge(T, T) bool`                                   |
| `u8 u16 u32 u64 usize i8 i16 i32 i64 isize char`         | `bit_not(T) T`; `bit_and(T, T) T`; `bit_or(T, T) T`; `bit_xor(T, T) T`; `shl(T, T) T`; `shr(T, T) T` |
| `bool`                                                   | `not(bool) bool`                                                                                     |

They are ordinary function values when named explicitly. A source `impl` may not declare one on a target that provides
it; the same name on another target is ordinary. The eager operators listed under [Static typing](#static-typing) select
these predefined meanings by exact operand type but remain core operator nodes; defining an associated function cannot
overload an operator or add a coercion.

### Predefined macros

The prelude provides `@CType` and `@sizeOf` with the reductions specified under
[Compile-time macros](#compile-time-macros). They are HIR-only and are absent from MIR and LIR.

## Syntax

### Grammar notation

| Form                 | Meaning                                               |
| -------------------- | ----------------------------------------------------- |
| `name`               | A production defined by this specification            |
| `"text"` or `'text'` | Literal UTF-8 text between matching quotes            |
| `a b`                | `a` followed by `b`                                   |
| `a \| b`             | Either `a` or `b`                                     |
| `(a)`                | Grouping                                              |
| `a?`                 | Zero or one occurrence                                |
| `a*`                 | Zero or more occurrences                              |
| `a+`                 | One or more occurrences                               |
| `a{m,n}`             | From `m` through `n` occurrences                      |
| `/* ... */`          | A prose definition or restriction, not language input |

Alternation has the lowest precedence, concatenation the next higher precedence, and postfix repetition the highest.
Parentheses override that order. Grammar defines syntax only; all applicable lexical, resolution, typing, and semantic
rules also apply.

### Source text and tokens

**Source text** is a sequence of Unicode scalar values encoded as UTF-8. Implementations must not normalize it;
canonically equivalent sequences remain distinct. The complete lexical definition is one grammar:

```text
ASCII-letter       = /* U+0041 through U+005A or U+0061 through U+007A */
ASCII-digit        = /* U+0030 through U+0039 */
ASCII-alphanumeric = ASCII-letter | ASCII-digit
decimal-digit      = ASCII-digit
binary-digit       = "0" | "1"
hexadecimal-digit  = decimal-digit | /* U+0041 through U+0046 or U+0061 through U+0066 */
character          = /* any Unicode scalar value */
newline            = /* U+000A */
Unicode-whitespace = /* U+0009 through U+000D, U+0020, U+0085, U+00A0, U+1680,
                        U+2000 through U+200A, U+2028, U+2029, U+202F, U+205F, or U+3000 */

token = whitespace
      | documentation-comment
      | line-comment
      | keyword
      | boolean-literal
      | null-literal
      | identifier
      | numeric-literal
      | character-literal
      | string-literal
      | c-string-literal
      | operator-or-punctuation

whitespace            = Unicode-whitespace+
non-newline-character = /* any character except newline */
line-comment          = "//" non-newline-character*
documentation-comment = "///" non-newline-character*

identifier = (ASCII-letter | "_") (ASCII-letter | ASCII-digit | "_")*

keyword = "pub" | "fn" | "if" | "else" | "while" | "loop" | "for" | "in" | "switch"
        | "case" | "default" | "break" | "continue" | "let" | "static" | "mut"
        | "volatile" | "return" | "type" | "Type" | "namespace" | "impl"
        | "struct" | "enum" | "packed" | "unsafe" | "extern" | "use"
        | "Self" /* HIR-only use: replaced before MIR */
boolean-literal = "true" | "false"
null-literal    = "null"

decimal-digits     = decimal-digit (decimal-digit | "_")* decimal-digit | decimal-digit
hexadecimal-digits = hexadecimal-digit (hexadecimal-digit | "_")* hexadecimal-digit | hexadecimal-digit
binary-digits      = binary-digit (binary-digit | "_")* binary-digit | binary-digit

integer-literal = decimal-digits | "0x" hexadecimal-digits | "0b" binary-digits
float-literal   = decimal-digits ("." decimal-digits exponent? | exponent)
exponent        = ("e" | "E") ("+" | "-")? decimal-digits
numeric-literal = integer-literal | float-literal

character-content = /* any character except U+0027, U+005C, or newline */
character-literal = "'" (character-content | character-escape) "'"
character-escape  = "\n" | "\r" | "\t" | "\0" | "\\" | "\'" | unicode-escape
unicode-escape    = "\u{" hexadecimal-digit{1,6} "}"

string-character           = /* any character except U+0022, U+005C, or newline */ | string-escape
multiline-string-character = /* one character other than U+005C that does not begin the closing delimiter */
                           | string-escape
string-escape      = "\n" | "\r" | "\t" | "\0" | "\\" | "\'" | '\"' | unicode-escape
single-line-string = '"' string-character* '"'
multiline-string   = '"""' multiline-string-character* '"""'
string-literal     = single-line-string | multiline-string
c-string-literal   = "c" (single-line-string | multiline-string)

operator-or-punctuation = "@" /* HIR-only macro introducer; absent from MIR */
                        | "::" | "(" | ")" | "{" | "}" | "[" | "]" | "," | ":" | ";" | "." | ".." | "="
                        | "+" | "-" | "*" | "/" | "%" | "+=" | "-=" | "*=" | "/=" | "%="
                        | "==" | "!=" | "<" | ">" | "<=" | ">="
                        | "&&" | "||" /* HIR-only short-circuit operators; reduced before MIR */
                        | "&&=" | "||=" | "!"
                        | "&" | "|" | "^" | "~" | "<<" | ">>" | "&=" | "|=" | "^=" | "<<=" | ">>="
```

Except for numeric candidates, the lexer takes the longest valid token at each position. A spelling equal to a keyword
or literal word is reclassified as that word. `c` immediately followed by a string delimiter begins a C string.
Operators and punctuation use longest match; `:::` is `::` followed by `:`, so trivia must separate an annotation colon
from a following absolute path.

The **token stream** is the ordered, lossless decomposition of one or more source files into tokens, preserving file
boundaries and origins. Every character of valid source text belongs to exactly one token. Each token retains its exact
UTF-8 lexeme and a half-open byte range. Tokens are contiguous, no end token is appended, and concatenating their
lexemes reconstructs the source exactly. The parser discards whitespace and comments before applying HIR grammar; they
may separate any two syntactic tokens. An item's range runs from its first through last syntactic token.

Each maximal nonempty whitespace run is one token. A line comment ends before newline or at end of input; newline
belongs to following whitespace. `///` begins a documentation comment and every other `//` a line comment. Both are
discarded by the parser; documentation comments are reserved for item documentation. Block comments do not exist: `/*`
is `/` followed by `*`.

Identifiers are case-sensitive and ASCII-only. Non-ASCII scalar values occur only in whitespace, comments, character
literals, and strings. Keywords and literal words cannot be names. Each has its own token kind. Primitive names are
identifiers. `Type` is only the annotation of a type alias; lowercase `type` is reserved and begins no production.
Boolean literals have type `bool`, and `null` has type `void`.

After an ASCII digit, the numeric candidate consumes the longest numeric-literal prefix. A decimal `.` enters the
candidate when followed by a decimal digit or `_` and the preceding syntactic token is not `.`. A following `e` or `E`
enters with an optional sign, and immediately following identifier characters, optionally after one `_`, are consumed as
a suffix. The whole candidate is validated as one token or one lexical error; malformed text is not split, and a
candidate with a suffix is invalid. `_` may repeat between digits, but a digit must occur at each end of a digit
sequence. `-` is always a separate operator.

A character escape must decode to one Unicode scalar value; surrogates and values above `U+10FFFF` are invalid. Escapes
in strings are decoded before semantic use while the token retains its original spelling. Three opening quotes select a
multiline string.

An ordinary string literal has immutable type `[u8]`. Its elements are the UTF-8 bytes of decoded text in
module-duration read-only storage, with no trailing zero; indexing observes bytes and the descriptor count is byte
length. A C-string literal has immutable type `*u8` in module-duration read-only storage, with exactly one appended zero
byte; embedded zeros remain. Each literal occurrence has its own storage, reused by every evaluation of it, so equal
literals at different sites have distinct addresses.

### Module grammar

Module and expression grammar is exclusively HIR grammar. Comments identify forms that the reducer removes before MIR.

```text
module          = use-declaration* item*
use-declaration = "use" identifier ";"

item = function-item
     | static-variable
     | type-alias
     | namespace-declaration
     | impl-block

function-item = "pub"? "extern"? signature ";"
              | "pub"? signature block
namespace-declaration = "namespace" identifier "{" use-declaration* item* "}"
impl-block             = "impl" type-expression "{" impl-function* "}"
impl-function          = "pub"? signature (";" | block)
static-variable        = "pub"? "static" identifier ":" type-expression ("=" static-initializer)? ";"
                       | "pub"? "extern" "static" identifier ":" type-expression ";"
static-initializer     = assignment-rhs
type-alias             = "let" identifier ":" "Type" "=" type-expression ";"

/* HIR only when the result is omitted: the reducer inserts void. */
signature  = "fn" identifier "(" parameters? ")" type-expression?
parameters = parameter ("," parameter)*
parameter  = identifier ":" type-expression

type-expression = "Self" /* HIR only: replaced with the enclosing impl target */
                | macro-invocation /* HIR only: expanded */
                | item-path
                | raw-pointer-type
                | mutable-type
                | volatile-type
                | function-type
                | tuple-type
                | fixed-array-type
                | slice-type
                | struct-type
                | enum-type

item-path        = "::"? identifier ("::" identifier)*
raw-pointer-type = "*" type-expression
mutable-type     = "mut" type-expression
volatile-type    = "volatile" type-expression
function-type    = "fn" "(" parameters? ")" type-expression
tuple-type       = "(" type-expression "," type-expression ("," type-expression)* ")"
struct-type      = "struct" "{" fields "}"
                 | "packed" "struct" "{" fields "}"
fields           = field ("," field)* ","?
field            = identifier ":" type-expression
enum-type        = "enum" "{" enum-variants ","? "}"
enum-variants    = enum-variant ("," enum-variant)*
/* HIR only when the ID is omitted: the reducer inserts the source-position ID. */
enum-variant     = identifier (":" type-expression)? ("=" numeric-literal)?
fixed-array-type = "[" type-expression ";" numeric-literal "]"
slice-type       = "[" type-expression "]"

/* HIR only: every invocation is expanded before MIR. */
macro-invocation = "@" identifier "(" macro-arguments? ")"
macro-arguments  = macro-argument ("," macro-argument)*
macro-argument   = expression | type-expression
```

A primitive type is a one-segment `item-path`. A function signature's result follows `)`; omission reduces to `void`. A
function type always writes its result, including `void`.

### Expression grammar

```text
expression = jump | assignment
binding    = "let" identifier (":" type-expression)? "=" assignment

/* HIR only when an operand is omitted: the reducer inserts null. */
jump = "return" assignment?
     | "break" assignment?
     | "continue"

block      = "{" block-body "}"
/* HIR only when the final expression is omitted: the reducer inserts null. */
block-body = block-entry* expression?
block-entry = expression ";" | binding ";" | ";" /* HIR only: reduced to discarded null */

/* HIR only when else is omitted for if, while, or for: the reducer inserts else { null }. */
control = control-head block ("else" block)?
        | "loop" block
        | switch-expression
control-head    = control-keyword expression | "for" identifier "in" expression
control-keyword = "if" | "while"

switch-expression = "switch" expression "{" switch-arm* "}"
switch-arm = "case" identifier ("(" identifier ")")? ":" expression
           | "default" ":" expression

assignment = logical-or
           | logical-or "=" assignment-rhs
           | logical-or compound-assignment assignment
assignment-rhs = assignment

aggregate-initializer = "[" initializer-elements? "]"
                      | "{" initializer-fields ","? "}"
initializer-elements = assignment-rhs ("," assignment-rhs)*
initializer-fields   = initializer-field ("," initializer-field)*
initializer-field    = identifier ":" assignment-rhs

compound-assignment = "+=" | "-=" | "*=" | "/=" | "%="
                    | "|=" | "^=" | "&=" | "<<=" | ">>="
                    | "&&=" | "||="

/* HIR-only operator tails: the reducer replaces || and && with conditionals. */
logical-or     = logical-and ("||" logical-and)*
logical-and    = bitwise-or ("&&" bitwise-or)*
bitwise-or     = bitwise-xor ("|" bitwise-xor)*
bitwise-xor    = bitwise-and ("^" bitwise-and)*
bitwise-and    = equality ("&" equality)*
equality       = relation (("==" | "!=") relation)*
relation       = shift (("<" | ">" | "<=" | ">=") shift)*
shift          = addition (("<<" | ">>") addition)*
addition       = multiplication (("+" | "-") multiplication)*
multiplication = unary (("*" | "/" | "%") unary)*

unary   = ("-" | "!" | "~" | "*") unary | postfix
postfix = primary postfix-tail
postfix-tail = ("." (identifier | tuple-index) | "[" subscript "]" | "(" arguments? ")")*
subscript = expression | expression? ".." expression?

primary = numeric-literal
        | character-literal
        | string-literal
        | c-string-literal
        | "true" | "false" | "null"
        | item-path
        | associated-path
        | anonymous-function /* HIR only: lifted by the reducer */
        | tuple-expression
        | aggregate-initializer
        | "(" expression ")"
        | block
        | control
        | macro-invocation /* HIR only: expanded */
        | "unsafe" block

/* HIR only: replaced by a lifted named function and function reference. */
anonymous-function = "fn" "(" parameters? ")" type-expression block
/* HIR only because Self is replaced before MIR. */
associated-path = "Self" "::" identifier
tuple-expression = "(" expression "," expression ("," expression)* ")"
tuple-index = numeric-literal
arguments   = expression ("," expression)*
```

Repetitions from `logical-or` through `multiplication` and in `postfix-tail` associate left. Assignment and prefix unary
operators associate right. A jump is a complete expression, not a primary; parentheses can place one where a primary is
required.

Every control head consumes an expression directly. Parentheses are ordinary grouping. Every body is a block, so a
completed control expression composes without parentheses and an `else` belongs to the control whose block immediately
precedes it. `{}` is an empty block, never an empty aggregate initializer. `associated-path` exists only for `Self`;
every other associated path is an `item-path`.

## ABI

### Machine and ABI model

The selected target ABI supplies pointer width, endianness, pointer representation, scalar size and alignment, aggregate
and stack layout, symbol decoration, and the platform C calling convention. This specification expresses all
target-dependent behavior through that ABI and contains no machine or target list.

Fixed-width primitives retain their specified widths. `usize`, `isize`, raw pointers, function references, enum tags,
and aggregate backing references use target pointer width. The emitter rejects a checked pointer-width literal, enum ID,
fixed-array iteration count, string length, layout, or symbol that the selected ABI cannot represent. Generated code may
call the target's compiler-runtime or C math routines for operations without a native instruction, such as floating
remainder or wide division.

`@CType` is the sole language facility for mapping supported C type declarations to `l` types. Its mapping follows the
target C ABI as specified under [Compile-time macros](#compile-time-macros); after expansion, its result is an ordinary
`l` type with no C-specific identity or behavior.

### Calling convention and interoperability

Functions use the selected target's C calling convention. An `extern` function declaration may therefore name a
compatible externally supplied function without a language-specific adapter. The source declaration must match the
linked definition; no C wrapper is generated and compatibility is not verified.

The selected C ABI governs extension, register, return, and indirect-call rules for every primitive type, whether
written directly or produced by `@CType`; `char` crosses a call as C `uint32_t` and `bool` as `_Bool`. `mut` and
`volatile` are access properties and never alter calling convention or stored representation.

An ordinary string is an immutable `[u8]` descriptor and is not a C string. A C-string literal is an immutable `*u8`
with one trailing zero and is intended for compatible C pointer parameters.

An address-valued `l` aggregate parameter or result carries one backing address and therefore corresponds to a C
pointer, not a C aggregate passed by value. Tuples and slices use direct `l` composite representations; no compatibility
with C structs is promised. Variadic functions, by-value C aggregates, and functions using a calling convention other
than the target's C calling convention have no general direct mapping and require a compatible external wrapper.

### Language value layout

`mut` and `volatile` change no size, alignment, padding, representation, or calling convention. `@sizeOf(T)` reports the
selected ABI's language value size under these rules:

- Fixed-array backing is a contiguous sequence of element representation slots. The array layer adds no inter-element
  padding beyond each element representation's own size and alignment requirements.
- A slice is an element storage reference followed by a pointer-width unsigned count, stored and passed as a direct
  value. Its size is twice pointer size.
- An ordinary struct follows target struct layout, including field and tail padding. A `packed struct` preserves field
  order, removes struct padding, and has alignment one; accesses may be unaligned.
- An aggregate-valued field or element stores one backing reference slot, not inline child backing. Raw pointers,
  function references, tuples, and slices use their direct representations.
- An enum is a target-layout structure containing a pointer-width tag followed by payload storage whose size and
  alignment are the maximum required by any variant representation. A unit payload has size zero and alignment one.
  Padding aligns the payload and complete enum.
- A tuple is a non-packed target-layout structure of its element representations. An aggregate element occupies one
  backing reference slot.
- A function reference has pointer size. `void` has value size zero.
- A stored `bool` occupies one byte for C `_Bool` compatibility; a load yields the byte's lowest bit.

Static backing and runtime backing use the same language layout. Relocations and padding do not change a type's ABI.

### Linkage

A function or static definition without `pub` has internal linkage. A public definition is exported. Every bodyless
function and static declaration without an initializer has external linkage, while `pub` independently controls source
visibility. An externally supplied entity must have a compatible symbol, type, layout, calling convention, and access
behavior.

An `extern` declaration uses its item name as its logical symbol, independent of its module path and package. Every
other ordinary function and static item, definition or declaration, uses the symbol of its place: that of its package,
its module path within that package, and its item name. An item of an interface belongs to the library's package; every
other item belongs to the package being compiled.

The symbol joins package name segments, module path segments within the package, and the item name with `__`; `-` in a
package segment becomes `_`, and an unnamed package contributes no segment, so its root item's symbol is its item name.
The package name surrounds the root module for linkage only. Relative and absolute source paths still resolve from that
package's own root. Distinct places may share a symbol, as `a_::b` and `a::_b` or packages `a--b` and `a/b` do, and
qualified symbols in an unnamed package are not a stable foreign interface. An `extern` symbol cannot contain adjacent
underscores, so it never reaches a qualified or named-package definition.

Declarations sharing a symbol denote one external entity: all must be functions, or all statics, of the same resolved
type. No definition may share its symbol with a declaration or another definition.

A named package prefixes `main`, so it does not expose the unqualified platform entry symbol. An executable entry point
therefore requires the logical root symbol `main` without a package prefix.

### Associated function symbols

An associated function symbol is independent of package and module names. It is the decimal character count of its
canonical resolved-type encoding, followed by that encoding, `__`, and the function name. No ordinary symbol starts with
a digit. Alias names never occur in the encoding; equal resolved types encode equally and distinct types differently. A
predefined function used as a value has the same form of symbol; each object using it emits an identical mergeable
definition.

Primitive encodings are:

| Type    | Code | Type    | Code | Type   | Code |
| ------- | ---- | ------- | ---- | ------ | ---- |
| `i8`    | `a`  | `u8`    | `h`  | `bool` | `b`  |
| `i16`   | `s`  | `u16`   | `t`  | `char` | `c`  |
| `i32`   | `l`  | `u32`   | `m`  | `f32`  | `f`  |
| `i64`   | `x`  | `u64`   | `y`  | `f64`  | `d`  |
| `isize` | `i`  | `usize` | `j`  | `void` | `v`  |

Complex encodings use unsigned decimal integers without leading zeros:

Angle brackets below enclose metavariables, postfix `*` and `+` have the notation meanings from
[Grammar notation](#grammar-notation), spaces are separators and are not emitted, and tags, `_`, and decimal integers
are emitted literally.

| Type           | Encoding                                                                                          |
| -------------- | ------------------------------------------------------------------------------------------------- |
| Tuple          | `T <type>+ E`                                                                                     |
| Fixed array    | `A <length> _ <type>`                                                                             |
| Slice          | `S <type>`                                                                                        |
| Raw pointer    | `P <type>`                                                                                        |
| Function       | `F <result type> <parameter type>* E`                                                             |
| Struct         | `O (<name> <type>)* E`                                                                            |
| Packed struct  | `Q (<name> <type>)* E`                                                                            |
| Enum           | `N (<name> <payload type> <id> _)* E`; unit payload is `v`                                        |
| `mut T`        | `M <type>`                                                                                        |
| `volatile T`   | `V <type>`                                                                                        |
| Back-reference | `R <n> _`, where `n` counts enclosing `A`, `F`, `O`, `Q`, or `N` types from zero, innermost first |

Each field or variant name is prefixed by its character count. Combined qualifiers encode as `M V <type>`. A compound
type structurally equal to an enclosing type uses a back-reference instead of unfolding, making recursive structural
types canonical. The logical symbol alphabet is ASCII letters, digits, and `_`; target object formats may apply their
ordinary external decoration.