Skip to content

Commit 5fbecd6

Browse files
olwangclaude
andcommitted
feat(selfhost): AST producer declaration items — struct/sum/const/alias/module/use → 121/563
Extends astdump.rss from a function-only core to full declaration-level coverage: - struct/class/resource: opaque, generic params + bounds (managed/struct/resource/ protocol), derives(...), handle/weak fields, field defaults, drop bodies. - sum: variants with fields. - const, type-alias (with generics), module, use (glob + `as` alias). - functions now emit generic params too. Driver dispatch mirrors the reference parse_program order. protocols/impls/ native-modules are skipped (they dump in a separate program section, not source order, so streaming can't place them — SH-025). Corpus reach: 58 -> 121 / 563 byte-exact, still 0 run-failures. Floor ratcheted to 121. Six curated samples/ast/* (functions, control, logic, structs, sums, decls) byte-exact and gating non-ignored. All 9 non-ignored selfhost tests green. Risks closed: curated fast gate (ast_parity_samples) mitigates corpus-gate runtime; the module story is decided (commit to concatenation) in selfhost/AST_FORMAT.md. Residual grammar tracked as SH-025 in the ledger; plan + format docs updated. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
1 parent 5489d2b commit 5fbecd6

8 files changed

Lines changed: 401 additions & 11 deletions

File tree

crates/rsscript/src/selfhost_parity.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1510,7 +1510,7 @@ fn ast_parity_samples() {
15101510
/// Floor for `ast_parity_corpus` — the number of corpus files whose rss AST dump
15111511
/// already matches the oracle byte-for-byte. Ratchets up as the producer's
15121512
/// coverage grows; a drop signals a regression. (Full parity = files.len().)
1513-
const AST_CORPUS_PARITY_FLOOR: usize = 58;
1513+
const AST_CORPUS_PARITY_FLOOR: usize = 121;
15141514

15151515
/// Step-2 measurement gate (ignored by default): how many of the 556 corpus files
15161516
/// the rss producer already reproduces byte-for-byte. Not full parity yet — this

docs/ledgers/rss-selfhost-ledger.md

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -867,3 +867,35 @@ gap is VM value-representation / intrinsic-dispatch cost (the next big lever).
867867
- **Status:** fixed (feature): positional multi-field variant binding supported
868868
across all backends; RS0037 removed as a restriction and repurposed for arity;
869869
spec §20.1 amended.
870+
871+
### SH-025 — AST-dump parity: streaming rss producer at 121/563, residual grammar is the growing tail
872+
873+
- **Context:** step 2 of frontend object parity (after the AST-dump format +
874+
oracle keystone, SH-adjacent). `selfhost/astdump.rss` is a recursive-descent
875+
rss parser that STREAMS the canonical dump (`selfhost/AST_FORMAT.md`); the
876+
harness (`crate::selfhost_parity`) diffs it byte-for-byte against the Rust
877+
oracle over `parse_source_raw`.
878+
- **Reach:** 121 / 563 corpus files byte-exact, **0 run-failures** — the producer
879+
never crashes; unsupported constructs mismatch (partial/`unknown-*` markers)
880+
rather than panic. Curated `samples/ast/*.rss` (6 files: functions, effects,
881+
control flow, calls, structs+generics+derives+handle fields, sums, module/use/
882+
const/type-alias) are byte-exact and gate non-ignored; `ast_parity_corpus`
883+
(`#[ignore]`) ratchets the floor (currently 121).
884+
- **Covered:** top-level fns (pub/async/native, generic params + bounds, params
885+
with read/mut/take effects, generic-arg types, return type, body); struct/class/
886+
resource (opaque, generics, derives, handle/weak fields, defaults, drop); sum
887+
(variants + fields); const/type-alias/module/use; statements return/let/local/
888+
assign/if-else/while-loop/break/continue/expr; a split-at-last-top-level-operator
889+
expression parser matching the oracle's precedence, plus call (name/qualified/
890+
receiver, named + effect args), field/index, array, try `?`, parens, literals.
891+
- **Residual (the tail):** for-loops, match statements/expressions, closures,
892+
object/map literals, interpolated strings, `!`/`~` unary desugars, negative
893+
number literals, effect-receiver calls (`read x.m()`), fn attributes
894+
(`#deprecated`/`#lower_name`), effect/retains clauses, protocols/impls/
895+
native-modules (they dump in a separate program section, not source order, so
896+
streaming can't place them), and `statement_end` operator/postfix line
897+
continuation. Each is additive; the floor ratchets as they land.
898+
- **Status:** open (growing tail). The producer + parity gate + risk mitigations
899+
(curated fast gate; module-story decision recorded in AST_FORMAT.md) are in
900+
place; full 556-file byte parity is incremental, tracked by the ratcheting
901+
floor.

docs/self-hosting-stress-test-plan.md

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -275,3 +275,19 @@ first. Two risks to treat as their own line items when `parser.rss` starts emitt
275275
AST: the `scan.rss`-prepend hack (no module/import story) becomes a scaling pain once
276276
an AST type module is added; and corpus-gate runtime (AST dumps ≫ token dumps) will
277277
likely want a sampled fast inner-loop gate plus the full corpus pre-push.
278+
279+
**Step-2 producer shipped (in progress, ratcheting).** `selfhost/astdump.rss` is a
280+
recursive-descent rss parser that STREAMS the canonical dump (no handle-based AST is
281+
materialized). Parity harness: `ast_parity_tiny_sample` + `ast_parity_samples`
282+
(non-ignored, byte-exact vs the oracle over curated `samples/ast/*`) and
283+
`ast_parity_corpus` (`#[ignore]`, ratchets a floor over all 563 files). Current
284+
reach: **121/563 byte-exact, 0 run-failures** (the producer never crashes;
285+
unsupported constructs mismatch rather than panic). Covered: fns (generics/effects/
286+
return/body), struct/class/resource (opaque/generics/derives/handle-weak/defaults/
287+
drop), sum, const/type-alias/module/use, the core statements, and a precedence-exact
288+
expression parser (calls, field/index, array, try, effects, literals). Both risks are
289+
handled: the curated set is the fast inner-loop gate; the module story is decided in
290+
`selfhost/AST_FORMAT.md` (commit to concatenation). The residual grammar (for/match/
291+
closures/object-map/interp/unary-desugars/effect-receiver/attributes/protocols/
292+
line-continuation) is the additive tail, tracked as **SH-025** and gated by the
293+
ratcheting floor.

selfhost/AST_FORMAT.md

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,23 @@ Binary op names: `add subtract multiply divide modulo bit-and bit-or bit-xor
152152
shift-left shift-right equal not-equal less less-equal greater greater-equal
153153
logical-and logical-or`.
154154

155+
## Producer & the module-story decision
156+
157+
The rss producer is `selfhost/astdump.rss`, a recursive-descent parser that
158+
**streams** this dump (the dump is a pre-order traversal, so no handle-based AST is
159+
materialized — each parse fn emits its node line(s) at a threaded depth and returns
160+
the next token index). It reuses the shared `scan.rss` tokenizer/accessors, which
161+
the harness prepends at compile time.
162+
163+
**Decision (module story):** the single-file VM model still has no cross-file
164+
import, so — like the lexer/parser/checker — `astdump.rss` is authored as one file
165+
and concatenated after `scan.rss` by the harness. We commit to concatenation for
166+
now rather than blocking AST parity on a new language module feature; if the
167+
producer grows unwieldy, the mitigation is to split the *Rust-side* corpus gate
168+
into sampled + full tiers (already done: curated `samples/ast/*` is the fast
169+
non-ignored gate, the full corpus is `#[ignore]`), not to invent an import system.
170+
Revisit only if a genuine multi-file need appears.
171+
155172
## Oracle
156173

157174
`crate::syntax::parse_source_raw` (never the desugared `parse_source`) is truth.

0 commit comments

Comments
 (0)