Sfoglia il codice sorgente

step10: module BEGIN bodies + self-reference; 143/143 tests green

Eric Streit 3 settimane fa
parent
commit
e239d3dd3c
31 ha cambiato i file con 2655 aggiunte e 2124 eliminazioni
  1. BIN
      BBadDup.MC4
  2. BIN
      BBadNest.MC4
  3. BIN
      BBadRet.MC4
  4. BIN
      BCall.MC4
  5. BIN
      BInit.MC4
  6. BIN
      BOrder.MC4
  7. BIN
      M2c
  8. 85 21
      M2c.atg
  9. 2149 2085
      M2c.lst
  10. 84 18
      M2cP.mod
  11. BIN
      M2cP.o
  12. 7 0
      MGen.def
  13. 30 0
      MGen.mod
  14. BIN
      MGen.o
  15. 7 0
      SymTab.def
  16. 34 0
      SymTab.mod
  17. BIN
      SymTab.o
  18. 50 0
      docs/summary_step10.md
  19. 10 0
      run_tests.sh
  20. 22 0
      tests/b_bad_dup.LST
  21. 15 0
      tests/b_bad_dup.mod
  22. 21 0
      tests/b_bad_nest.LST
  23. 14 0
      tests/b_bad_nest.mod
  24. 17 0
      tests/b_bad_ret.LST
  25. 10 0
      tests/b_bad_ret.mod
  26. 22 0
      tests/b_call.LST
  27. 16 0
      tests/b_call.mod
  28. 16 0
      tests/b_init.LST
  29. 10 0
      tests/b_init.mod
  30. 21 0
      tests/b_order.LST
  31. 15 0
      tests/b_order.mod

BIN
BBadDup.MC4


BIN
BBadNest.MC4


BIN
BBadRet.MC4


BIN
BCall.MC4


BIN
BInit.MC4


BIN
BOrder.MC4


BIN
M2c


+ 85 - 21
M2c.atg

@@ -3,9 +3,10 @@ COMPILER M2c
    (see MGen for details).
 
    - program module only, no DEFINITION / IMPLEMENTATION split
-   - local MODULEs (single-file, no nesting, no bodies): EXPORT of
-     VARs, CONSTs, TYPEs and procedures (value/VAR params, functions,
-     open array formals with fixed actuals); use as M.x / M.P(args);
+   - local MODULEs (single-file, no nesting): EXPORT of VARs, CONSTs,
+     TYPEs and procedures (value/VAR params, functions, open array
+     formals with fixed actuals); use as M.x / M.P(args); optional
+     BEGIN..END init bodies run at startup in declaration order;
      no PRIORITY
    - procedures: declarations (nested), value and VAR parameters,
      functions with RETURN, recursion, FORWARD headings;
@@ -254,10 +255,13 @@ PRODUCTIONS
                                            SymTab.CloseProc;
                                            MGen.DefLabel(endL); .) ) .
   ModuleDecl                            (. VAR n, m, e: SymTab.Name;
-                                             noMod, enterOk: BOOLEAN; .)
+                                             noMod, enterOk,
+                                             hasInit: BOOLEAN;
+                                             initL, initN: INTEGER; .)
     = "MODULE"                          (. noMod := SymTab.InProc()
                                                   OR SymTab.InModule();
-                                           enterOk := FALSE; .)
+                                           enterOk := FALSE;
+                                           hasInit := FALSE; .)
       GetIdent<n>                       (. IF noMod THEN
                                            SemError(230)
                                          ELSIF ~SymTab.EnterModule(n) THEN
@@ -278,10 +282,24 @@ PRODUCTIONS
                                          END; .) } ]
       ";"
       { Declaration }
+      [ "BEGIN"                         (. hasInit := TRUE;
+                                           IF ~noMod & enterOk THEN
+                                             initL := MGen.NewLabel();
+                                             MGen.Jmp(initL);
+                                             initN := MGen.ModInitBegin();
+                                             IF initN < 0 THEN
+                                               SemError(230)
+                                             END
+                                           END; .)
+        StatSeq ]
       "END"
       GetIdent<m>                       (. IF ~SymTab.Equal(n, m) THEN
                                            SemError(202)
                                          END;
+                                         IF hasInit & ~noMod & enterOk THEN
+                                           MGen.ModInitEnd(initN);
+                                           MGen.DefLabel(initL)
+                                         END;
                                          IF ~noMod & enterOk THEN
                                            IF ~SymTab.ExitModule() THEN
                                              SemError(201)
@@ -341,9 +359,15 @@ PRODUCTIONS
                                            IF SymTab.ExpKind(n, m)
                                               = SymTab.KindType THEN
                                              t := SymTab.ExpType(n, m)
+                                           ELSIF SymTab.SelfKind(n, m)
+                                              = SymTab.KindType THEN
+                                             t := SymTab.SymType(m)
                                            ELSE
-                                             IF SymTab.ExpKind(n, m) = -1 THEN
-                                               SemError(201)
+                                             IF SymTab.ExpKind(n, m) < 0 THEN
+                                               IF SymTab.SelfKind(n, m) < 0 THEN
+                                                 SemError(201)
+                                               ELSE SemError(221)
+                                               END
                                              ELSE SemError(221)
                                              END;
                                              t := SymTab.InvalidType
@@ -840,6 +864,13 @@ PRODUCTIONS
                                            IF isModP THEN
                                              modPNum := SymTab.ExpProc(pn,
                                                               exp);
+                                             IF (modPNum < 0)
+                                                & (SymTab.SelfKind(pn,
+                                                     exp)
+                                                   = SymTab.KindProc) THEN
+                                               modPNum :=
+                                                 SymTab.ProcNum(exp)
+                                             END;
                                              IF modPNum < 0 THEN
                                                IF SymTab.ExpKind(pn,
                                                     exp) # -1 THEN
@@ -1442,6 +1473,7 @@ PRODUCTIONS
                                              esl, ebytes: CARDINAL;
                                              firstT: BOOLEAN;
                                              clsI: INTEGER;
+                                             sk: INTEGER;
                                              qM: SymTab.Name; .)
     =                                   (. sfx := FALSE; .)
       { "."                             (. firstT := ~sfx;
@@ -1462,13 +1494,37 @@ PRODUCTIONS
                                            END; .)
         GetIdent<m>                     (. IF (k = SymTab.KindModule) THEN
                                              IF SymTab.ExpKind(bn, m) = -1 THEN
-                                               SemError(201);
-                                               MGen.CopyName(m, lx);
-                                               t := SymTab.InvalidType;
-                                               IF doLoad THEN
-                                                 MGen.Drop; MGen.PushInt(0)
-                                               ELSIF firstT THEN
-                                               ELSE MGen.Drop
+                                               sk := SymTab.SelfKind(bn, m);
+                                               IF sk = SymTab.KindProc THEN
+                                                 MGen.CopyName(m, lx);
+                                                 t := SymTab.InvalidType;
+                                                 IF doLoad THEN
+                                                   MGen.Drop; MGen.PushInt(0)
+                                                 ELSIF firstT THEN
+                                                 ELSE MGen.Drop
+                                                 END
+                                               ELSIF sk # -1 THEN
+                                                 t := SymTab.SymType(m);
+                                                 k := sk;
+                                                 SymTab.SelfQual(m, qM);
+                                                 IF doLoad THEN
+                                                   MGen.Drop;
+                                                   MGen.GlobalAddr(qM)
+                                                 ELSE
+                                                   IF firstT THEN
+                                                   ELSE MGen.Drop
+                                                   END;
+                                                   MGen.GlobalAddr(qM)
+                                                 END
+                                               ELSE
+                                                 SemError(201);
+                                                 MGen.CopyName(m, lx);
+                                                 t := SymTab.InvalidType;
+                                                 IF doLoad THEN
+                                                   MGen.Drop; MGen.PushInt(0)
+                                                 ELSIF firstT THEN
+                                                 ELSE MGen.Drop
+                                                 END
                                                END
                                              ELSIF SymTab.ExpKind(bn, m)
                                                     = SymTab.KindProc THEN
@@ -1900,7 +1956,7 @@ PRODUCTIONS
                                              lxD, lx2: MGen.LitStr;
                                              v2: BOOLEAN;
                                              vn2: SymTab.Name;
-                                             vi: INTEGER;
+                                             vi, mpF: INTEGER;
                                              c: CARDINAL;
                                              b: LONGCARD;
                                              sfxF: BOOLEAN;
@@ -2029,12 +2085,20 @@ PRODUCTIONS
                                              ELSIF (SymTab.SymKind(bnF)
                                                        = SymTab.KindModule)
                                                 & sfxF
-                                                & (SymTab.StrLen(lxD) > 0)
-                                                & (SymTab.ExpProc(bnF,
-                                                     lxD) >= 0) THEN
-                                               t := SymTab.ProcRetByNum(
-                                                      SymTab.ExpProc(bnF,
-                                                        lxD))
+                                                & (SymTab.StrLen(lxD) > 0) THEN
+                                               mpF := SymTab.ExpProc(bnF,
+                                                        lxD);
+                                               IF (mpF < 0)
+                                                  & (SymTab.SelfKind(bnF,
+                                                       lxD)
+                                                     = SymTab.KindProc) THEN
+                                                 mpF := SymTab.ProcNum(lxD)
+                                               END;
+                                               IF mpF >= 0 THEN
+                                                 t := SymTab.ProcRetByNum(mpF)
+                                               ELSE
+                                                 t := SymTab.InvalidType
+                                               END
                                              ELSE
                                                t := SymTab.InvalidType
                                              END

File diff suppressed because it is too large
+ 2149 - 2085
M2c.lst


+ 84 - 18
M2cP.mod

@@ -272,7 +272,7 @@ PROCEDURE Fact (VAR t: SymTab.TypeIndex; VAR lx: MGen.LitStr;
     lxD, lx2: MGen.LitStr;
     v2: BOOLEAN;
     vn2: SymTab.Name;
-    vi: INTEGER;
+    vi, mpF: INTEGER;
     c: CARDINAL;
     b: LONGCARD;
     sfxF: BOOLEAN;
@@ -414,12 +414,20 @@ PROCEDURE Fact (VAR t: SymTab.TypeIndex; VAR lx: MGen.LitStr;
             ELSIF (SymTab.SymKind(bnF)
                       = SymTab.KindModule)
                & sfxF
-               & (SymTab.StrLen(lxD) > 0)
-               & (SymTab.ExpProc(bnF,
-                    lxD) >= 0) THEN
-              t := SymTab.ProcRetByNum(
-                     SymTab.ExpProc(bnF,
-                       lxD))
+               & (SymTab.StrLen(lxD) > 0) THEN
+              mpF := SymTab.ExpProc(bnF,
+                       lxD);
+              IF (mpF < 0)
+                 & (SymTab.SelfKind(bnF,
+                      lxD)
+                    = SymTab.KindProc) THEN
+                mpF := SymTab.ProcNum(lxD)
+              END;
+              IF mpF >= 0 THEN
+                t := SymTab.ProcRetByNum(mpF)
+              ELSE
+                t := SymTab.InvalidType
+              END
             ELSE
               t := SymTab.InvalidType
             END
@@ -730,6 +738,13 @@ PROCEDURE CallTail (pn: SymTab.Name; exp: SymTab.Name; sfx: BOOLEAN;
     IF isModP THEN
       modPNum := SymTab.ExpProc(pn,
                        exp);
+      IF (modPNum < 0)
+         & (SymTab.SelfKind(pn,
+              exp)
+            = SymTab.KindProc) THEN
+        modPNum :=
+          SymTab.ProcNum(exp)
+      END;
       IF modPNum < 0 THEN
         IF SymTab.ExpKind(pn,
              exp) # -1 THEN
@@ -804,6 +819,7 @@ PROCEDURE DesignTail (VAR t: SymTab.TypeIndex; VAR k: INTEGER;
     esl, ebytes: CARDINAL;
     firstT: BOOLEAN;
     clsI: INTEGER;
+    sk: INTEGER;
     qM: SymTab.Name;
   BEGIN
     sfx := FALSE;;
@@ -829,13 +845,37 @@ PROCEDURE DesignTail (VAR t: SymTab.TypeIndex; VAR k: INTEGER;
         GetIdent(m);
         IF (k = SymTab.KindModule) THEN
           IF SymTab.ExpKind(bn, m) = -1 THEN
-            SemError(201);
-            MGen.CopyName(m, lx);
-            t := SymTab.InvalidType;
-            IF doLoad THEN
-              MGen.Drop; MGen.PushInt(0)
-            ELSIF firstT THEN
-            ELSE MGen.Drop
+            sk := SymTab.SelfKind(bn, m);
+            IF sk = SymTab.KindProc THEN
+              MGen.CopyName(m, lx);
+              t := SymTab.InvalidType;
+              IF doLoad THEN
+                MGen.Drop; MGen.PushInt(0)
+              ELSIF firstT THEN
+              ELSE MGen.Drop
+              END
+            ELSIF sk # -1 THEN
+              t := SymTab.SymType(m);
+              k := sk;
+              SymTab.SelfQual(m, qM);
+              IF doLoad THEN
+                MGen.Drop;
+                MGen.GlobalAddr(qM)
+              ELSE
+                IF firstT THEN
+                ELSE MGen.Drop
+                END;
+                MGen.GlobalAddr(qM)
+              END
+            ELSE
+              SemError(201);
+              MGen.CopyName(m, lx);
+              t := SymTab.InvalidType;
+              IF doLoad THEN
+                MGen.Drop; MGen.PushInt(0)
+              ELSIF firstT THEN
+              ELSE MGen.Drop
+              END
             END
           ELSIF SymTab.ExpKind(bn, m)
                  = SymTab.KindProc THEN
@@ -2293,9 +2333,15 @@ PROCEDURE QualIdent (VAR t: SymTab.TypeIndex);
       IF SymTab.ExpKind(n, m)
          = SymTab.KindType THEN
         t := SymTab.ExpType(n, m)
+      ELSIF SymTab.SelfKind(n, m)
+         = SymTab.KindType THEN
+        t := SymTab.SymType(m)
       ELSE
-        IF SymTab.ExpKind(n, m) = -1 THEN
-          SemError(201)
+        IF SymTab.ExpKind(n, m) < 0 THEN
+          IF SymTab.SelfKind(n, m) < 0 THEN
+            SemError(201)
+          ELSE SemError(221)
+          END
         ELSE SemError(221)
         END;
         t := SymTab.InvalidType
@@ -2439,12 +2485,15 @@ PROCEDURE ConstExpr (VAR t: SymTab.TypeIndex; VAR lx: MGen.LitStr);
 
 PROCEDURE ModuleDecl;
   VAR n, m, e: SymTab.Name;
-    noMod, enterOk: BOOLEAN;
+    noMod, enterOk,
+    hasInit: BOOLEAN;
+    initL, initN: INTEGER;
   BEGIN
     Expect(5);
     noMod := SymTab.InProc()
            OR SymTab.InModule();
-    enterOk := FALSE;;
+    enterOk := FALSE;
+    hasInit := FALSE;;
     GetIdent(n);
     IF noMod THEN
     SemError(230)
@@ -2475,11 +2524,28 @@ PROCEDURE ModuleDecl;
     WHILE (sym = 5) OR (sym = 13) OR (sym = 14) OR (sym = 15) OR (sym = 18) DO
       Declaration;
     END;
+    IF (sym = 11) THEN
+      Get;
+      hasInit := TRUE;
+      IF ~noMod & enterOk THEN
+        initL := MGen.NewLabel();
+        MGen.Jmp(initL);
+        initN := MGen.ModInitBegin();
+        IF initN < 0 THEN
+          SemError(230)
+        END
+      END;;
+      StatSeq;
+    END;
     Expect(12);
     GetIdent(m);
     IF ~SymTab.Equal(n, m) THEN
     SemError(202)
     END;
+    IF hasInit & ~noMod & enterOk THEN
+    MGen.ModInitEnd(initN);
+    MGen.DefLabel(initL)
+    END;
     IF ~noMod & enterOk THEN
     IF ~SymTab.ExitModule() THEN
       SemError(201)

BIN
M2cP.o


+ 7 - 0
MGen.def

@@ -269,6 +269,13 @@ PROCEDURE CallDisplay (num: INTEGER; np: CARDINAL);
 PROCEDURE Leave (nPar: CARDINAL; func: BOOLEAN);
 (* 84H (proper) or 85H (function) procedure leave. *)
 
+PROCEDURE ModInitBegin (): INTEGER;
+(* Opens a module init body as a parameterless proper procedure,
+   recorded for the startup calls in BeginBody. -1 when full. *)
+
+PROCEDURE ModInitEnd (num: INTEGER);
+(* Closes a module init body (no-op for num < 0). *)
+
 (* ---- actual parameters (nested-call-safe frame stack) ---- *)
 
 PROCEDURE ActBegin (pn: ARRAY OF CHAR);

+ 30 - 0
MGen.mod

@@ -107,6 +107,8 @@ VAR
   procAddr : ARRAY [0 .. 64] OF INTEGER;
   maxNum : CARDINAL;
   mainAddr : CARDINAL;
+  initNums : ARRAY [0 .. 7] OF INTEGER;
+  nInits : CARDINAL;
 
 (* ---------------- byte helpers ---------------- *)
 
@@ -257,6 +259,7 @@ PROCEDURE OpenModule (name: ARRAY OF CHAR);
     nLab := 0; nFix := 0; loopTop := 0; noSup := 0; noEmit := 0;
   actTop := 0; withTop := 0;
     maxNum := 0; mainAddr := 0;
+    nInits := 0;
     i := 0;
     WHILE i <= 64 DO procAddr[i] := -1; INC(i) END;
     inBody := FALSE;
@@ -348,6 +351,11 @@ PROCEDURE BeginBody;
       PushValue(inits[i].kind, inits[i].ival, inits[i].bits);
       EmitOpB(OPstoreGlb, inits[i].idx);
       INC(i)
+    END;
+    i := 0;
+    WHILE i < nInits DO
+      CallProc(initNums[i]);
+      INC(i)
     END
   END BeginBody;
 
@@ -599,6 +607,27 @@ PROCEDURE CallDisplay (num: INTEGER; np: CARDINAL);
     EmitOpB(OPcallFrame, VAL(CARDINAL, num))
   END CallDisplay;
 
+PROCEDURE ModInitBegin (): INTEGER;
+(* Opens a module init body as a parameterless proper procedure
+   (module bodies declare no locals; globals are used directly).
+   Records its number for the startup calls in BeginBody.
+   -1 when the proc table or init list is full. *)
+  VAR num : INTEGER;
+  BEGIN
+    IF (maxNum >= 64) OR (nInits > 7) THEN RETURN -1 END;
+    num := VAL(INTEGER, maxNum + 1);
+    initNums[nInits] := num;
+    INC(nInits);
+    ProcEntry(num, 0);
+    RETURN num
+  END ModInitBegin;
+
+PROCEDURE ModInitEnd (num: INTEGER);
+(* Closes a module init body (no-op for num < 0). *)
+  BEGIN
+    IF num >= 0 THEN Leave(0, FALSE) END
+  END ModInitEnd;
+
 PROCEDURE Leave (nPar: CARDINAL; func: BOOLEAN);
   BEGIN
     IF nPar > 255 THEN nPar := 255 END;
@@ -1619,6 +1648,7 @@ BEGIN
   nLab := 0; nFix := 0; loopTop := 0; noSup := 0; noEmit := 0;
   actTop := 0; withTop := 0;
   maxNum := 0; mainAddr := 0;
+  nInits := 0;
   inBody := FALSE;
   modName[0] := 0C
 END MGen.

BIN
MGen.o


+ 7 - 0
SymTab.def

@@ -148,6 +148,13 @@ PROCEDURE ExpQual (mod, exp: ARRAY OF CHAR; VAR qual: Name);
 (* Qualified MGen name ("M.x"), empty if absent / not a variable
    or constant. *)
 
+PROCEDURE SelfKind (mod, exp: ARRAY OF CHAR): INTEGER;
+(* Kind of exp as M.exp from inside M itself (live body scope,
+   since exports resolve only at END). -1 if not applicable. *)
+
+PROCEDURE SelfQual (exp: ARRAY OF CHAR; VAR qual: Name);
+(* CurMod.exp for a self reference (call only when SelfKind # -1). *)
+
 PROCEDURE PushRecord (t: TypeIndex): BOOLEAN;
 (* Pushes a scope containing t's fields (as KindField). FALSE if t
    is not a record type (or invalid). Caller must PopScope after. *)

+ 34 - 0
SymTab.mod

@@ -83,6 +83,7 @@ VAR
   retSt : ARRAY [0 .. MaxPDepth] OF TypeIndex;
   modNames : ARRAY [0 .. 7] OF Name;
   modTop : CARDINAL;
+  modLevs : ARRAY [0 .. 7] OF CARDINAL;
   modExps : ARRAY [0 .. 7] OF ARRAY [0 .. 31] OF Name;
   modNExps : ARRAY [0 .. 7] OF CARDINAL;
   expMod : ARRAY [0 .. 127] OF Name;
@@ -395,6 +396,7 @@ PROCEDURE EnterModule (name: ARRAY OF CHAR): BOOLEAN;
     modNExps[modTop] := 0;
     INC(modTop);
     PushScope;
+    modLevs[modTop - 1] := curLev;
     RETURN TRUE
   END EnterModule;
 
@@ -513,6 +515,38 @@ PROCEDURE ExpQual (mod, exp: ARRAY OF CHAR; VAR qual: Name);
     IF k <= HIGH(qual) THEN qual[k] := 0C END
   END ExpQual;
 
+PROCEDURE SelfKind (mod, exp: ARRAY OF CHAR): INTEGER;
+(* Kind of exp as a self-qualified M.exp reference from inside module
+   M itself (the export table only fills at END, so the live body
+   scope is consulted). -1 when not inside M or not at body level. *)
+  VAR idx : INTEGER;
+  BEGIN
+    IF modTop = 0 THEN RETURN -1 END;
+    IF ~Equal(modNames[modTop - 1], mod) THEN RETURN -1 END;
+    idx := Find(exp);
+    IF idx = -1 THEN RETURN -1 END;
+    IF syms[idx].lev # modLevs[modTop - 1] THEN RETURN -1 END;
+    RETURN syms[idx].kind
+  END SelfKind;
+
+PROCEDURE SelfQual (exp: ARRAY OF CHAR; VAR qual: Name);
+(* CurMod.exp for a self reference (call only when SelfKind # -1). *)
+  VAR m : Name;
+    j, k : CARDINAL;
+  BEGIN
+    CurModName(m);
+    k := 0; j := 0;
+    WHILE (k < HIGH(qual)) & (m[j] # 0C) DO
+      qual[k] := m[j]; INC(k); INC(j)
+    END;
+    IF k <= HIGH(qual) THEN qual[k] := "."; INC(k) END;
+    j := 0;
+    WHILE (k < HIGH(qual)) & (exp[j] # 0C) DO
+      qual[k] := exp[j]; INC(k); INC(j)
+    END;
+    IF k <= HIGH(qual) THEN qual[k] := 0C END
+  END SelfQual;
+
 (* ---------------- type descriptors ---------------- *)
 
 PROCEDURE NewDesc (form: INTEGER; ref: TypeIndex): TypeIndex;

BIN
SymTab.o


+ 50 - 0
docs/summary_step10.md

@@ -0,0 +1,50 @@
+# Step 10 — Module BEGIN bodies + self-reference (uncommitted)
+
+143/143 tests green (137 + 3 run + 3 rejection), mc64 boot + example
+green, both Showcases unchanged (157, 83).
+
+## Goal
+
+Complete single-file local modules: optional `BEGIN..END` init bodies run
+at startup in declaration order, including calls to the module's own
+procedures (plain and `M.`-qualified).
+
+## What was built
+
+- `MGen`: module inits compile as parameterless proper procedures
+  (`ModInitBegin` allocates a proc-table number + `ENTER`, `ModInitEnd`
+  emits `LEAVE`); `BeginBody` calls them in order after const inits,
+  before program statements. Max 8 inits (module limit), sharing the 64
+  proc numbers (print helper still takes `maxNum+1` at `EndModule`).
+- `M2c.atg` `ModuleDecl`: optional `BEGIN StatSeq`, jumped over inline
+  (`Jmp`/`DefLabel` like procedures), skipped entirely for
+  nested/duplicate modules. `RETURN` in a body is already 232 (not in a
+  proc); header updated (`no bodies` dropped).
+- `SymTab`: `modLevs[]` records each module's body scope level;
+  `SelfKind(mod, exp)` resolves `M.x` against the live body scope (the
+  export table only fills at `END`), guarded to body level so nested
+  scopes can't hijack; `SelfQual` builds `M.x` for codegen.
+- `M2c.atg` call sites use it: `DesignTail` (vars/consts/procs),
+  `CallTail` (by-number via `ProcNum`), `Fact` (return types),
+  `QualIdent` (`M.T` inside `M`).
+
+## Tests — 143/143 (137 + 3 + 3)
+
+3 run: `b_init` 42, `b_order` 111 (two inits, order + cross-module read),
+`b_call` 15 (plain `Inc()` and `M.Inc()` from init). 3 rejections, each
+exactly one error: `b_bad_ret` 232, `b_bad_nest` 230, `b_bad_dup` 200.
+
+## Bugs found and fixed
+
+1. `M.Inc()` inside `M` gave 201: the export table is empty until `END`.
+   Self-scope fallback fixes vars, consts, procs, and types uniformly.
+2. gm2 16.0.1 ICE (deterministic, no source location) on
+   `x = -1 & (y = -1)` in generated `M2cP.mod` — minimized to
+   `IF a = -1 & (b = -1) THEN END` in 20 lines. Workaround: nested `IF`s
+   with `< 0` (single `F() = -1` and `(x < 0) & ...` shapes compile).
+   New rule: never compare against a negative literal inside an `&` chain.
+
+## Known limits (deferred)
+
+`DEFINITION`/`IMPLEMENTATION` split (the remaining big item), `WITH`-field
+`VAR` actuals, `CHAR`/`BOOLEAN` tails as `VAR` actuals, open-to-open.

+ 10 - 0
run_tests.sh

@@ -273,5 +273,15 @@ expect_fail t_bad_mtype.mod "not a type name"
 expect_fail t_bad_mghost.mod "undeclared identifier"
 expect_fail t_bad_mmod.mod "not supported in this phase"
 
+echo "=== Step-10 run tests (module BEGIN bodies) ==="
+expect_run b_init.mod 42
+expect_run b_order.mod 111
+expect_run b_call.mod 15
+
+echo "=== Step-10 rejection tests ==="
+expect_fail b_bad_ret.mod "bad RETURN"
+expect_fail b_bad_nest.mod "not supported in this phase"
+expect_fail b_bad_dup.mod "duplicate identifier"
+
 echo "=== $pass passed, $fail failed ==="
 test "$fail" = 0

+ 22 - 0
tests/b_bad_dup.LST

@@ -0,0 +1,22 @@
+Listing:
+
+    1  MODULE BBadDup;
+    2  MODULE M EXPORT cnt;
+    3  VAR cnt : INTEGER;
+    4  BEGIN
+    5    cnt := 1
+    6  END M;
+    7  MODULE M EXPORT k;
+*****         ^ duplicate identifier
+    8  VAR k : INTEGER;
+    9  BEGIN
+   10    k := 2
+   11  END M;
+   12  VAR ExitCode : INTEGER;
+   13  BEGIN
+   14    ExitCode := 0
+   15  END BBadDup.
+
+    1 error
+
+

+ 15 - 0
tests/b_bad_dup.mod

@@ -0,0 +1,15 @@
+MODULE BBadDup;
+MODULE M EXPORT cnt;
+VAR cnt : INTEGER;
+BEGIN
+  cnt := 1
+END M;
+MODULE M EXPORT k;
+VAR k : INTEGER;
+BEGIN
+  k := 2
+END M;
+VAR ExitCode : INTEGER;
+BEGIN
+  ExitCode := 0
+END BBadDup.

+ 21 - 0
tests/b_bad_nest.LST

@@ -0,0 +1,21 @@
+Listing:
+
+    1  MODULE BBadNest;
+    2  VAR ExitCode : INTEGER;
+    3  PROCEDURE P;
+    4  MODULE M EXPORT cnt;
+*****         ^ not supported in this phase
+    5  VAR cnt : INTEGER;
+    6  BEGIN
+    7    cnt := 1
+    8  END M;
+    9  BEGIN
+   10    ExitCode := 0
+   11  END P;
+   12  BEGIN
+   13    ExitCode := 0
+   14  END BBadNest.
+
+    1 error
+
+

+ 14 - 0
tests/b_bad_nest.mod

@@ -0,0 +1,14 @@
+MODULE BBadNest;
+VAR ExitCode : INTEGER;
+PROCEDURE P;
+MODULE M EXPORT cnt;
+VAR cnt : INTEGER;
+BEGIN
+  cnt := 1
+END M;
+BEGIN
+  ExitCode := 0
+END P;
+BEGIN
+  ExitCode := 0
+END BBadNest.

+ 17 - 0
tests/b_bad_ret.LST

@@ -0,0 +1,17 @@
+Listing:
+
+    1  MODULE BBadRet;
+    2  MODULE M EXPORT cnt;
+    3  VAR cnt : INTEGER;
+    4  BEGIN
+    5    RETURN
+*****    ^ bad RETURN
+    6  END M;
+    7  VAR ExitCode : INTEGER;
+    8  BEGIN
+    9    ExitCode := 0
+   10  END BBadRet.
+
+    1 error
+
+

+ 10 - 0
tests/b_bad_ret.mod

@@ -0,0 +1,10 @@
+MODULE BBadRet;
+MODULE M EXPORT cnt;
+VAR cnt : INTEGER;
+BEGIN
+  RETURN
+END M;
+VAR ExitCode : INTEGER;
+BEGIN
+  ExitCode := 0
+END BBadRet.

+ 22 - 0
tests/b_call.LST

@@ -0,0 +1,22 @@
+Listing:
+
+    1  MODULE BCall;
+    2  MODULE M EXPORT cnt, Inc;
+    3  VAR cnt : INTEGER;
+    4  PROCEDURE Inc;
+    5  BEGIN
+    6    cnt := cnt + 5
+    7  END Inc;
+    8  BEGIN
+    9    Inc();
+   10    M.Inc()
+   11  END M;
+   12  VAR ExitCode : INTEGER;
+   13  BEGIN
+   14    M.Inc();
+   15    ExitCode := M.cnt
+   16  END BCall.
+
+    0 errors
+
+

+ 16 - 0
tests/b_call.mod

@@ -0,0 +1,16 @@
+MODULE BCall;
+MODULE M EXPORT cnt, Inc;
+VAR cnt : INTEGER;
+PROCEDURE Inc;
+BEGIN
+  cnt := cnt + 5
+END Inc;
+BEGIN
+  Inc();
+  M.Inc()
+END M;
+VAR ExitCode : INTEGER;
+BEGIN
+  M.Inc();
+  ExitCode := M.cnt
+END BCall.

+ 16 - 0
tests/b_init.LST

@@ -0,0 +1,16 @@
+Listing:
+
+    1  MODULE BInit;
+    2  MODULE M EXPORT cnt;
+    3  VAR cnt : INTEGER;
+    4  BEGIN
+    5    cnt := 42
+    6  END M;
+    7  VAR ExitCode : INTEGER;
+    8  BEGIN
+    9    ExitCode := M.cnt
+   10  END BInit.
+
+    0 errors
+
+

+ 10 - 0
tests/b_init.mod

@@ -0,0 +1,10 @@
+MODULE BInit;
+MODULE M EXPORT cnt;
+VAR cnt : INTEGER;
+BEGIN
+  cnt := 42
+END M;
+VAR ExitCode : INTEGER;
+BEGIN
+  ExitCode := M.cnt
+END BInit.

+ 21 - 0
tests/b_order.LST

@@ -0,0 +1,21 @@
+Listing:
+
+    1  MODULE BOrder;
+    2  MODULE A EXPORT x;
+    3  VAR x : INTEGER;
+    4  BEGIN
+    5    x := 1
+    6  END A;
+    7  MODULE B EXPORT y;
+    8  VAR y : INTEGER;
+    9  BEGIN
+   10    y := A.x + 10
+   11  END B;
+   12  VAR ExitCode : INTEGER;
+   13  BEGIN
+   14    ExitCode := A.x * 100 + B.y
+   15  END BOrder.
+
+    0 errors
+
+

+ 15 - 0
tests/b_order.mod

@@ -0,0 +1,15 @@
+MODULE BOrder;
+MODULE A EXPORT x;
+VAR x : INTEGER;
+BEGIN
+  x := 1
+END A;
+MODULE B EXPORT y;
+VAR y : INTEGER;
+BEGIN
+  y := A.x + 10
+END B;
+VAR ExitCode : INTEGER;
+BEGIN
+  ExitCode := A.x * 100 + B.y
+END BOrder.

Some files were not shown because too many files changed in this diff