You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
To eliminate the block-vs-record-literal parser ambiguity (families
C+D of #215) structurally rather than by a human-facing lookahead
heuristic, AffineScript moves to a Rust-like model:
{ in expression position is ALWAYS a block.
Record/struct literals use the #{ … } sigil — both anonymous
(#{ x: 1 }) and typed (Foo #{ x: 1 }). This also removes the
Rust struct-literal-in-if/match-scrutinee hazard entirely.
Record patterns (match x { Foo { a } => … }) are unaffected —
pattern position has no block alternative, so no ambiguity there.
Owner-approved (2026-05-18). Supersedes the lookahead-heuristic option.
Status of the grammar change
Implemented and correct on branch stage-c/pc-brace-disambig: HASH_LBRACE token (token.ml), #{ lexer rule (lexer.ml), both ExprRecord productions rerouted (parser.mly). Conflicts dropped
72→68 S/R, 10→7 R/R, build clean. Not merged — breaking; needs the
migration to land atomically with it.
Scope (true cost, measured)
~60 of 353 .affine files in the affinescript repo use the old
record syntax (test fixtures, golden oracles, examples, stdlib) —
21 tests currently fail (expected, pre-migration).
Wider estate.affine files on top of that.
A residual reduce/reduce remains even after migration
(state 401, LBRACE IF expr block option(else_part) — a distinct if-expr-as-statement ambiguity, family-D-residual) plus ~68 S/R;
tracked as follow-on families, NOT blocking this migration.
Plan
Codemod (linchpin): instrument the origin/main parser (old
grammar still parses old syntax) to emit each ExprRecord's LBRACE byte-offset per file; a script inserts # at those
offsets (descending). Precise — only true record literals, never
blocks/declarations/match/if. Validate on a sample.
Atomic affinescript PR: grammar/lexer/token change
(stage-c/pc-brace-disambig) + codemod-migrated repo .affine
(stdlib + tests + examples + golden) so the 257 gate goes green
with the new syntax. Conflict delta reported.
Estate sweep: run the codemod across all estate .affine
repos, one PR per repo (or batched), each gated.
Decision
To eliminate the block-vs-record-literal parser ambiguity (families
C+D of #215) structurally rather than by a human-facing lookahead
heuristic, AffineScript moves to a Rust-like model:
{in expression position is ALWAYS a block.#{ … }sigil — both anonymous(
#{ x: 1 }) and typed (Foo #{ x: 1 }). This also removes theRust struct-literal-in-
if/match-scrutinee hazard entirely.match x { Foo { a } => … }) are unaffected —pattern position has no block alternative, so no ambiguity there.
Owner-approved (2026-05-18). Supersedes the lookahead-heuristic option.
Status of the grammar change
Implemented and correct on branch
stage-c/pc-brace-disambig:HASH_LBRACEtoken (token.ml),#{lexer rule (lexer.ml), bothExprRecordproductions rerouted (parser.mly). Conflicts dropped72→68 S/R, 10→7 R/R, build clean. Not merged — breaking; needs the
migration to land atomically with it.
Scope (true cost, measured)
.affinefiles in the affinescript repo use the oldrecord syntax (test fixtures, golden oracles, examples, stdlib) —
21 tests currently fail (expected, pre-migration).
.affinefiles on top of that.(state 401,
LBRACE IF expr block option(else_part)— a distinctif-expr-as-statement ambiguity, family-D-residual) plus ~68 S/R;tracked as follow-on families, NOT blocking this migration.
Plan
grammar still parses old syntax) to emit each
ExprRecord'sLBRACEbyte-offset per file; a script inserts#at thoseoffsets (descending). Precise — only true record literals, never
blocks/declarations/match/if. Validate on a sample.
(
stage-c/pc-brace-disambig) + codemod-migrated repo.affine(stdlib + tests + examples + golden) so the 257 gate goes green
with the new syntax. Conflict delta reported.
.affinerepos, one PR per repo (or batched), each gated.
R/R + remaining S/R → continue Eliminate all Menhir parser conflicts (75 S/R + 10 R/R) — dedicated grammar-conflict workstream #215 family work.
#{.Done when
#{is the sole record-literal syntax estate-wide, affinescript 257gate green, conflict count reported, residual families re-listed on
#215.
🤖 Generated with Claude Code