Procházet zdrojové kódy

docs: session summary for two-phase parse milestone 1 (2026-10-15)

Eric Streit před 2 dny
rodič
revize
e933b7d5b9
1 změnil soubory, kde provedl 102 přidání a 0 odebrání
  1. 102 0
      docs/summary_two-phase-m1-2026-10-15.md

+ 102 - 0
docs/summary_two-phase-m1-2026-10-15.md

@@ -0,0 +1,102 @@
+# Session summary — 2026-10-15: two-phase parse, milestone 1 (probe)
+
+Branch **`resolve-check`**, HEAD `6c64b46`, tag **`v3-two-phase-m1`**.
+Suite **196/196**; fixpoint **OK (3,517,333 bytes)**; tree clean.
+
+Design doc: `docs/plan-two-phase-parse.md` (now carries a Progress section).
+Previous session: `docs/summary_resolve-check-2026-10-15.md` (step 4d,
+the conclusion that `FwdVar*` can only die with a two-phase parse).
+
+## Goal of the thread
+
+Delete `SymTab.FwdVarRef`/`FwdVarName`/`FwdVarResolve`,
+`Check.NoteForward`/`FlushForward`, the `Design` forward branch and the
+`Op=1` marker — by parsing module-level declarations before procedure
+bodies, so a forward reference binds normally instead of being deferred.
+
+## What milestone 1 landed (all green)
+
+Each outermost procedure/method body is **shadow-skipped at the token
+level and the skip verified before the body parses normally**, behind
+`-twophase` (default off — fully inert):
+
+| Piece | File | What |
+| --- | --- | --- |
+| State save/restore | `compiler/src/scanner.frm` | `PushPos`/`PopPos`: full scanner state (cursor, all published positions, `errors`) on an 8-deep stack |
+| Switch + helpers | `compiler/src/M2.atg` | `SetTwoPhase`, `procNest` (hooked once in `Block`, so `ProcDecl` *and* method bodies probe), `TokIs` (token-*text* compare), `Adv`, `ProbeBody` (opener counting + `END <name>` check) |
+| Flag plumbing | `compiler/src/compiler.frm`, `parser.frm` | `-twophase` → `M2P.SetTwoPhase` at both driver `Parse` sites |
+| Gate | `compiler/run_tests.sh` | `twophase_same`: `.ssa` byte-compared flag-off vs flag-on (3 files) |
+| Generated fallout | `compiler/src/M2.lst` | Coco/R listing regenerated (line shifts only) |
+
+Opener set: `MODULE` (nested modules), `PROCEDURE`, `CLASS` (incl.
+`CLASS IMPLEMENTATION`), `RECORD` (incl. variant `CASE`), `IF`, `CASE`,
+`WHILE`, `FOR`, `LOOP`, `WITH`. `BEGIN` is not an opener;
+`REPEAT…UNTIL` needs none. The probe is silent on success; a bad skip
+prints `twophase probe mismatch` to StdOut — never into the listing.
+
+## Verification
+
+- `./build.sh` + `./run_tests.sh` → **196/196** (193 + 3 probe gates).
+- Flag-on sweep: all **142 single-file tests** plus session
+  spot-checks (`DBasicProg`, `TString`, `Showcase12`, `Library1`) and
+  the compiler's own sources (`SymTab.mod`, `M2P.mod`, `Lower.mod`)
+  produce **byte-identical `.ssa`/`.LST`**, zero mismatches.
+- Positive control: a temporary success print proved the probe fires
+  exactly when the flag is on (then reverted).
+- `bootstrap/fixpoint.sh` → **FIXPOINT OK** (3,517,333 bytes).
+
+## Finding worth keeping (V3 name resolution)
+
+The first cut called the frame's `Get` from the new atg helper. gm2
+accepts it (whole-module scope), but the self-hosted V3 compiler
+resolves **single-pass**: the bare `Get` bound the *imported*
+`M2S.Get(VAR sym)` and stage 2 failed with 233s (plus knock-on 201s at
+`END M2P`). Fix: advance via `Adv` (`M2S.Get(sym); INC(errDist)` —
+exactly the frame's `Get` body for this pragma-free grammar, where the
+scanner never returns a token above `maxT`). **Rule going forward:
+atg helpers must never call a later-declared frame procedure by a name
+that collides with an import.** (Same family as the known
+declaration-before-use constraint on `Check`.)
+
+## What is next (milestone 2)
+
+Deferral + body re-parse, still behind the flag, byte-compared:
+
+1. **Record body spans** in the probe: table of (procedure name, start
+   `nextPos`) for outermost bodies; dump it in diagnostic mode and
+   calibrate (stability across the suite is the gate).
+2. **Restart mechanism** — two candidates, decision open:
+   - *(a, recommended)* driver-level replay: `M2S.Reset` + repeated
+     `Get` to the recorded offset (reproduces exact scanner state,
+     incl. `pos`/`len`, with no new scanner internals). Caveat: `Reset`
+     re-reads the `src` handle — check `FileIO` reposition semantics
+     or reopen the file per body.
+   - *(b)* scanner `SeekTo(p)` with line recompute (plan's original
+     piece 1); must handle the stale `pos`/`len` model (they describe
+     the *previous* token — see the resolve-check summary §"scanner's
+     position model").
+3. **Body-entry production**: parse one `Block` for an already-entered
+   heading at end of unit, walking the span table; bodies then see all
+   module-level declarations.
+4. **Flip + delete**: default on when suite and fixpoint byte-compare;
+   then delete `FwdVar*`, `NoteForward`/`FlushForward`, the `Design`
+   forward branch and the `Op=1` marker (the §9 list in
+   `docs/plan-resolve-check.md`, plus `PushPos`/`PopPos`/`ProbeBody`
+   if unused).
+
+Watch items: nested-module procedures (probe covers them; decide
+whether deferral does), generic re-parse (`DoInst` interplay),
+`errDist` save/restore across restarts (error suppression must not
+shift), the `M2.lst` churn convention (commit it with the `.atg`).
+
+## Resume
+
+```sh
+cd .../m2compiler-V3
+git checkout resolve-check          # HEAD 6c64b46, tag v3-two-phase-m1
+cd compiler && ./build.sh && ./run_tests.sh   # 196/196
+cd .. && ./bootstrap/fixpoint.sh    # FIXPOINT OK
+```
+
+Probe check on any file: `./M2 -twophase tests/<f>.mod` — identical
+`.ssa`, no `twophase probe mismatch` on StdOut.