فهرست منبع

generics inc3 (partial): value (constant) generic parameters

A generic formal may now be a value, not just a type:
GENERIC DEFINITION MODULE Buf (size : CARDINAL); TYPE T = ARRAY
[0..size] OF CHAR; ... instantiated by MODULE X = Buf(10);

- GenericFormal collects its names, then accepts ': TYPE' (type formal)
  or ': TypeIdent' (value formal).
- Actual accepts integer / charConst / ident (type name = type actual,
  CONST name = value actual), recording kind + value text.
- Refinement actuals carry kind/value (refKind/refVal, instKind/instVal
  + accessors); driver passes them through.
- On instantiation a value formal binds to a CONST with the actual
  value; in the abstract template it is a CONST placeholder ("0") so
  template parsing succeeds (templates are never lowered).

Two instances with distinct sizes verified end-to-end (HIGH(T) reflects
the bound). Suite 209/209 (BufProg), fixpoint OK, corpus unchanged.
Procedure parameters / constraints remain.
Eric Streit 1 روز پیش
والد
کامیت
f582946326

+ 2 - 0
compiler/run_tests.sh

@@ -283,6 +283,8 @@ expect_run_files GenericProg 42 \
   g_ident.def g_ident.mod g_intid.def g_intid.mod g_prog.mod
 expect_run_files PairProg 73 \
   g_pair.def g_pair.mod g_intchar.def g_intchar.mod g_pair_prog.mod
+expect_run_files BufProg 42 \
+  g_buf.def g_buf.mod g_buf10.def g_buf10.mod g_bufprog.mod
 expect_run_files WrapProg 42 \
   ../runtime/syslib/SysShim.def ../runtime/syslib/SysShim.mod \
   ../stdlib/iochan.def ../stdlib/iochan.mod \

+ 120 - 21
compiler/src/M2.atg

@@ -151,6 +151,8 @@ VAR
   refInst, refGen: SymTab.Name;
   refN: CARDINAL;
   refActual: ARRAY [0 .. 15] OF SymTab.TypeIndex;
+  refKind: ARRAY [0 .. 15] OF INTEGER;   (* 0 = type actual, 1 = value *)
+  refVal:  ARRAY [0 .. 15] OF SymTab.Name;
   isGen: BOOLEAN;
 
   (* Generics (Increment 2): instantiation re-parse context.  When the
@@ -160,6 +162,8 @@ VAR
   instActive: BOOLEAN;
   instName: SymTab.Name;
   instActual: ARRAY [0 .. 15] OF SymTab.TypeIndex;
+  instKind: ARRAY [0 .. 15] OF INTEGER;
+  instVal:  ARRAY [0 .. 15] OF SymTab.Name;
   instN: CARDINAL;
   instFk: CARDINAL;   (* formal cursor while binding during re-parse *)
 
@@ -198,9 +202,36 @@ PROCEDURE InstBegin (name: ARRAY OF CHAR);
   BEGIN instActive := TRUE; CopyNm(name, instName); instN := 0;
     instFk := 0 END InstBegin;
 
-PROCEDURE InstAddActual (t: SymTab.TypeIndex);
+PROCEDURE InstActualKind (i: CARDINAL) : INTEGER;
   BEGIN
-    IF instN <= HIGH(instActual) THEN instActual[instN] := t; INC(instN) END
+    IF i >= instN THEN RETURN 0 END;
+    RETURN instKind[i]
+  END InstActualKind;
+
+PROCEDURE InstActualVal (i: CARDINAL; VAR v: SymTab.Name);
+  VAR k: CARDINAL;
+  BEGIN
+    v[0] := CHR(0);
+    IF i >= instN THEN RETURN END;
+    k := 0;
+    WHILE (k <= HIGH(v)) AND (instVal[i][k] # CHR(0)) DO
+      v[k] := instVal[i][k]; INC(k)
+    END;
+    v[k] := CHR(0)
+  END InstActualVal;
+
+PROCEDURE InstAddActual (kind: INTEGER; t: SymTab.TypeIndex;
+                         val: ARRAY OF CHAR);
+  VAR k: CARDINAL;
+  BEGIN
+    IF instN > HIGH(instActual) THEN RETURN END;
+    instKind[instN] := kind; instActual[instN] := t;
+    k := 0;
+    WHILE (k <= HIGH(instVal[instN])) AND (val[k] # CHR(0)) DO
+      instVal[instN][k] := val[k]; INC(k)
+    END;
+    instVal[instN][k] := CHR(0);
+    INC(instN)
   END InstAddActual;
 
 PROCEDURE InstEnd;
@@ -236,6 +267,24 @@ PROCEDURE RefineActualGet (i: CARDINAL) : SymTab.TypeIndex;
     RETURN refActual[i]
   END RefineActualGet;
 
+PROCEDURE RefineActualKind (i: CARDINAL) : INTEGER;
+  BEGIN
+    IF i >= refN THEN RETURN 0 END;
+    RETURN refKind[i]
+  END RefineActualKind;
+
+PROCEDURE RefineActualVal (i: CARDINAL; VAR v: SymTab.Name);
+  VAR k: CARDINAL;
+  BEGIN
+    v[0] := CHR(0);
+    IF i >= refN THEN RETURN END;
+    k := 0;
+    WHILE (k <= HIGH(v)) AND (refVal[i][k] # CHR(0)) DO
+      v[k] := refVal[i][k]; INC(k)
+    END;
+    v[k] := CHR(0)
+  END RefineActualVal;
+
 PROCEDURE NoteLabel (nm: ARRAY OF CHAR);
 (* Record a statement label; duplicate is 200. *)
   VAR i: CARDINAL;
@@ -494,27 +543,77 @@ PRODUCTIONS
      TYPE parameters only; actuals are type identifiers. *)
   GenericFormals
     = "(" GenericFormal { ";" GenericFormal } ")" .
-  GenericFormal                         (. VAR nm: SymTab.Name; .)
-    = GetIdent<nm>                      (. IF instActive THEN
-                                             IF NOT SymTab.EnterTypeParamBound(nm,
-                                                InstActualGet(instFk)) THEN
-                                               SemError(200) END
-                                           ELSIF NOT SymTab.EnterTypeParam(nm) THEN
-                                             SemError(200) END;
-                                           INC(instFk); .)
-      { "," GetIdent<nm>                (. IF instActive THEN
-                                             IF NOT SymTab.EnterTypeParamBound(nm,
-                                                InstActualGet(instFk)) THEN
-                                               SemError(200) END
-                                           ELSIF NOT SymTab.EnterTypeParam(nm) THEN
-                                             SemError(200) END;
-                                           INC(instFk); .) }
-      ":" "TYPE" .
+  GenericFormal                         (. VAR nm: SymTab.Name; vt: SymTab.TypeIndex;
+                                             names: ARRAY [0 .. 15] OF SymTab.Name;
+                                             nn, k: CARDINAL;
+                                             isTypeFormal: BOOLEAN; .)
+    =                                   (. nn := 0; .)
+      GetIdent<nm>                      (. k := 0;
+                                           WHILE (k <= HIGH(names[nn])) AND (nm[k] # CHR(0)) DO
+                                             names[nn][k] := nm[k]; INC(k) END;
+                                           names[nn][k] := CHR(0); INC(nn); .)
+      { "," GetIdent<nm>                (. k := 0;
+                                           WHILE (k <= HIGH(names[nn])) AND (nm[k] # CHR(0)) DO
+                                             names[nn][k] := nm[k]; INC(k) END;
+                                           names[nn][k] := CHR(0); INC(nn); .) }
+      ":"                               (. vt := SymTab.InvalidType; isTypeFormal := FALSE; .)
+      ( "TYPE"                          (. isTypeFormal := TRUE; .)
+      | TypeIdent<vt> )                 (. k := 0;
+                                           WHILE k < nn DO
+                                             IF isTypeFormal THEN
+                                               IF instActive THEN
+                                                 IF NOT SymTab.EnterTypeParamBound(names[k], InstActualGet(instFk)) THEN
+                                                   SemError(200) END
+                                               ELSIF NOT SymTab.EnterTypeParam(names[k]) THEN
+                                                 SemError(200) END
+                                             ELSE
+                                               IF NOT SymTab.Enter(names[k], SymTab.KindConst) THEN
+                                                 SemError(200) END;
+                                               SymTab.SetSymType(names[k], vt);
+                                               IF instActive THEN
+                                                 InstActualVal(instFk, nm);
+                                                 SymTab.SetSymVal(names[k], nm)
+                                               ELSE SymTab.SetSymVal(names[k], "0")
+                                               END
+                                             END;
+                                             INC(instFk); INC(k)
+                                           END; .) .
   Actuals
     = Actual { "," Actual } .
-  Actual                                (. VAR at: SymTab.TypeIndex; .)
-    = TypeIdent<at>                     (. IF refN <= HIGH(refActual) THEN
-                                             refActual[refN] := at; INC(refN)
+  Actual                                (. VAR at: SymTab.TypeIndex;
+                                             nm: SymTab.Name;
+                                             s: ARRAY [0 .. 255] OF CHAR;
+                                             qv: QbeGen.QVal;
+                                             isCh, isV: BOOLEAN;
+                                             k: CARDINAL; .)
+    =                                   (. isV := FALSE; at := SymTab.InvalidType; nm[0] := CHR(0); .)
+      ( integer                         (. LexString(s); QbeGen.NormInt(s, qv);
+                                           isV := TRUE; at := SymTab.IntType();
+                                           CopyNm(qv, nm); .)
+      | charConst                       (. LexString(s); QbeGen.NormLit(s, qv, isCh);
+                                           isV := TRUE; at := SymTab.CharType();
+                                           CopyNm(qv, nm); .)
+      | GetIdent<nm>                    (. IF SymTab.Lookup(nm)
+                                              AND ((SymTab.SymKind(nm) = SymTab.KindType)
+                                                OR (SymTab.SymKind(nm) = SymTab.KindPredef)) THEN
+                                              at := SymTab.SymType(nm); isV := FALSE
+                                            ELSIF SymTab.Lookup(nm)
+                                              AND (SymTab.SymKind(nm) = SymTab.KindConst) THEN
+                                              isV := TRUE; at := SymTab.SymType(nm);
+                                              IF NOT SymTab.GetSymVal(nm, s) THEN s[0] := CHR(0) END;
+                                              CopyNm(s, nm)
+                                            ELSE SemError(201);
+                                              at := SymTab.InvalidType; isV := FALSE
+                                            END; .) )
+                                        (. IF refN <= HIGH(refActual) THEN
+                                             IF isV THEN refKind[refN] := 1
+                                             ELSE refKind[refN] := 0 END;
+                                             refActual[refN] := at;
+                                             k := 0;
+                                             WHILE (k <= HIGH(refVal[refN])) AND (nm[k] # CHR(0)) DO
+                                               refVal[refN][k] := nm[k]; INC(k) END;
+                                             refVal[refN][k] := CHR(0);
+                                             INC(refN)
                                            END; .) .
   Unit
     =                                   (. isGen := FALSE;

تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 3676 - 3577
compiler/src/M2.lst


+ 5 - 2
compiler/src/compiler.frm

@@ -8,9 +8,11 @@ MODULE -->Grammar;
   FROM -->Scanner IMPORT lst, src, errors, Error, CharAt;
   FROM -->Parser IMPORT Parse, Successful, GetUnit,
     InInst, InstBegin, InstAddActual, InstEnd, InstNameGet, InstActualGet,
+    InstActualKind, InstActualVal,
     UnitNameGet, UnitIsGeneric, UnitIsDefModule,
     RefineSeen, RefineIsDef, RefineInst, RefineGen,
-    RefineActualCount, RefineActualGet, SetTwoPhase;
+    RefineActualCount, RefineActualGet, RefineActualKind, RefineActualVal,
+    SetTwoPhase;
   IMPORT
     Strings, Storage, SYSTEM, FileIO, SymTab, QbeGen, AST, Lower;
   FROM libc IMPORT exit;
@@ -401,7 +403,8 @@ MODULE -->Grammar;
     InstBegin(iname);
     j := 0;
     WHILE j < RefineActualCount() DO
-      InstAddActual(RefineActualGet(j)); INC(j)
+      RefineActualVal(j, iname);
+      InstAddActual(RefineActualKind(j), RefineActualGet(j), iname); INC(j)
     END;
     AST.Init;
     Lower.BeginUnit;

+ 6 - 1
compiler/src/parser.frm

@@ -145,10 +145,13 @@ PROCEDURE GetUnit (): AST.Node;
 
 PROCEDURE InInst (): BOOLEAN;
 PROCEDURE InstBegin (name: ARRAY OF CHAR);
-PROCEDURE InstAddActual (t: SymTab.TypeIndex);
+PROCEDURE InstAddActual (kind: INTEGER; t: SymTab.TypeIndex;
+                         val: ARRAY OF CHAR);
 PROCEDURE InstEnd;
 PROCEDURE InstNameGet (VAR nm: SymTab.Name);
 PROCEDURE InstActualGet (i: CARDINAL): SymTab.TypeIndex;
+PROCEDURE InstActualKind (i: CARDINAL): INTEGER;
+PROCEDURE InstActualVal (i: CARDINAL; VAR v: SymTab.Name);
 
 PROCEDURE UnitNameGet (VAR nm: SymTab.Name);
 PROCEDURE UnitIsGeneric (): BOOLEAN;
@@ -160,6 +163,8 @@ PROCEDURE RefineInst (VAR nm: SymTab.Name);
 PROCEDURE RefineGen (VAR nm: SymTab.Name);
 PROCEDURE RefineActualCount (): CARDINAL;
 PROCEDURE RefineActualGet (i: CARDINAL): SymTab.TypeIndex;
+PROCEDURE RefineActualKind (i: CARDINAL): INTEGER;
+PROCEDURE RefineActualVal (i: CARDINAL; VAR v: SymTab.Name);
 
 (* Returns TRUE if no errors have been recorded while parsing *)
 

+ 4 - 0
compiler/tests/g_buf.def

@@ -0,0 +1,4 @@
+GENERIC DEFINITION MODULE Buf (size : CARDINAL);
+TYPE T = ARRAY [0..size] OF CHAR;
+PROCEDURE Mark(x : CHAR);
+END Buf.

+ 4 - 0
compiler/tests/g_buf.mod

@@ -0,0 +1,4 @@
+GENERIC IMPLEMENTATION MODULE Buf;
+PROCEDURE Mark(x : CHAR);
+BEGIN END Mark;
+END Buf.

+ 2 - 0
compiler/tests/g_buf10.def

@@ -0,0 +1,2 @@
+DEFINITION MODULE Buf10 = Buf(10);
+END Buf10.

+ 2 - 0
compiler/tests/g_buf10.mod

@@ -0,0 +1,2 @@
+IMPLEMENTATION MODULE Buf10 = Buf(10);
+END Buf10.

+ 4 - 0
compiler/tests/g_bufprog.mod

@@ -0,0 +1,4 @@
+MODULE BufProg;
+FROM Buf10 IMPORT T;
+VAR a : T; ExitCode : INTEGER;
+BEGIN ExitCode := HIGH(a) + 32 END BufProg.

+ 18 - 0
docs/analysis_generics.md

@@ -24,6 +24,24 @@
 > `BeginDef` into the `;` branch (so the refinement does not
 > pre-register `X`), a `SymTab.EnterTypeParamBound`, a grammar
 > instantiation context + accessors, and driver re-parse logic.
+>
+> **Done (Increment 3, partial — 2026-10-16): value (constant)
+> parameters.**  A generic formal may now be a value rather than a
+> type: `GENERIC DEFINITION MODULE Buf (size : CARDINAL); TYPE T = ARRAY
+> [0..size] OF CHAR; …` instantiated by `MODULE X = Buf(10);`.  Grammar:
+> `GenericFormal` collects its names then accepts `: TYPE` (type formal)
+> or `: TypeIdent` (value formal); `Actual` accepts an integer, `charConst`
+> or an identifier (type name = type actual, `CONST` name = value
+> actual).  Refinement actuals now carry a **kind** (type/value) and a
+> **value text** (`refKind`/`refVal`, `instKind`/`instVal` +
+> `InstActualKind`/`InstActualVal`/`RefineActualKind`/`RefineActualVal`).
+> On instantiation a value formal becomes a `CONST` bound to the actual
+> value; in the **abstract template** it is a `CONST` with a placeholder
+> value (`"0"`), so template parsing succeeds — templates are never
+> lowered, so only instances matter.  Suite tests `BufProg` (and a
+> second instance, `Buf(3)`), verified end-to-end (`HIGH(T)` reflects the
+> bound size).  Suite 209/209, fixpoint OK, corpus unchanged.
+> Procedure parameters / constraints remain for a later increment.
 
 Study reviewed: `../Generics/` (the three `m2-generics-coco-r-*.md`
 analyses, the `m2generic/` prototype: `M2Generic.atg`,

برخی فایل ها در این مقایسه diff نمایش داده نمی شوند زیرا تعداد فایل ها بسیار زیاد است