Selaa lähdekoodia

housekeeping: refresh README + STATUS to current state, add docs/INDEX.md

README: layout and language status updated (219/219, fixpoint 3,714,376
bytes, corpus 372/612; classes, coroutines, Unicode, type conversions,
generics; two-phase parse + Lower-only architecture; -notwophase).
STATUS: rewritten as a current snapshot (was dated 2026-10-08, 184/184).
docs/INDEX.md: navigation to the load-bearing docs (no history deleted).
Eric Streit 10 tuntia sitten
vanhempi
commit
7cbf7cf64c
3 muutettua tiedostoa jossa 149 lisäystä ja 206 poistoa
  1. 37 19
      README.md
  2. 42 0
      docs/INDEX.md
  3. 70 187
      docs/STATUS.md

+ 37 - 19
README.md

@@ -34,31 +34,48 @@ usage/IO problems (no input, unopenable file) — no aborts.
 ## Layout (Blaise-adapted)
 
 ```text
-compiler/src/      M2.atg, frames, FileIO, SymTab, QbeGen (+ generated)
+compiler/src/      M2.atg, frames, FileIO, SymTab, QbeGen, Lower (+ generated)
 compiler/tests/    t_*.mod (check/reject/run) + showcase<N>.mod tours
 compiler/gen_ssa/  build outputs (gitignored)
 runtime/syslib/    always-linked runtime (SYSTEM, Storage, SysIO, …)
 stdlib/            opt-in libraries (Strings, TextIO, …; classic form)
-tools/             syntax helpers (redux-check direction)
+tools/             syntax helpers + v3-corpus (coverage harness)
 bootstrap/         stage1/2/3 + fixpoint.sh (self-hosting proof)
 vendor/            qbe toolchain pin
-docs/              plan.md, summary_stepN.md (one file per step)
+docs/              STATUS.md, plan.md, plan-*.md, analysis_*.md, summary_*.md
 ```
 
-## Language status (at v3-step4.3, 87/87 green)
+## Status (2026-10-16)
+
+- Suite **219/219**; self-hosting **fixpoint OK** (byte-identical
+  stage2/stage3, 3,714,376 bytes); corpus **372/612 compile-OK,
+  0 crashes** (`tools/v3-corpus`).
+- Active branch **`resolve-check`** (holds the AST/`Lower`/parse
+  refactors and generics).
 
 Lowers today: program modules; `CONST`/`VAR`/`TYPE` (scalars,
-subranges, enums declared, arrays, records, sets, pointers);
-`ARRAY`/`RECORD`/`SET`/`POINTER`, `WITH`, `IN`; whole
-array/record copy; `NEW`/`DISPOSE`; all scalar arithmetic,
-relations, boolean connectives; `IF/CASE/WHILE/REPEAT/LOOP/FOR`;
-procedures with value/`VAR` params, functions, recursion,
-`FORWARD`, nested procedures (static-link display); **separate
-compilation** (`lib.def lib.mod prog.mod` in one run → one image,
-`FROM`/`IMPORT`, qualified `L.x`, opaque-type completion).
-Parse-now/lower-later (230): enum literals, Clarion-form `CLASS`
-(declared + checked; class lowering pending), `HIGH`/`LEN`,
-procedure-type variables.
+subranges, enums, arrays, records incl. variants, sets, pointers);
+`ARRAY`/`RECORD`/`SET`/`POINTER`, `WITH`, `IN`; whole array/record
+copy; `NEW`/`DISPOSE`; all scalar arithmetic, relations, boolean
+connectives; `IF/CASE/WHILE/REPEAT/LOOP/FOR`, `GOTO`/labels;
+procedures with value/`VAR` params, functions, recursion, `FORWARD`,
+nested procedures (static-link display), procedure values;
+Clarion-form `CLASS` with methods, inheritance and virtual dispatch;
+PIM coroutines (`PROCESS`/`NEWPROCESS`/`TRANSFER`/`IOTRANSFER`);
+Unicode (`UCHAR` codepoints, `UString`, UTF-8 at the edges); ISO type
+conversions `T(x)` (incl. CONST folding); **separate compilation**
+(`lib.def lib.mod prog.mod` in one run → one image, `FROM`/`IMPORT`,
+qualified `L.x`, opaque-type completion); **generics** — ISO 10514-2
+refinement form (`GENERIC … MODULE M(T:TYPE)` + `MODULE X = M(actuals)`)
+with type/value/procedure parameters, constraints
+(`T : TYPE (ORDINAL|INTEGER|REAL|POINTER|SCALAR)`), nested generics,
+and generic classes.
+
+Architecture: a **two-phase parse** — each unit's procedure bodies are
+deferred and re-parsed at unit end, so forward references bind
+normally and the old forward-reference machinery is gone.  There is no
+separate resolve/check pass; `Lower` is the only emitter and walks the
+AST.  `-notwophase` restores the legacy inline parse (debug escape).
 
 Long-term rules already locked: every `ARRAY` is `LONGCARD` count
 + elements (all arrays, inline, element counts, no NUL);
@@ -70,7 +87,8 @@ byte-identical `.ssa` over three stages.
 
 - Grammar grows section by section in `compiler/src/M2.atg`
   (kept LL(1)-clean — Coco/R must report no errors).
-- Every step keeps the full suite green; per-step record in
-  `docs/summary_stepN.md`; `showcase<N>.mod` tours each stage.
-- Tags `v3-step1[.sub]` / `v3-step2` mark green states; no pushes
-  without asking (see `git.txt` for the remote recipe).
+- Every step keeps the full suite green; per-session record in
+  `docs/summary_*.md`; `showcase<N>.mod` tours each stage.
+  See `docs/INDEX.md` for the load-bearing docs.
+- Tags `v3-*` mark green states; no pushes without asking (see
+  `git.txt` for the remote recipe).

+ 42 - 0
docs/INDEX.md

@@ -0,0 +1,42 @@
+# docs/ index
+
+`docs/` has accumulated many per-session records.  This index points to
+the **load-bearing** documents; everything else is history (useful for
+bisecting *why* a decision was made, not for reading end-to-end).
+
+## Start here
+
+- **`STATUS.md`** — current state, architecture, what remains.
+- **`plan.md`** — the phased plan (Blaise-adapted).
+- **`features.md`** — the feature list.
+- **`analysis_gaps.md`** — language gaps + corpus notes.
+
+## Designs / running records
+
+- `analysis_generics.md` — generics (chosen ISO 10514-2 form, mechanism,
+  increments).
+- `plan-two-phase.md`, `plan-two-phase-parse.md` — the AST/`Lower` split
+  and the two-phase (deferred-body) parse.
+- `plan-resolve-check.md` — the resolve/check thread (now concluded; the
+  pass was deleted).
+- `plan-lower.md` — the `Lower` emitter.
+- `blaise-phases-map.md`, `language-report.md`, `grammar.md` — the
+  grammar/phases reference.
+
+## Recent session summaries (newest first)
+
+- `summary_dlist-showcase-2026-10-16.md` — showcase23 + limitation fixes.
+- `summary_generics-limitations-fixed-2026-10-16.md` — the two
+  template/proc-param limitations, fixed.
+- `summary_showcase23-dlist-2026-10-16.md` — the DList showcase + the
+  global-record data-size bug.
+- `summary_generics-closed-2026-10-16.md` — generics: what works, what
+  does not (generic classes: via generic modules; dedup: N/A).
+- `summary_generics-inc3-2026-10-16.md` — value params, kind
+  constraints, proc params, constraint model.
+- `summary_two-phase-complete-2026-10-16.md` — two-phase complete,
+  `Check` removed.
+
+Everything else (`summary_stepN.md`, `summary_two-phase-sliceN.md`,
+`summary_<topic>.md`, `session-*.md`, `session-handoff-*.md`) is a
+chronological record kept for provenance.

+ 70 - 187
docs/STATUS.md

@@ -1,203 +1,86 @@
-# m2compiler-V3 — status (2026-10-08)
+# m2compiler-V3 — status (2026-10-16)
 
-This answers "where are we after all the refactoring?".
+This answers "where are we now?".
 
-## MILESTONE (2026-10-08): L7 complete
+## Numbers
 
-**Lower is the only emitter**; the grammar's inline emit is gone from
-every production where it could be removed cleanly, `-lower` is retired,
-and the dead scaffolding is swept.  Verified:
+- Suite **219/219** (`compiler/run_tests.sh`).
+- Self-hosting **FIXPOINT OK** — stage2 and stage3 images are
+  byte-identical (3,714,376 bytes).
+- Corpus **372 / 612** sources compile with 0 errors, **0 crashes**
+  (`tools/v3-corpus/corpus.sh` over the gm2 testsuite); the rest are
+  genuine language gaps or unresolved imports.
+- Branch **`resolve-check`**; tree clean.
 
-- `run_tests.sh` is **184/184**.
-- `bootstrap/fixpoint.sh` is **FIXPOINT OK** (3,392,601 bytes).
+## Architecture (current)
 
-The L7 flip itself (2026-10-07) was a no-op because `Lower` had been
-verified byte-identical to the legacy inline emit on every single-file
-test and every session.  Since then:
-
-- the inline emit was deleted from statements, control flow,
-  declarations, expressions/designators, calls and `ProcHeading`;
-- a latent VAR-actual **note-ring bug** was found and fixed
-  (`RestoreSession` now clears the ring);
-- dead code was swept (tree-wide scan: 0 unreferenced procs);
-- `-lower` and the now-degenerate byte-compare tests were retired;
-- the **array-of-record inline length-word** bug was fixed (inline
-  expansion for small arrays, a generated run-time init for large ones);
-- **statement-context result suffixes** (`F()^.x := e`) were added;
-- **composite function results** (record/array/set, via sret) were added,
-  which also required storing a method's block declarations (fixing
-  methods with local variables);
-- **class results** and **chained post-call method calls** (`F().M()`)
-  were added;
-- **`GOTO`/labels** were added (the `Design` production was split into
-  `Design` + `DesignTail` to resolve the LL(1) label/designator clash).
-
-## TL;DR
-
-- **The compiler works and self-hosts today.**  `run_tests.sh` is
-  **184/184** and `bootstrap/fixpoint.sh` is **FIXPOINT OK**
-  (3,392,601 bytes, byte-identical stage2/stage3).
-- The **two-phase refactor (L0–L7) is done**: `Lower` emits the whole
-  session from the AST and is the only active emitter.
-- What remains is cleanup (delete the last suppressed writers +
-  `SaveSession`/`SetNoEmit`), language coverage (`GOTO`, generics,
-  chained post-call calls), and robustness — see "What remains" below.
-
-## What the refactor actually is
-
-There are **two ways** the compiler can turn Modula-2 into QBE IR:
-
-1. **Legacy "inline" emit** — the grammar emits QBE IR *while* it
-   parses.  This used to be the default; it now only runs suppressed
-   (its output is discarded) and is being deleted.
-2. **Lower (two-phase)** — the grammar builds an **AST**, and a
-   separate module `Lower` walks the AST and emits QBE IR.  This is
-   now the **only active emitter** ("the flip").
-
-The refactor is being done in slices:
-
-| phase | what | state |
-|---|---|---|
-| L0–L2 | scalars, control flow (`IF`/`WHILE`/`FOR`/…) | done |
-| L3 | procedures, calls, the self-host root-cause fix | done |
-| L4 | builtins, `CASE`, `WITH` | done |
-| L5 | records/arrays/pointers/sets/strings, literals | done |
-| L6 | nested modules, classes, qualified names | done |
-| **L7** | **the flip: Lower emits the whole session** | **done** (flip landed 2026-10-07) |
-
-Everything is committed in small steps; the many commits are
-**incremental fixes to the new `Lower` path**, not changes to the
-working legacy compiler.
-
-## Where exactly we are (L7)
-
-The flip is driven per unit: the driver suppresses the grammar's
-inline emit (`SetNoEmit`), snapshots the QbeGen state before each
-unit's parse, restores it, and lets `Lower` emit the unit from the
-AST.  This is now the *only* path — plain `./M2` runs it, and the
-self-hosting fixpoint runs it too.  `EndSession` writes the single
-session image.
-
-The `-lower` flag survives only for the test harness: it names the
-image `<mod>L.ssa` instead of `<mod>.ssa` so `run_tests.sh` can still
-byte-compare two runs.  Both runs now use Lower, so the comparison is
-degenerate; it will be retired together with the inline emit.
-
-Because `Lower` was verified byte-identical to the legacy inline emit
-on every single-file test and every session, flipping the default did
-not change any emitted image.
-
-## What L7 fixed so far
+```
+per unit:
+  Parse   -> AST + declarations; each procedure body is skipped and
+             re-parsed at unit end, so forward references bind normally
+  Lower   -> walk the AST, emit QBE (the only emitter)
+  Emit    -> buffered image, EndModule
+```
 
-- `Lower` is **V3-legal** (forward references declared in `Lower.def`;
-  V3 has no whole-module pass) and the `SymTab.FormalOk` open-array
-  def/impl bug.
-- Whole-session tables + an open-addressing **hash index** for
-  `FindSym`/`FindProc`.
-- **Symbol scoping**: a procedure's locals no longer collide with
-  another procedure's (`HIGH(s)` picked the wrong `s`).
-- **Chunked sequences** where a list can exceed `AST.MaxChild`:
-  `CASE` arms, multi-name `VAR` declarations, `CASE` bodies.
-- External procedures, indirect calls (proc-typed variables), `VAL`,
-  `LEN`/`HIGH`, qualified calls, qualified proc-typed variables,
-  const values, 1-char strings passed as `ARRAY OF CHAR`.
-- Per-unit global materialisation (`MaterializeReplace`).
-- Duplicate nested procedure names resolve by scope and uid.
+- **Two-phase parse.**  Procedure bodies are deferred (module level) and
+  re-parsed after the unit's declarations, which removed the entire
+  forward-reference mechanism (`FwdVar*`, `Design`'s forward branch).
+  A module body may now call a procedure declared later; a nested-local
+  forward is a plain `201`.  `-notwophase` restores the legacy inline
+  parse for debugging.
+- **No resolve/check pass.**  The `Check` module was deleted once it was
+  proven vestigial (gutting it left the emitted `.ssa` byte-identical):
+  binding is late by construction.
+- **`Lower` is the only emitter**; the AST is the interface.
+
+## Language coverage
+
+Program modules; `CONST`/`VAR`/`TYPE` (scalars, subranges, enums,
+arrays, records incl. variants, sets, pointers); `WITH`/`IN`; whole
+array/record copy; `NEW`/`DISPOSE`; full expressions and control flow;
+`GOTO`/labels; procedures (value/`VAR` params, functions, recursion,
+`FORWARD`, nested procedures, procedure values); Clarion-form `CLASS`
+(methods, single inheritance, virtual dispatch); PIM coroutines;
+Unicode (`UCHAR`/`UString`, UTF-8 edges); ISO type conversions `T(x)`;
+separate compilation (`FROM`/`IMPORT`, qualified `L.x`, opaque types);
+**generics** (ISO 10514-2 refinement): type/value/procedure
+parameters, constraints, nested generics, generic classes.
+
+## Landed recently (this thread)
+
+- AST + `Lower` (L0–L7) — `Lower` emits the whole session from the AST.
+- Two-phase parse; forward machinery deleted; `Check` deleted.
+- Generics increment 3: value/procedure parameters, constraint model,
+  nested generics, generic classes via generic modules.
+- ISO type conversions `T(x)` (incl. CONST folding): corpus 365 → 372.
+- Clean `M2` exit codes (0 ok / 1 errors / 2 usage-IO).
+- Bug fixes: `PopPos` wiping repass diagnostics; global record data
+  size (`w 0` → `l 0` for pointer/`LONGINT`/proc fields); template
+  arithmetic over a type formal; proc-typed formals in DEF/IMPL;
+  imported procedures used as values.
+- Showcase `showcase23` (generic doubly linked list).
 
 ## What remains
 
-Cleanup with no codegen gaps left.  **Not** purely mechanical: many
-`QbeGen.*` calls are semantic queries or parser state, not emit, and
-must stay — `TopLoop`/`PushLoop`/`PopLoop` (validates `EXIT`),
-`TopWith`/`PushWith`/`PopWith` (validates a bare field name in `WITH`),
-`IsImm`/`Fold2`/`NormInt`/`NormReal`/`StrFold`/… (constant values that
-`Lower` consumes via `NoteConstVal`), `LocFull`, `Mangled`, `ConstInt`.
-Only the true emission calls are removed, production group by group,
-with suite + fixpoint after each.
-
-Done:
-1. Builtin statements (`EXIT`, `INCL/EXCL`, `INC/DEC`, `NEW`, `DISPOSE`).
-2. Control flow (`IF`/`WHILE`/`REPEAT`/`LOOP`/`FOR`/`CASE`), `RETURN`,
-   `HALT`.
-3. Declarations/lifecycle: `DeclVar`/`DeclConst`, the module/impl/
-   nested/class `BeginInit`/`EndInit`/`BeginBody`/`EndModule`,
-   `FlushPend`, `FwdPatch`.  (This exposed and fixed a real bug — see
-   below.)
-
-Still to do:
-4. **Expressions/designators/calls: DONE (2026-10-08).**  The runtime
-   emit is gone from `SimExpr`, `Term`, `Expr`, `Fact`, `Design`,
-   `ResultComp`, `ArgList`, `ActParam` and assignment; a runtime result
-   is the non-constant sentinel `"@"` (which `IsImm`/`ConstInt`
-   reject), while constant folding (`NegFold`/`Fold2`/`StrFold`) and
-   every check stay.
-   The coupled change that had blocked this landed together: `Fact`
-   drops the `NoteAddr` chain, `ActParam` checks VAR-actual
-   addressability by AST kind (`NkDesignator`, or `NkStrLit`) instead
-   of the `NoteAddr`/`AddrOfVal` chain and drops `CallArg`, and
-   `ArgList` drops `CallBegin`/`CallEnd`.  (`NoteAddr`/`AddrOfVal`
-   remain, now used only by `Lower` for its own emit.)
-5. **Proc headings, set/ctor literals, string pooling: remaining.**
-   `ProcHeading` still calls `BeginFunc`/`FuncParam`/`EndFuncHeader`/
-   `EndFunc`/`Mangled`/`SetFuncRes`/`AbortFunc`; note `FuncParam` is a
-   check that relies on `BeginFunc` resetting `nPar`, so these must be
-   split rather than dropped.  `SetLit`/`TypedBraceLit`
-   (`NewSetTemp`/`SetZero`/`SetRange`/`SetBit`/`Ctor*`) and the
-   `DeclStr`/`DeclUStr` string pool are value-ish; `CopyOp`/`IsImm`/
-   `IntStr`/`Fold2`/`Norm*`/`Conv*` are the value layer and stay.
-6. Retire the `-lower` test flag and the now-degenerate byte-compare
-   tests.  **Done 2026-10-08:** `-lower`/`IsLowerParam`/`lowerTest` and
-   `EndSession`'s `testSuffix` are gone, and the 23 `lower_ok` cases
-   dropped (suite now **181**; the programs are still covered by the
-   `expect_run`/session cases).
-7. Remove the dead scaffolding.  Done 2026-10-08: `LowerSession`,
-   `LowerUnit`, the whole `Can*` capability-walker family,
-   `CanLower`/`CanExpr`/`CanDecls`/`CanProc`, the dead
-   `SetLower`/`lowerRequested`, plus every compiler proc a tree-wide
-   scan (tests included) finds unreferenced — `QbeGen`'s
-   `CloseModule`/`FwdPatch`/`FwdElemPatch`/`Remark`/`StrLen`,
-   `SymTab`'s `CurModule`/`CurUnit`/`ProcDepth`/`ParamName`/
-   `ModDefined`/`ModImplemented`/`Qual*`/`NestArray`/`NewSub`/
-   `SetElemCheck`/`SetFor`/`UnaryCheck`/`FwdVarKind`, and `AST`'s
-   `TxtLen`/`SetKind` (`AST.AddChild` stays; `tests/t_ast.mod` uses it).
-   Still needed until the inline emit is gone:
-   `SaveSession`/`RestoreSession`/`SetNoEmit` (the grammar still emits
-   suppressed) and `MaterializeGlobals`/`MaterializeReplace` (called
-   from `LowerOneUnit`).
-
-Note: full deletion to zero is gated on moving constant folding into
-`Lower` (item 4).  Until then the expression/value layer stays.
-
-### Fixed (2026-10-08): the note ring leaked the grammar's notes into Lower
-
-Removing `QbeGen.DeclVar` from `VarDecl` had made `Lower` resolve one
-VAR actual to the wrong symbol (`Showcase11`: `Strings.Replace`'s `src`
-became `$Strings_nl`).  Root cause: `QbeGen.AddrOfVal` scans the whole
-256-entry `nVal`/`nAddr` VAR-actual note ring, and `RestoreSession`
-restored `nn` but never cleared the ring — so the grammar's suppressed
-parse-time `NoteAddr` entries survived into `Lower`.  Their keys are
-temps that restart per function, so a stale entry could false-match
-`Lower`'s own key.  Removing `DeclVar` (fewer `AllocLocal`/`NewTemp`
-calls) shifted those keys and exposed it.  `RestoreSession` now clears
-the ring; `Lower` re-notes its own VAR actuals, so an empty ring is
-correct.  The fix is output-neutral on `Showcase11` and corrects some
-latent resolutions in the compiler's own image (fixpoint size moved).
-
-
-## Are we near completion?
-
-- **Of the working compiler:** yes — it is done, green, and
-  self-hosting, and it now emits through `Lower`.
-- **Of the L7 flip:** the flip is done; only the mechanical deletion of
-  the unused inline emitter remains.  It is not required for the
-  compiler to function — it is a quality/architecture goal.
+1. **Corpus language gaps** — top `LANG` buckets are `not supported
+   yet`, `undeclared identifier`, `invalid call`; separate genuine gaps
+   from missing stdlib imports (`LIB`), then fix the top bounded one.
+   See `docs/analysis_gaps.md`.
+2. **The size-sensitive V3 miscompile** — the long-standing "removing
+   `ASTDUMP` from `M2.atg` breaks the fixpoint" has never been
+   root-caused.  A real correctness landmine.
+3. **Robustness** — fixed table limits resolve silently when exceeded;
+   weak error recovery; error-message polish.
+4. **Library holes** — channel/device framework (`docs/wip/`).
+5. **Housekeeping** — consolidate `docs/summary_*.md` (see
+   `docs/INDEX.md`); decide on merging/pushing `resolve-check`.
 
 ## How to check for yourself
 
 ```sh
 cd compiler
-./build.sh          # rebuild
-./run_tests.sh      # 184/184
+./build.sh          # M2.atg -> scanner/parser/driver -> ./M2
+./run_tests.sh      # 219/219
 cd ..
-bootstrap/fixpoint.sh   # FIXPOINT OK
+./bootstrap/fixpoint.sh   # FIXPOINT OK (byte-identical stage2/stage3)
 ```