Prechádzať zdrojové kódy

showcase24: multi-file generics + classes + stdlib session

An eleven-file showcase: generic GStack(T) instantiated as IntStack,
the two-parameter GPair(K,V) instantiated as PairIC, a
Shape/Circle/Square class hierarchy with VIRTUAL dispatch through
base-class pointers, a local helper library (Show24Util) over
Strings/Conversions/Math, and TextIO.  Prints "showcase24 total=42"
and exits 42.

Finding recorded (analysis_gaps §10): a generic module instantiated
twice with arguments from different families fails on the second
instantiation (GStack(INTEGER) + GStack(CHAR)); INTEGER+CARDINAL passes
only because the shared binding still type-checks.  The showcase uses a
single GStack instantiation plus GPair, avoiding the bug.

Suite 239/239.
Eric Streit 11 hodín pred
rodič
commit
a4a5a3eaa6

+ 1 - 1
README.md

@@ -47,7 +47,7 @@ docs/              STATUS.md, plan.md, plan-*.md, analysis_*.md, summary_*.md
 
 ## Status (2026-10-18)
 
-- Suite **238/238**; self-hosting **fixpoint OK** (byte-identical
+- Suite **239/239**; self-hosting **fixpoint OK** (byte-identical
   stage2/stage3, 3,812,771 bytes); corpus **405/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/`).

+ 12 - 0
compiler/run_tests.sh

@@ -330,6 +330,18 @@ expect_run_files_out Showcase23 35 "list: 5 10 20" \
   showcase23lib.def showcase23lib.mod \
   showcase23int.def showcase23int.mod \
   showcase23vis.def showcase23vis.mod showcase23.mod
+expect_run_files_out Showcase24 42 "showcase24 total=42" \
+  ../runtime/syslib/Utf8.def ../runtime/syslib/Utf8.mod \
+  ../stdlib/textio.def ../stdlib/textio.mod \
+  ../stdlib/conversions.def ../stdlib/conversions.mod \
+  ../stdlib/strings.def ../stdlib/strings.mod \
+  ../stdlib/math.def ../stdlib/math.mod \
+  showcase24stack.def showcase24stack.mod \
+  showcase24int.def showcase24int.mod \
+  showcase24pair.def showcase24pair.mod \
+  showcase24pic.def showcase24pic.mod \
+  showcase24util.def showcase24util.mod \
+  showcase24.mod
 expect_run_files TImportProc 7 pvi.def pvi.mod t_importproc.mod
 expect_run_files_out Showcase22 42 "showcase22 total=42" \
   ../runtime/syslib/SysShim.def ../runtime/syslib/SysShim.mod \

+ 117 - 0
compiler/tests/showcase24.mod

@@ -0,0 +1,117 @@
+MODULE Showcase24;
+// Multi-file session showcase.  Combines:
+//   * ISO generic modules: GStack(T) instantiated as IntStack, and the
+//     two-parameter GPair(K, V) instantiated as PairIC(INTEGER, CHAR),
+//   * a Clarion CLASS hierarchy with VIRTUAL dispatch (Shape/Circle/
+//     Square) held through base-class pointers,
+//   * stdlib libraries: TextIO, Strings, Conversions, Math,
+//   * a local helper library, Show24Util.
+//
+// Pushes each shape's virtual Area() onto the generic stack, pops and
+// sums them (9+16+16+1 = 42), builds "showcase24 total=42" in
+// Show24Util (Strings + Conversions), reverses it through the same
+// generic stack, checks a real sqrt via Math and a pair via PairIC.
+// Prints the label and exits 42.
+IMPORT TextIO, Strings, IntStack, PairIC, Show24Util;
+
+TYPE
+  CLASS Shape;
+    VIRTUAL PROCEDURE Area() : INTEGER;
+  END Shape;
+
+  CLASS Circle (Shape);
+    r : INTEGER;
+    PROCEDURE SetR(v : INTEGER);
+    VIRTUAL PROCEDURE Area() : INTEGER;
+  END Circle;
+
+  CLASS Square (Shape);
+    s : INTEGER;
+    PROCEDURE SetS(v : INTEGER);
+    VIRTUAL PROCEDURE Area() : INTEGER;
+  END Square;
+
+CLASS IMPLEMENTATION Shape;
+  PROCEDURE Area() : INTEGER;
+  BEGIN RETURN 0 END Area;
+END Shape;
+
+CLASS IMPLEMENTATION Circle;
+  PROCEDURE SetR(v : INTEGER);
+  BEGIN r := v END SetR;
+  PROCEDURE Area() : INTEGER;
+  BEGIN RETURN r * r END Area;
+END Circle;
+
+CLASS IMPLEMENTATION Square;
+  PROCEDURE SetS(v : INTEGER);
+  BEGIN s := v END SetS;
+  PROCEDURE Area() : INTEGER;
+  BEGIN RETURN s * s END Area;
+END Square;
+
+VAR ExitCode : INTEGER;
+VAR a, b : POINTER TO Circle;
+VAR c, d : POINTER TO Square;
+VAR shapes : ARRAY [0 .. 3] OF POINTER TO Shape;
+VAR st : IntStack.Stack;
+VAR line, rev : ARRAY [0 .. 63] OF CHAR;
+VAR i, n, total, v : INTEGER;
+VAR ch : CHAR;
+VAR ok : BOOLEAN;
+
+BEGIN
+  ExitCode := 0;
+
+  (* four polymorphic shapes: Circle(3)=9, Circle(4)=16,
+     Square(4)=16, Square(1)=1 -> 42 *)
+  NEW(a); a^.SetR(3);
+  NEW(b); b^.SetR(4);
+  NEW(c); c^.SetS(4);
+  NEW(d); d^.SetS(1);
+  shapes[0] := a; shapes[1] := b; shapes[2] := c; shapes[3] := d;
+
+  (* generic stack: push each virtual Area(), then pop and sum *)
+  IntStack.Init(st);
+  i := 0;
+  WHILE i <= 3 DO
+    IntStack.Push(st, shapes[i]^.Area());
+    INC(i)
+  END;
+  IF IntStack.Depth(st) # 4 THEN ExitCode := 1 END;
+
+  total := 0;
+  WHILE IntStack.Pop(st, v) DO total := total + v END;
+
+  (* helper library: line = "showcase24 total=" + IntToStr(total) *)
+  Show24Util.Label("showcase24 total=", total, line);
+
+  (* reverse the label through the same generic stack *)
+  n := Strings.Length(line);
+  IntStack.Init(st);
+  i := 0;
+  WHILE i < n DO
+    IntStack.Push(st, ORD(line[i]));
+    INC(i)
+  END;
+  i := 0; ok := TRUE;
+  WHILE ok DO
+    ok := IntStack.Pop(st, v);
+    IF ok THEN rev[i] := CHR(v); INC(i) END
+  END;
+  rev[i] := CHR(0);
+  IF (n # 19) OR (rev[0] # "2") OR (rev[n - 1] # "s") THEN ExitCode := 1 END;
+
+  (* two-parameter generic: PairIC = GPair(INTEGER, CHAR) *)
+  IF PairIC.First(total, "!") # 42 THEN ExitCode := 1 END;
+  ch := PairIC.Second(total, "!");
+  IF ch # "!" THEN ExitCode := 1 END;
+
+  (* real math through the Math library *)
+  IF Show24Util.Root(42) # 6 THEN ExitCode := 1 END;
+
+  TextIO.WriteString(line);
+  TextIO.WriteLn;
+
+  IF total = 42 THEN ExitCode := ExitCode + 42 ELSE ExitCode := 99 END
+END Showcase24.

+ 2 - 0
compiler/tests/showcase24int.def

@@ -0,0 +1,2 @@
+DEFINITION MODULE IntStack = GStack(INTEGER);
+END IntStack.

+ 2 - 0
compiler/tests/showcase24int.mod

@@ -0,0 +1,2 @@
+IMPLEMENTATION MODULE IntStack = GStack(INTEGER);
+END IntStack.

+ 5 - 0
compiler/tests/showcase24pair.def

@@ -0,0 +1,5 @@
+GENERIC DEFINITION MODULE GPair (K : TYPE; V : TYPE);
+(* A generic pair accessor over two independent type parameters. *)
+PROCEDURE First(k : K; v : V) : K;
+PROCEDURE Second(k : K; v : V) : V;
+END GPair.

+ 11 - 0
compiler/tests/showcase24pair.mod

@@ -0,0 +1,11 @@
+GENERIC IMPLEMENTATION MODULE GPair;
+PROCEDURE First(k : K; v : V) : K;
+BEGIN
+  RETURN k
+END First;
+
+PROCEDURE Second(k : K; v : V) : V;
+BEGIN
+  RETURN v
+END Second;
+END GPair.

+ 2 - 0
compiler/tests/showcase24pic.def

@@ -0,0 +1,2 @@
+DEFINITION MODULE PairIC = GPair(INTEGER, CHAR);
+END PairIC.

+ 2 - 0
compiler/tests/showcase24pic.mod

@@ -0,0 +1,2 @@
+IMPLEMENTATION MODULE PairIC = GPair(INTEGER, CHAR);
+END PairIC.

+ 18 - 0
compiler/tests/showcase24stack.def

@@ -0,0 +1,18 @@
+GENERIC DEFINITION MODULE GStack (T : TYPE);
+(* A generic linked stack over a type parameter T.  Instantiated as
+   IntStack = GStack(INTEGER) and CharStack = GStack(CHAR). *)
+TYPE
+  Node = POINTER TO NodeRec;
+  NodeRec = RECORD
+    val  : T;
+    next : Node;
+  END;
+  Stack = RECORD
+    top   : Node;
+    depth : INTEGER;
+  END;
+PROCEDURE Init(VAR s : Stack);
+PROCEDURE Push(VAR s : Stack; v : T);
+PROCEDURE Pop(VAR s : Stack; VAR v : T) : BOOLEAN;
+PROCEDURE Depth(VAR s : Stack) : INTEGER;
+END GStack.

+ 27 - 0
compiler/tests/showcase24stack.mod

@@ -0,0 +1,27 @@
+GENERIC IMPLEMENTATION MODULE GStack;
+PROCEDURE Init(VAR s : Stack);
+BEGIN
+  s.top := NIL; s.depth := 0
+END Init;
+
+PROCEDURE Push(VAR s : Stack; v : T);
+VAR n : Node;
+BEGIN
+  NEW(n); n^.val := v; n^.next := s.top; s.top := n;
+  s.depth := s.depth + 1
+END Push;
+
+PROCEDURE Pop(VAR s : Stack; VAR v : T) : BOOLEAN;
+VAR n : Node;
+BEGIN
+  IF s.top = NIL THEN RETURN FALSE END;
+  n := s.top; v := n^.val; s.top := n^.next;
+  s.depth := s.depth - 1;
+  RETURN TRUE
+END Pop;
+
+PROCEDURE Depth(VAR s : Stack) : INTEGER;
+BEGIN
+  RETURN s.depth
+END Depth;
+END GStack.

+ 9 - 0
compiler/tests/showcase24util.def

@@ -0,0 +1,9 @@
+DEFINITION MODULE Show24Util;
+(* A small helper library: string building (Strings + Conversions) and
+   a real-valued square root through Math. *)
+PROCEDURE Label(prefix : ARRAY OF CHAR; n : INTEGER;
+                VAR out : ARRAY OF CHAR);
+(* out := prefix followed by n's decimal image. *)
+PROCEDURE Root(n : INTEGER) : INTEGER;
+(* floor(sqrt(n)). *)
+END Show24Util.

+ 16 - 0
compiler/tests/showcase24util.mod

@@ -0,0 +1,16 @@
+IMPLEMENTATION MODULE Show24Util;
+IMPORT Strings, Conversions, Math;
+
+PROCEDURE Label(prefix : ARRAY OF CHAR; n : INTEGER;
+                VAR out : ARRAY OF CHAR);
+VAR num : ARRAY [0 .. 15] OF CHAR;
+BEGIN
+  Conversions.IntToStr(n, num);
+  Strings.Concat(prefix, num, out)
+END Label;
+
+PROCEDURE Root(n : INTEGER) : INTEGER;
+BEGIN
+  RETURN VAL(INTEGER, Math.floor(Math.sqrt(VAL(REAL, n))))
+END Root;
+END Show24Util.

+ 2 - 2
docs/STATUS.md

@@ -4,7 +4,7 @@ This answers "where are we now?".
 
 ## Numbers
 
-- Suite **238/238** (`compiler/run_tests.sh`).
+- Suite **239/239** (`compiler/run_tests.sh`).
 - Self-hosting **FIXPOINT OK** — stage2 and stage3 images are
   byte-identical (3,812,771 bytes).
 - Corpus **405 / 612** sources compile with 0 errors, **0 crashes**
@@ -121,7 +121,7 @@ is the 10 gm2-leniency files now correctly rejected).
 ```sh
 cd compiler
 ./build.sh          # M2.atg -> scanner/parser/driver -> ./M2
-./run_tests.sh      # 238/238
+./run_tests.sh      # 239/239
 cd ..
 ./bootstrap/fixpoint.sh   # FIXPOINT OK (byte-identical stage2/stage3)
 ```

+ 20 - 0
docs/analysis_gaps.md

@@ -286,3 +286,23 @@ Modula-2 forbids and V3 correctly rejects; `iso/system`; `gm2-ext`;
 cases (`subrange4`/`7`/`11`, `shift3`/`4`, `constsize2`, `setoverflow`,
 `setconst3`) are **not standard Modula-2** — only a `POINTER`'s base type
 may be declared later.
+
+## 10. Finding while building `showcase24` (generics)
+
+A **generic module may not be instantiated twice with type arguments
+from different families** in one session.  With
+
+```mod
+GENERIC DEFINITION MODULE GStack (T : TYPE);
+TYPE NodeRec = RECORD val : T; next : Node END; ...
+```
+
+`CharStack = GStack(CHAR)` compiles **alone**, and `GStack(INTEGER)`
+works; but `GStack(INTEGER)` **plus** `GStack(CHAR)` fails on the second
+instantiation (`incompatible assignment` at `n^.val := v`).  The
+`INTEGER`+`CARDINAL` pair happens to pass (both `ClInt`, so the wrong
+binding still type-checks), which suggests the instantiations **share
+the formal `T`'s binding** instead of getting independent substitutions.
+Repro: `/tmp`-style five-file session (generic def/mod, two
+instantiations, a program) — see `showcase24` (which therefore uses one
+`GStack` instantiation plus the two-parameter `GPair(K,V)`).

+ 18 - 2
docs/summary_set-constants-2026-10-18.md

@@ -1,6 +1,6 @@
 # Session summary — SET CONST + builtin CONST folding 2026-10-18
 
-Branch **`resolve-check`**.  Suite **238/238**; fixpoint **OK
+Branch **`resolve-check`**.  Suite **239/239**; fixpoint **OK
 (3,812,771 bytes)**; corpus **405/612 compile-OK, 0 crashes**.
 
 Tags: `v3-set-constants`, `v3-const-builtin-fold`, `v3-const-conv-fold`,
@@ -156,6 +156,22 @@ legal exception.  Corpus **398 → 388**: the 10 files dropped
 leniency.  Forward references to module-level **variables**/**procedures**
 from a body (the two-phase parse) remain — a separate, larger item.
 
+## Showcase24: multi-file, generics + classes + libraries
+
+`showcase24` (test suite) is an eleven-file session: a generic `GStack(T)`
+(instantiated `IntStack`), a two-parameter `GPair(K,V)` (instantiated
+`PairIC`), a `Shape/Circle/Square` class hierarchy driven by VIRTUAL
+dispatch through base-class pointers, a local helper library
+(`Show24Util`) over `Strings`/`Conversions`/`Math`, and `TextIO`.  It
+prints `showcase24 total=42` and exits 42.
+
+It surfaced a **generics limitation**: instantiating one generic twice
+with arguments from different families (`GStack(INTEGER)` +
+`GStack(CHAR)`) fails on the second one; `INTEGER`+`CARDINAL` passes only
+because the shared binding still type-checks.  Recorded in
+`docs/analysis_gaps.md` §10.  The showcase therefore uses one `GStack`
+instantiation plus the 2-parameter `GPair`.
+
 ## Track B: `ORDL` de-reserved
 
 `ORDL` is a gm2/FileIO helper, not a Modula-2 built-in; V3 reserved it,
@@ -249,7 +265,7 @@ modules),
 ```sh
 cd .../m2compiler-V3
 git checkout resolve-check
-cd compiler && ./build.sh && ./run_tests.sh   # 238/238
+cd compiler && ./build.sh && ./run_tests.sh   # 239/239
 cd .. && TMP="$PWD/.scratch/fixpoint" ./bootstrap/fixpoint.sh
 M2FLAGS="" ./.scratch/corpusx.sh              # 405 OK, 0 crash
 ```