<match>
Tier 1 pattern matching as a block. Structural exhaustiveness against an enum type; rules-inert; same state-children shape that promotes mechanically to <engine>.
Syntax
<match for=TypeName [on=expr]>
<Variant />
<OtherVariant payload />
...
</match>
for=
names the discriminating enum type. Every variant of that
type must have an arm or the compiler fires
E-MATCH-NOT-EXHAUSTIVE.
on=
picks the expression to match against; if omitted, the
block matches the auto-declared engine variable for that
type (typically the lowercased first-letter of the type
name).
There is also a JS-style form
match expr {...}
for value-return branching in expression position. The two
shapes coexist: the block-form <match> is the
canonical UI-tree shape; the JS-style form is the
canonical value-return shape. Both check exhaustiveness.
See SPEC §18 for the JS-style grammar.
Worked example
A loading-state pattern. One enum, one match block, four arms — the compiler enforces that every variant has UI.
type Phase:enum = { Idle, Loading, Error(msg: string), Success(count: int) }
<phase> = .Idle
<match for=Phase>
<Idle>
<button onclick=${@phase = .Loading}>Load</button>
</Idle>
<Loading>
Loading...
</Loading>
<Error msg>
<div>${msg}</div>
</Error>
<Success count>
Got it: ${count} rows
</Success>
</match>
.Error
and .Success
carry payload; the arm binds it positionally
(<Error msg>,
<Success count>)
and the body reads it bare. Per SPEC §18.0.3 + §18.7.
Semantics
-
Exhaustiveness is structural. The
compiler reads the enum's variant list and requires an
arm per variant. Missing arms fire
E-MATCH-NOT-EXHAUSTIVE.
A
_wildcard arm covers the residual. -
Rules are inert.
rule=on a <match> arm is accepted syntactically but does NOT enforce transitions — the surface is the <engine> feature. The compiler fires W-MATCH-RULE-INERT as a warning nudging toward promotion. Per SPEC §18.0.2. -
effect=and<onTransition>are forbidden. <match> is pass-through case analysis — state-machine effects belong on <engine>. Fires E-MATCH-EFFECT-FORBIDDEN or E-MATCH-ONTRANSITION-FORBIDDEN. -
Bare-variant inference. Arm patterns
may omit the type qualifier
(
<Idle>not<Phase.Idle>) becausefor=Phasefixes the scope. Per SPEC §14.10 + §18.0.3. -
Promotion is mechanical.
bun scrml promote --matchrewrites a <match> block to an <engine> in place. State-children carry verbatim; the wrapper tag changes. Per SPEC §56.
Errors this feature can fire
- E-MATCH-NOT-EXHAUSTIVE
- W-MATCH-RULE-INERT
- E-MATCH-EFFECT-FORBIDDEN
- E-MATCH-ONTRANSITION-FORBIDDEN
- E-VARIANT-AMBIGUOUS
- I-MATCH-PROMOTABLE
Edge cases
-
The
on=expression is reactive. Whenon=reads reactive cells, the <match> block re-evaluates on change. Withouton=, the block tracks the auto-declared engine variable for itsfor=type. -
JS-style
match expr {...}does NOT promote directly. Its semantic is value-return, not state-machine. If the value-return logic accumulates transition shape, hoist into a block-form <match for=Type> first, then runbun scrml promote. -
An if-else chain over enum variants is also
promotable.
if (@phase == .Idle) ... else if (@phase == .Loading) ...fires I-MATCH-PROMOTABLE info-level lint at the discrimination site. Runbun scrml promote --match <file>to lift mechanically. Per SPEC §56.
Related features
-
<engine>
— Tier 2 sibling. Same state-children
shape; rules ACTIVE; transitions enforced;
<onTransition>+effect=allowed. -
JS-style
match expr {...}— value-return form. Same exhaustiveness check against the discriminating type. - if= / show= — Tier 0 unstructured branching. No exhaustiveness guarantee; promotes to <match> via the I-MATCH-PROMOTABLE info-level lint.
- <errors of=expr/> — the canonical way to render the ValidationError variants when a cell's validators fail. Often appears alongside <match> on form pages.
Availability
| Surface | Since | Notes |
|---|---|---|
| <match for=Type> block | S57 D2.8 (2026-05-04) | Spec §18.0.1; parser+typer A1b B15-style |
| JS-style match expr { } | v0.2 | Pre-existing; ratified L8 — two shapes coexist |
| bun scrml promote --match | S66 (Tier B SHIPPED 2026-05-07) | CLI subcommand; idempotent; --dry-run supported |
| I-MATCH-PROMOTABLE info lint | S66 (2026-05-07) | Predicate matrix supports == and is .V at the discrimination site |
Specification
This page summarizes SPEC §18 (Pattern Matching and Enums) plus §56 (Promotion Ergonomics). The normative text lives at compiler/SPEC.md in the scrmlTS repository. When this page disagrees with SPEC.md, SPEC.md is authoritative — surface the contradiction and we'll fix the docs.
Quick-lookup anchors: SPEC-INDEX.md entries — match block-form <match for=Type>, match attribute legality, bare-variant inference (match arm patterns), I-MATCH-PROMOTABLE, bun scrml promote --match.