Files
AILang/docs/journals/2026-05-18-iter-prose-loop-binders.1.md
T
Brummel c9355d7d58 iter prose-loop-binders.1: Form-B loop binders as parenthesised init-list
The Term::Loop arm of write_term rendered binders as bare
`name = init;` statements inside the `loop { … }` body block, which
reads as C/Rust re-init-every-iteration semantics — a projection
lying about a body the prose surface exists to let the reader trust.
Rewrite to a parenthesised init-list on the keyword line,
`loop(acc = 0, i = 1) { … }`, positionally isomorphic to the
unchanged Term::Recur arm. Projection-only: loop/recur AST, Form-A,
JSON-AST, typecheck, codegen, and the Form-A↔JSON round-trip
invariant untouched. RED-first via two new committed
examples/*.prose.txt byte-equality snapshots + two snapshot_loop_*
tests; full ailang-prose suite 10/0; both ail-prose CLI byte-matches
green. Single-iteration milestone, brainstorm→plan→implement.

Spec: docs/specs/2026-05-18-prose-loop-binders.md
Plan: docs/plans/prose-loop-binders.1.md
2026-05-18 01:04:19 +02:00

73 lines
2.9 KiB
Markdown

# iter prose-loop-binders.1 — Form-B `loop` renders binders as a parenthesised init-list on the keyword
**Date:** 2026-05-18
**Started from:** 6533134dab888605c24fb2e50a65fcbf99c1897e
**Status:** DONE
**Tasks completed:** 2 of 2
## Summary
Projection-only single-iteration milestone in `ailang-prose`. The
`Term::Loop` arm of `write_term` (`crates/ailang-prose/src/lib.rs`)
now renders loop binders as a parenthesised init-list on the keyword
line — `loop(acc = 0, i = 1) { … }` — instead of bare
`name = init;` statements inside the body block. The old shape
implied C/Rust re-init-every-iteration semantics; the new shape
mirrors the adjacent (untouched) `Term::Recur` arm's
`enumerate()` + `", "`-separator idiom and renders init expressions
at `level` (they sit on the keyword line, not the indented block).
RED-first: two committed `examples/*.prose.txt` snapshot fixtures
plus two `check_snapshot`-calling `#[test]` fns were added and
verified failing against the old renderer before the arm rewrite
made them pass. Loop/recur AST, Form-A, JSON-AST, typecheck,
codegen and the Form-A↔JSON round-trip invariant are untouched by
construction (single render-arm body rewrite, no signature change,
no caller touched).
## Per-task notes
- iter prose-loop-binders.1.1: RED — created
`examples/loop_sum_to_run.prose.txt` (multi-binder + non-recur
exit) and `examples/loop_forever_build.prose.txt` (single-binder
recur-only) with the exact Option-A bytes from the plan; appended
`snapshot_loop_sum_to_run` + `snapshot_loop_forever_build` after
`snapshot_ordering_match` in `tests/snapshot.rs`. `cargo test -p
ailang-prose snapshot_loop``0 passed; 2 failed; 8 filtered
out` (filter resolved to exactly the two new tests; both panic
with the expected `prose snapshot mismatch` message). RED
confirmed.
- iter prose-loop-binders.1.2: GREEN — rewrote the `Term::Loop`
arm at `lib.rs:938-955` verbatim per the plan (parenthesised
init-list, init at `level`, stale "not yet designed" comment
removed). `cargo test -p ailang-prose snapshot_loop``2
passed; 0 failed`; full `ailang-prose` suite → `10 passed; 0
failed` (no pre-existing snapshot regressed); both `ail prose |
diff` CLI byte-matches → `MATCH`; post-cleanup `git status
--porcelain` is EXACTLY the four expected paths.
## Concerns
(none)
## Known debt
(none — projection-only single-arm rewrite, fully gated by
whole-file byte-equality snapshots + live-CLI diff)
## Files touched
- `crates/ailang-prose/src/lib.rs``Term::Loop` arm of
`write_term` rewritten (single hunk, lines 938-953)
- `crates/ailang-prose/tests/snapshot.rs` — two `#[test]` fns
appended after `snapshot_ordering_match`
- `examples/loop_sum_to_run.prose.txt` — new committed snapshot
- `examples/loop_forever_build.prose.txt` — new committed snapshot
## Blocked detail
(n/a — Status DONE)
## Stats
bench/orchestrator-stats/2026-05-18-iter-prose-loop-binders.1.json