Iter 15e: render is the exact inverse of parse — CLI hygiene
The CLI help text claimed `render` was symmetric to `parse`, but `render` was wired to ailang_core::pretty::module (an older human-pretty form) while `parse` consumed form (A). Two different "text projections" coexisted under one name. Fix: Cmd::Render and Cmd::Describe (both branches) now call ailang_surface::print, the actual inverse of `parse`. Round-trip gate via `ail render | ail parse` is now an e2e test in crates/ail/tests/e2e.rs in addition to the existing unit-level round-trip across all 25 fixtures in ailang-surface/tests. Cleanup: `ailang_core::pretty::module` and its three private helpers (`def_block`, `term_block`, `term_inline`) deleted — ~260 LOC of duplicate-purpose code removed. pretty.rs goes from 457 to 196 LOC. Surviving surface is intentionally narrow: manifest, type_to_string, pattern_to_string — the diagnostic stringification used in error messages, where one-line ML notation reads better than form (A)'s nested S-expressions. Module-level doc rewritten to nail down the single-purpose framing. Tests: 89/89 (e2e +1, ailang-core unit -1 since the deleted test exercised the deleted fn). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -2606,3 +2606,67 @@ the CLI. Logged as 15e.
|
||||
**Queue update.** 15d done; remaining queue: 15e (CLI render/parse
|
||||
symmetry — small, just discovered), then `std_pair` if more stdlib
|
||||
is wanted, then 16a/16b language gaps.
|
||||
|
||||
---
|
||||
|
||||
## Iter 15e — `render` is the inverse of `parse` (CLI hygiene)
|
||||
|
||||
**Trigger.** Discovered during 15d: `ail render | ail parse` did not
|
||||
round-trip. The help text claimed they were inverses but `render`
|
||||
called `ailang_core::pretty::module` (an old human-readable
|
||||
S-expression-ish form), while `parse` consumes form (A). Two
|
||||
different "text projections" lived in the codebase, one of them
|
||||
exposed via the CLI under a name that promised inversion.
|
||||
|
||||
The form-(A) printer in `ailang_surface::print` was already correct
|
||||
and gated by `crates/ailang-surface/tests/round_trip.rs` across
|
||||
every fixture (25 modules at the time of writing) — it was simply
|
||||
not exposed at the CLI surface.
|
||||
|
||||
**Changes.**
|
||||
|
||||
1. `Cmd::Render` now calls `ailang_surface::print(&m)`. Help text
|
||||
updated to state explicitly: form (A), exact inverse of `parse`,
|
||||
round-trippable.
|
||||
2. `Cmd::Describe` (both single-module and `--workspace` branches)
|
||||
likewise switched to `ailang_surface::print` so that "text view
|
||||
of one def" means the same thing everywhere in the CLI.
|
||||
3. `ailang_core::pretty::module` deleted. With `module` gone its
|
||||
helpers (`def_block`, `term_block`, `term_inline`) became dead
|
||||
weight — also deleted. ~260 LOC of duplicate-purpose code gone;
|
||||
`crates/ailang-core/src/pretty.rs` shrank from 457 to 196 LOC.
|
||||
4. The remaining surface of `ailang_core::pretty` — `manifest`,
|
||||
`type_to_string`, `pattern_to_string` — is the diagnostic
|
||||
stringification surface (used in error messages and the
|
||||
`ail manifest` summary, where one-line ML notation is more
|
||||
readable than form (A)'s nested S-expression). Module-level
|
||||
doc rewritten to make this single-purpose framing explicit;
|
||||
no more "pretty-printer" / "render" overloading.
|
||||
5. New e2e test `render_parse_round_trip_canonical` (in
|
||||
`crates/ail/tests/e2e.rs`) gates the CLI shell pipeline:
|
||||
shell out `ail render <fixture>` → write to tmp .ailx →
|
||||
shell out `ail parse <tmp>` → assert canonical-byte equality
|
||||
with the original fixture. The unit-level round-trip in
|
||||
`ailang-surface/tests/round_trip.rs` covered the printer
|
||||
function directly; this new test additionally guards the
|
||||
CLI wiring.
|
||||
6. The `ailang_core::pretty` unit test `pretty_print_does_not_panic`
|
||||
exercised the deleted `module` fn — removed. `manifest_contains_
|
||||
type_and_hash` stays.
|
||||
|
||||
**Doctrinal pin.** Form (A) is the only round-trippable text form.
|
||||
The diagnostic stringification in `ailang_core::pretty` is
|
||||
asymmetric and lossy by design — it exists for the *limited*
|
||||
purpose of sticking a type or pattern into an error message in
|
||||
human-friendlier shape than form (A). It does not roundtrip and
|
||||
must not be used as an authoring or persistence target. Any
|
||||
future add to it should add to that purpose, not back-fill toward
|
||||
"another text projection".
|
||||
|
||||
**Tests: 89/89.** (e2e went from 31 to 32; ailang-core unit
|
||||
tests went from 11 to 10 — the deleted unit test exercised the
|
||||
removed fn. Net same.)
|
||||
|
||||
**Cumulative state, post-15e.** No new language features. Two
|
||||
canonical text projections collapsed to one (form A). Internal
|
||||
cleanup; no behavioural change for any program in the repo.
|
||||
|
||||
Reference in New Issue
Block a user