@@ -198,32 +198,52 @@ a degenerate always-`OK`/always-`CLEAN` tool is caught without the corpus gate);
198198corpus gates run with ` -- --ignored ` (` lexer_parity_corpus ` , ` parser_parity_corpus ` ,
199199` checker_parity_corpus ` , ` lexer_perf_corpus ` ).
200200
201- ### Findings (ledger ` SH-016 ` … ` SH-023 ` )
202- - ** SH-016** — no character-literal syntax; ` ' ` lexes to ` ? ` , cascading a misleading
203- ` RS0013 ` . * (language + diagnostics)*
204- - ** SH-017** — statement-level binary-operator expressions can't cross a newline; the
205- leading-operator form ** compiles but is silently wrong** . * (language + correctness-grade
206- diagnostics)*
207- - ** SH-018** — no cursor/state object (no methods/` impl ` , ` mut ` params can't advance a
208- cursor); stateful passes thread state positionally. * (language ergonomics)*
209- - ** SH-019** — a ` fresh ` -returning fn can't build its result via ` mut ` + ` List.push `
210- (` RS0601 ` ). * (analyzer/freshness ergonomics)*
211- - ** SH-020** — recursive descent must encode ` (ok, new-index) ` as a sentinel ` Int ` . * (ergonomics)*
212- - ** SH-021** — ` parse_source_raw ` defers body validation, so recognition parity under-tests
213- the grammar (deep grammar is enforced in the analyzer, not the parser). * (methodology)*
214- - ** SH-022** — ** the headline perf result:** the self-hosted lexer is ~ 5100× slower on the
215- reg-VM than native Rust (79.5 s vs 15.3 ms over 712 KB). A controlled ` String.concat ` (O(n²))
216- → ` StringBuilder ` (O(n)) swap moved nothing, isolating the cost to ** per-character intrinsic
217- dispatch** (` List.get ` on ` List<Char> ` + ` Char.* ` peeks — VM value-representation +
218- intrinsic-dispatch overhead), not string building. * (VM + stdlib)*
219- - ** SH-023** — the checker reaches ` RS0005 ` parity; the load-bearing rule is the analyzer's
220- ** merged callable namespace** (fn names + type-constructor names collide). * (insight)*
221-
222- ### Highest-ROI next lever (from the data)
223- SH-022 is the first real workload that unambiguously profiles as ** VM-dispatch-bound** . The
224- indicated fix is a native ** string char/byte-cursor intrinsic** (iterate a ` String ` without
225- materializing a boxed ` List<Char> ` ) plus lower per-intrinsic dispatch cost — this feeds the
226- parked collection-representation / perf roadmap with real-workload evidence. Deeper checker
227- passes (name resolution, exhaustiveness) are the natural next self-hosting step but require a
228- real expression/statement/pattern parser (the depth ` parse_source_raw ` let Phase 2 skip —
229- SH-021).
201+ ### Findings (ledger ` SH-016 ` … ` SH-023 ` ) — historical; current status per item
202+
203+ These are the findings the stress test surfaced. ** All of the actionable ones have
204+ since been fixed or closed** — the table above (556/556, ~ 46×) is the current state;
205+ the list below records what each finding was and where it landed. See the linked
206+ ledger entry for the full write-up.
207+
208+ - ** SH-016** — * (was)* no character-literal syntax; ` ' ` lexed to ` ? ` , cascading a
209+ misleading ` RS0013 ` . ** FIXED** — ` 'x' ` is a real ` Char ` value end-to-end (and a
210+ stray out-of-inventory char now lexes to an ` Unknown ` token the parser reports,
211+ not ` ? ` ; empty/multi-char literals are ` RS0038 ` ). * (language + diagnostics)*
212+ - ** SH-017** — * (was)* statement-level binary-operator expressions couldn't cross a
213+ newline; the leading-operator form compiled but was silently wrong. ** FIXED** —
214+ operator-continuation lexing is supported. * (language + correctness diagnostics)*
215+ - ** SH-018** — * (was)* no cursor/state object; ` mut ` params couldn't advance a
216+ cursor. ** FIXED** — scalar-` Copy ` ` mut ` params are reassignable with caller
217+ write-back (and, as of this review, ` mut ` field/element * places* are written back
218+ too, on both backends). * (language ergonomics)*
219+ - ** SH-019** — * (was)* a ` fresh ` -returning fn couldn't build its result via ` mut ` +
220+ ` List.push ` (` RS0601 ` ). ** FIXED** — managed fresh bindings survive the flow merge.
221+ * (analyzer/freshness)*
222+ - ** SH-020** — * (was)* recursive descent had to encode ` (ok, new-index) ` as a
223+ sentinel ` Int ` . ** CLOSED** — not a real gap; tuple returns work (the original
224+ over-claim was corrected). * (ergonomics)*
225+ - ** SH-021** — ` parse_source_raw ` defers body validation, so recognition parity
226+ under-tests the grammar (deep grammar is enforced in the analyzer, not the
227+ parser). ** Accepted methodology limitation** — partly mitigated by the
228+ non-ignored negative-parser / positive-` RS0005 ` smoke tests. * (methodology)*
229+ - ** SH-022** — * (was)* the self-hosted lexer was ~ 5100× slower on the reg-VM than
230+ native Rust. ** FIXED (→ ~ 46×).** NOTE: the original "per-character intrinsic
231+ dispatch" hypothesis was ** wrong** ; the real root cause was ** O(n²)** — every
232+ lexer helper's ` read List<Char> ` param got an eager prologue ` DeepCopy ` that the
233+ elision pass KEPT (taint flowed through ` List.get ` to the extracted ` Char ` , and
234+ ` Char.* ` were classified ` Keep ` ). The fix classifies the pure scalar ` Char.* `
235+ intrinsics as ` PureFreshReader ` so the copy is elided (VM-only, parity-safe):
236+ lexer/VM 79.5 s → 732 ms (~ 108×), VM-vs-native 5100× → ~ 45.6×. * (VM elision)*
237+ - ** SH-023** — the checker reaches ` RS0005 ` parity; the load-bearing rule is the
238+ analyzer's ** merged callable namespace** (fn names + type-constructor names
239+ collide). * (insight)*
240+
241+ ### Current residual perf problem (separate from SH-022)
242+ With SH-022's O(n²) removed, the remaining VM-vs-native gap is a flat ** ~ 46×**
243+ general per-op tax (HashMap/` Handle ` /` Rc<RefCell> ` per op + per-intrinsic dispatch),
244+ not an algorithmic blowup — real code (e.g. the mailbox) already runs ~ 2.4× native.
245+ The only remaining lever is a ` TypedMap ` /` TypedSet ` representation rewrite (parked;
246+ ~ 10–15% on collection-bound micro-kernels, med-high risk), tracked in the perf
247+ roadmap. Deeper checker passes (name resolution, exhaustiveness) are the natural
248+ next self-hosting step but need a real expression/statement/pattern parser (the
249+ depth ` parse_source_raw ` let Phase 2 skip — SH-021).
0 commit comments