Explorar o código

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

Eric Streit hai 1 mes
pai
achega
e239d3dd3c
Modificáronse 31 ficheiros con 2655 adicións e 2124 borrados
  1. BIN=BIN
      BBadDup.MC4
  2. BIN=BIN
      BBadNest.MC4
  3. BIN=BIN
      BBadRet.MC4
  4. BIN=BIN
      BCall.MC4
  5. BIN=BIN
      BInit.MC4
  6. BIN=BIN
      BOrder.MC4
  7. BIN=BIN
      M2c
  8. 85 21
      M2c.atg
  9. 2149 2085
      M2c.lst
  10. 84 18
      M2cP.mod
  11. BIN=BIN
      M2cP.o
  12. 7 0
      MGen.def
  13. 30 0
      MGen.mod
  14. BIN=BIN
      MGen.o
  15. 7 0
      SymTab.def
  16. 34 0
      SymTab.mod
  17. BIN=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=BIN
BBadDup.MC4


BIN=BIN
BBadNest.MC4


BIN=BIN
BBadRet.MC4


BIN=BIN
BCall.MC4


BIN=BIN
BInit.MC4


BIN=BIN
BOrder.MC4


BIN=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

A diferenza do arquivo foi suprimida porque é demasiado grande
+ 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=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=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=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.

Algúns arquivos non se mostraron porque demasiados arquivos cambiaron neste cambio