Explorar el Código

feat: add wide sets and SET OF CARDINAL

Eric Streit hace 1 día
padre
commit
31eaefebe5

+ 3 - 3
README.md

@@ -87,13 +87,13 @@ docs/              STATUS.md, plan.md, plan-*.md, analysis_*.md, summary_*.md
 
 ## Status (2026-10-24)
 
-- Suite **306/306**; self-hosting **fixpoint OK** (byte-identical
-  stage2/stage3, 3,808,348 bytes); corpus **519/612 compile-OK,
+- Suite **307/307**; self-hosting **fixpoint OK** (byte-identical
+  stage2/stage3, 3,809,843 bytes); corpus **521/612 compile-OK,
   0 crashes** (`tools/v3-corpus`; the corpus is gm2's testsuite, so it
   mixes conforming Modula-2 with gm2 leniencies — see `docs/gaps/`).
   The remaining `except*`/`onebyte*`-style corpus files still hit V3's
   declaration-order policy.
-- Active branch **`master`**, feature state **`v3-language-robustness`**.
+- Active branch **`master`**, feature state **`v3-wide-sets`**.
   Recent milestones: `PACKEDSET`, ISO exceptions (`EXCEPT`/`RETRY`,
   `EXCEPTIONS`, `M2EXCEPTION`, catchable language traps including
   `functionException`, module `FINALLY`), self-referential pointer

+ 3 - 3
TUTORIAL.md

@@ -10,7 +10,7 @@ From the repository root:
 ```sh
 cd compiler
 ./build.sh          # M2.atg -> scanner/parser/driver -> ./M2
-./run_tests.sh      # 306/306
+./run_tests.sh      # 307/307
 ```
 
 `M2` reads Modula-2 sources and writes QBE IR to `gen_ssa/`.
@@ -149,8 +149,8 @@ TMP="$PWD/.scratch/fixpoint-separate" ./bootstrap/fixpoint-separate.sh
 tools/v3-corpus/corpus.sh
 ```
 
-Current gates: suite **306/306**, fixpoint **OK (3,808,348 bytes)**,
-corpus **519/612 compile-OK, 0 crashes**.
+Current gates: suite **307/307**, fixpoint **OK (3,809,843 bytes)**,
+corpus **521/612 compile-OK, 0 crashes**.
 
 ## 7. Current limits
 

+ 1 - 0
compiler/run_tests.sh

@@ -94,6 +94,7 @@ expect_run t_word16.mod 42
 expect_run t_packedset.mod 42
 expect_run t_ptrchain.mod 42
 expect_run t_addreq.mod 42
+expect_run t_wide_set.mod 42
 expect_run t_finally.mod 43
 expect_run t_finally_return.mod 43
 expect_run t_finally_except.mod 42

+ 4 - 1
compiler/src/M2.atg

@@ -1619,9 +1619,12 @@ PRODUCTIONS
                                                blo := 0;
                                                bspan := VAL(INTEGER,
                                                  SymTab.EnumCount(base))
+                                             ELSIF (bcls = SymTab.ClInt) AND
+                                                   SymTab.IsCardinalType(base) THEN
+                                               blo := 0; bspan := 1000000
                                              ELSE bspan := 0 END;
                                              IF (bspan <= 0)
-                                                OR (bspan > 65536) THEN
+                                                OR (bspan > 1000000) THEN
                                                SemError(230);
                                                t := SymTab.InvalidType
                                              ELSE t := SymTab.NewSet(base)

+ 2 - 0
compiler/src/SymTab.def

@@ -610,6 +610,8 @@ PROCEDURE SetBaseLo (t: TypeIndex): INTEGER;
 (* Base minimum (bool/char 0, subrange lo); 0 when unsuitable. *)
 PROCEDURE SetCount (t: TypeIndex): CARDINAL;
 (* Base span in values (0 when unsuitable). *)
+PROCEDURE IsCardinalType (t: TypeIndex): BOOLEAN;
+(* TRUE for the predefined CARDINAL type (wide SET base). *)
 PROCEDURE TypeBounds (t: TypeIndex; VAR lo, hi: INTEGER): BOOLEAN;
 (* Ordinal bounds of a type (MIN/MAX): subrange/array, CHAR/UCHAR,
    BOOLEAN, enumeration, set base, or the integer family. *)

+ 10 - 1
compiler/src/SymTab.mod

@@ -12,6 +12,7 @@ CONST
   MaxPP     = 1024;   (* total procedure-type parameter slots *)
   MaxEnumLit = 8192;  (* enumeration literals, for export/import *)
   MaxDefer  = 512;    (* deferred procedure bodies (two-phase parse) *)
+  MaxSetSpan = 1000000; (* wide set implementation limit (bits) *)
 
   (* descriptor forms *)
   FNone = 0; FAlias = 1; FSub = 2; FEnum = 3; FArray = 4;
@@ -1403,13 +1404,16 @@ PROCEDURE SetSpan (t: TypeIndex; VAR lo, n: INTEGER): BOOLEAN;
     IF tform[r] = FSByte THEN lo := -128; n := 256; RETURN TRUE END;
     IF tform[r] = FWord16 THEN lo := 0; n := 65536; RETURN TRUE END;
     IF tform[r] = FSWord16 THEN lo := -32768; n := 65536; RETURN TRUE END;
+    (* wide sets: CARDINAL uses the implementation span; arbitrary
+       INTEGER remains unsuitable for a finite set. *)
+    IF (r = Resolve(dCard)) THEN lo := 0; n := MaxSetSpan; RETURN TRUE END;
     IF tform[r] = FEnum THEN
       IF tenum[r] = 0 THEN RETURN FALSE END;
       lo := 0; n := VAL(INTEGER, tenum[r]); RETURN TRUE
     END;
     IF (tform[r] = FSub)
  AND SubBounds(b, blo, bhi) AND (bhi >= blo)
- AND (bhi - blo < 65536) THEN
+ AND (bhi - blo <= MaxSetSpan) THEN
       lo := blo; n := bhi - blo + 1; RETURN TRUE
     END;
     RETURN FALSE
@@ -1453,6 +1457,11 @@ PROCEDURE SetCount (t: TypeIndex): CARDINAL;
     RETURN VAL(CARDINAL, n)
   END SetCount;
 
+PROCEDURE IsCardinalType (t: TypeIndex): BOOLEAN;
+  BEGIN
+    RETURN Resolve(t) = Resolve(dCard)
+  END IsCardinalType;
+
 PROCEDURE TypeBounds (t: TypeIndex; VAR lo, hi: INTEGER): BOOLEAN;
 (* The ordinal bounds of a type, for MIN/MAX: subrange/array bounds,
    CHAR/UCHAR, BOOLEAN, enumeration, or a set's base span. *)

+ 23 - 0
compiler/tests/t_wide_set.mod

@@ -0,0 +1,23 @@
+MODULE TWideSet;
+(* Wide set implementation limits: a large explicit span and the
+   implicit SET OF CARDINAL span. *)
+TYPE
+  Wide = SET OF [0..100000];
+  CardSet = SET OF CARDINAL;
+VAR
+  w : Wide;
+  c : CardSet;
+  ExitCode : INTEGER;
+BEGIN
+  w := Wide{};
+  INCL(w, 100000);
+  c := CardSet{};
+  INCL(c, 2);
+  INCL(c, 65535);
+  IF (100000 IN w) AND (2 IN c) AND (65535 IN c)
+     AND NOT (3 IN c) THEN
+    ExitCode := 42
+  ELSE
+    ExitCode := 1
+  END
+END TWideSet.

+ 7 - 6
docs/STATUS.md

@@ -4,17 +4,17 @@ This answers "where are we now?".
 
 ## Numbers
 
-- Suite **306/306** (`compiler/run_tests.sh`).
+- Suite **307/307** (`compiler/run_tests.sh`).
 - Self-hosting **FIXPOINT OK** — stage2 and stage3 images are
-  byte-identical (3,808,348 bytes).
-- Corpus **519 / 612** sources compile with 0 errors, **0 crashes**
+  byte-identical (3,809,843 bytes).
+- Corpus **521 / 612** sources compile with 0 errors, **0 crashes**
   (`tools/v3-corpus/corpus.sh` over the gm2 testsuite; the harness now
   resolves V3's own shipped libraries); the rest are genuine language
   gaps, **gm2 leniencies V3 deliberately rejects**, or unresolved
   imports of gm2-only modules.  Open-array corpus cases `unbounded`,
   `unbounded2`, `unbounded3`, `unbounded4` and `array9` now compile;
   `unbounded`/`unbounded2`/`unbounded3`/`unbounded4` also run.
-- Branch **`master`**, feature state **`v3-language-robustness`**; tree
+- Branch **`master`**, feature state **`v3-wide-sets`**; tree
   clean.
 
 ## Architecture (current)
@@ -68,8 +68,9 @@ remaining a string for `ARRAY OF CHAR` (whole-array assignment and
 content comparison).  `PACKEDSET OF <ordinal>` is supported with
 1/2/4-byte storage (1/2/4/8/16/32-bit spans); `SIZE` and `ORD` follow
 the packed width, and `INCL`/`EXCL`/`IN`/set operations/assignment work
-on packed values.  Wider packed sets are a loud implementation limit
-(`230`).  Runtime **subrange range checks** now trap on
+on packed values.  Wide ordinary sets use up to 1,000,000 bits, including
+`SET OF CARDINAL`; `SET OF INTEGER` stays rejected.  Wider packed sets
+are a loud implementation limit (`230`).  Runtime **subrange range checks** now trap on
 assignment, value actuals, `RETURN` and `INC`/`DEC`
 (`QbeGen.CheckRange`); the post-increment of a `FOR` control variable is
 not checked (the final successor may legitimately exceed a full

+ 7 - 6
docs/comparison-PIM4-gm2-V3.md

@@ -2,8 +2,8 @@
 
 **Date:** 2026-10-24 · **V3 state:** open arrays, dialect library
 folders and separate compilation with `M2 -I`/incremental objects
-(suite 306/306, self-hosting fixpoint OK 3,808,348 bytes, corpus
-519/612, 0 crashes).
+(suite 307/307, self-hosting fixpoint OK 3,809,843 bytes, corpus
+521/612, 0 crashes).
 
 **Scope and sources.**
 
@@ -72,7 +72,7 @@ change individual cells.
 | Basic integer/real/bool/char types | ✅ | ✅ | ✅ (+ `OCTET`, `LONGCARD`) | ✅ PIM types | ✅ |
 | Subranges | ✅ | ✅ | ✅ (`[lo..hi] OF Base`) | ✅ | ✅ (typed CHAR/enum subranges) |
 | Enumerations | ✅ | ✅ | ✅ extensible | ✅ | ✅ |
-| Sets (`SET OF`) | ✅ any finite ordinal (impl. limit) | ✅ | 🔄 `SET OF <enumType>` only | ✅ range/base/enum bases | 🔄 bool/char/byte/16-bit/enum/small-int; span ≤ 65536; no `SET OF CARDINAL` |
+| Sets (`SET OF`) | ✅ any finite ordinal (impl. limit) | ✅ | 🔄 `SET OF <enumType>` only | ✅ range/base/enum bases | 🔄 bool/char/byte/16-bit/enum/small-int; wide spans ≤ 1,000,000 bits; bounded `SET OF CARDINAL` |
 | `PACKEDSET` | ❌ (ISO) | ✅ | ❌ | ❌ | ✅ (1/2/4 bytes, span ≤ 32) |
 | Fixed / multi-dimensional arrays | ✅ `[a], [b] OF` | ✅ | ✅ `ARRAY count, count OF` (zero-based) | ✅ | ✅ both `[a], [b]` and `[a, b]` |
 | Open arrays (1-D) | ✅ | ✅ | ✅ (`BARE ARRAY OF`) | ✅ | ✅ |
@@ -162,8 +162,8 @@ change individual cells.
   payload with per-level views; payload `SIZE`/`ADR` and row/subarray
   conversion are implemented.  Its hard gaps are **complex arithmetic,
   finalization/protection, ISO OO** and parts of the **word model**
-  (`SHORTREAL`, `REAL` width), plus a **65536-bit `SET` span limit**
-  and a **32-bit `PACKEDSET` limit**.  Self-referential pointer records
+  (`SHORTREAL`, `REAL` width), plus a **1,000,000-bit wide `SET`
+  limit** and a **32-bit `PACKEDSET` limit**.  Self-referential pointer records
   and chained pointer-field designators (`p^.next^.value`) are
   supported.  **Separate compilation** is now available for normal
   modules: `M2 -c` emits one object per unit, library objects have no
@@ -181,7 +181,8 @@ change individual cells.
   are 32-bit; `LONGINT`/`LONGCARD` are 64-bit; every `REAL`/`SHORTREAL`
   is 8 bytes; `COMPLEX*` is a placeholder.
 - **Sets:** bases limited to bool/char/byte/16-bit/enum/small subranges;
-  `SET` total span ≤ 65536; no `SET OF CARDINAL`.  `PACKEDSET` uses
+  wide `SET` spans up to 1,000,000 bits; `SET OF CARDINAL` is bounded
+  to that span; `SET OF INTEGER` remains rejected.  `PACKEDSET` uses
   1/2/4-byte storage with a 32-bit span limit (wider spans are a loud
   `230`).
 - **Runtime range checks** are emitted for subrange assignment, value

+ 2 - 2
docs/features.md

@@ -1,4 +1,4 @@
-# m2compiler-V3 — feature status (2026-10-24; suite 306/306 green)
+# m2compiler-V3 — feature status (2026-10-24; suite 307/307 green)
 
 Pipeline: Coco/R `M2.atg` (1748 lines, 73 productions) → `gm2`-built
 `M2` → QBE `.ssa` → `qbe` → `cc` → run. `SymTab.mod` 1623 lines,
@@ -80,7 +80,7 @@ Legend: ✅ done · 🔄 partial · ⏸ not started / deferred.
   as a statement).  Unknown names keep the permissive no-result varargs
   external.  String/CHAR-array actuals pass as `descriptor+8`.
 - ✅ Set builtins `INCL`/`EXCL` and `SHIFT`/`ROTATE`; `SET OF <enum>`
-  and `SET OF <char-range>`; set spans up to 65536.
+  and `SET OF <char-range>`; wide sets up to 1,000,000 bits; `SET OF CARDINAL` uses that bounded span. `SET OF INTEGER` remains rejected.
 - ✅ Module-level forward type references (a global may name a type
   declared further down; emission deferred).
 - ✅ `RECORD` (flat blobs, nested inline, array fields as pointers),

+ 2 - 2
docs/plan-separate-compilation.md

@@ -5,8 +5,8 @@
 one-shot mode remains the default for the suite/corpus; this document
 keeps the design record and the deferred phases.
 
-**Baseline now:** suite 306/306, fixpoint OK 3,808,348 bytes, corpus
-519/612, 0 crashes.
+**Baseline now:** suite 307/307, fixpoint OK 3,809,843 bytes, corpus
+521/612, 0 crashes.
 
 ---
 

+ 11 - 5
docs/summary_session-2026-10-24-language-robustness.md

@@ -1,22 +1,28 @@
 # Session 2026-10-24 — language/robustness pass
 
-**Gates:** suite **306/306**, one-shot fixpoint **OK (3,808,348
+**Gates:** suite **307/307**, one-shot fixpoint **OK (3,809,843
 bytes)**, separate-object fixpoint **OK (11 objects)**, corpus
-**519/612 compile-OK, 0 crashes**.
+**521/612 compile-OK, 0 crashes**.
 
 ## Landed
 
 - **`ADDRESS` ↔ pointer equality** (`SymTab.EqCheck`): an `ADDRESS`
   now compares with any pointer value, which is the standard way to
   check `ADR(p^) = p`.  Regression `t_addreq`.
+- **Wide sets / `SET OF CARDINAL`**: ordinary sets now allow spans up
+  to 1,000,000 bits; `SET OF CARDINAL` uses that bounded span and
+  supports empty literals, `INCL`/`EXCL`, membership and copying.
+  `SET OF INTEGER` remains rejected.  Regression `t_wide_set`; corpus
+  `settest1`/`settest3` now compile (519 → 521).
 - The corpus case `adraddress` remains a declaration-order reject; the
   language operation itself is no longer a gap.
 - Updated the feature status, comparison table and corpus triage.
 
 ## Still open (language/robustness)
 
-- Wide sets (`SET OF CARDINAL`, spans above 65536 bits) remain an
-  implementation limit.
+- Wide ordinary sets stop at 1,000,000 bits; `PACKEDSET` remains
+  capped at 32 bits.  Wider set constants also carry the static-mask
+  limit.
 - `COMPLEX*`, true 16-bit `SHORTREAL`, absolute variables and inline ASM
   remain outside the chosen PIM/ISO target.
 - ISO exception protection/coroutine follow-ups.
@@ -26,4 +32,4 @@ bytes)**, separate-object fixpoint **OK (11 objects)**, corpus
 
 ## Commit/tag
 
-- feature tag `v3-language-robustness`
+- feature tags `v3-language-robustness`, `v3-wide-sets`

+ 3 - 3
docs/summary_session-2026-10-24-separate-compilation.md

@@ -4,8 +4,8 @@ V3 now builds per-unit objects.  The one-shot mode remains the default
 for the suite/corpus.
 
 **Branch:** `master`.  **Feature state:** `v3-separate-compilation`.
-**Gates:** suite **306/306**, fixpoint **OK (3,808,348 bytes)**,
-corpus **519/612 compile-OK, 0 crashes**.
+**Gates:** suite **307/307**, fixpoint **OK (3,809,843 bytes)**,
+corpus **521/612 compile-OK, 0 crashes**.
 
 ---
 
@@ -88,7 +88,7 @@ Manual M2make cross-object class check: `CLib.def/.mod` + `CProg.mod`
   `gen_ssa/<Module>.o`, so definition-only data and class vtables link.
 - Added `CDefProg` (class-only `.def` vtable) and M2make checks for the
   ABI stamp and definition-only object.
-- Suite is now 306/306.
+- Suite is now 307/307.
 
 ## Generic-instance objects (2026-10-24)
 

+ 4 - 3
docs/triage-corpus-2026-10-24.md

@@ -1,8 +1,8 @@
 # Corpus triage — 2026-10-24
 
 **State after this pass:** suite **301/301**, fixpoint OK
-**3,573,487 bytes**, corpus **519/612 compile-OK, 0 crashes**,
-**66 LANG**, **27 LIB**.
+**3,573,487 bytes**, corpus **521/612 compile-OK, 0 crashes**,
+**64 LANG**, **27 LIB**.
 
 The corpus is compile-only.  This pass separated the remaining `LANG`
 failures into policy, dialect/lexical choices, implementation limits,
@@ -72,7 +72,8 @@ No policy relaxation is recommended.
 
 ## Implementation limits
 
-- `settest1`, `settest3`: set span beyond the current 65536-bit limit.
+- `settest1`, `settest3`: fixed by the 1,000,000-bit wide-set
+  implementation (corpus 519 → 521).
 - `largeset5`: set ordering (`<`, `>=`); PIM/ISO only defines
   `=`/`#`/`IN` for sets, so this is a gm2 extension rather than a
   missing standard operation.