Parcourir la source

language: constant-fold ordinal type conversions in CONST initialisers

A conversion T(x) whose operand is an immediate ordinal and whose
source and target classes are both ordinal (OrdClass) folds to the
operand, so CONST low = ind1(-200) compiles. ActParam exports the last
actual's folded value/type (convQ/convT). Cross-representation
conversions (int<->real, long<->int) are not folded. Test t_convconst;
suite 208/208; fixpoint OK; corpus 368 -> 372 (subrange3/9/10/12), 0
crash.
Eric Streit il y a 1 jour
Parent
commit
de015ff4fd
5 fichiers modifiés avec 2502 ajouts et 2464 suppressions
  1. 1 0
      compiler/run_tests.sh
  2. 27 3
      compiler/src/M2.atg
  3. 2457 2457
      compiler/src/M2.lst
  4. 9 0
      compiler/tests/t_convconst.mod
  5. 8 4
      docs/analysis_gaps.md

+ 1 - 0
compiler/run_tests.sh

@@ -114,6 +114,7 @@ expect_run t_classinherit.mod 7
 expect_run t_virtual.mod 3
 expect_run t_valconv.mod 15
 expect_run t_conv.mod 42
+expect_run t_convconst.mod 42
 expect_run t_classsibling.mod 7
 expect_run t_classinit.mod 42
 expect_run t_class.mod 0

+ 27 - 3
compiler/src/M2.atg

@@ -83,6 +83,12 @@ VAR
   allowDefer: BOOLEAN;
   curProcNode: AST.Node;
 
+  (* The last actual argument parsed by ActParam: folded value and type.
+     A conversion T(x) has exactly one actual, so these let Fact
+     constant-fold it (needed for `CONST c = T(x)`). *)
+  convQ: QbeGen.QVal;
+  convT: SymTab.TypeIndex;
+
   (* Result slot for the expression-AST builder (slice 2).  Every
      Expr/SimExpr/Term/Fact leaves its node here; the combination
      productions save it into locals before parsing the next operand.
@@ -356,6 +362,17 @@ PROCEDURE Adv;
     INC(errDist)
   END Adv;
 
+PROCEDURE OrdClass (t: SymTab.TypeIndex): BOOLEAN;
+(* TRUE for scalar ordinal classes (int/char/bool/enum/uchar); a
+   conversion between two of these is representation-preserving, so its
+   folded value equals the operand's. *)
+  VAR c: INTEGER;
+  BEGIN
+    c := SymTab.ClassOf(t);
+    RETURN (c = SymTab.ClInt) OR (c = SymTab.ClChar) OR (c = SymTab.ClBool)
+        OR (c = SymTab.ClEnum) OR (c = SymTab.ClUChar)
+  END OrdClass;
+
 PROCEDURE NoteSpan (pn: SymTab.Name; start: M2S.INT32);
 (* Records an outermost body span for the re-parse pass (milestone 2).
    Diagnostic only for now: nothing consumes the table yet.  Declared
@@ -2068,7 +2085,8 @@ PRODUCTIONS
                                              savedArgs[aj] := astArgs[aj];
                                              INC(aj)
                                            END; .)
-      Expr<at, qe>                      (. astActual := astCur;
+      Expr<at, qe>                      (. QbeGen.CopyOp(qe, convQ); convT := at;
+                                           astActual := astCur;
                                            astNArgs := savedN; aj := 0;
                                            WHILE aj <= HIGH(astArgs) DO
                                              astArgs[aj] := savedArgs[aj];
@@ -3012,7 +3030,8 @@ PRODUCTIONS
                                               j: CARDINAL;
                                               astArg2: AST.Node;
                                               astBrace: AST.Node;
-                                              astRes: AST.Node; mname: SymTab.Name; isM: BOOLEAN; .)
+                                              astRes: AST.Node; mname: SymTab.Name; isM: BOOLEAN;
+                                              isConvF: BOOLEAN; .)
     = (. astIsLit := FALSE; .)
     ( integer                           (. LexString(s);
                                            QbeGen.NormInt(s, q); astIsLit := TRUE; astCur := AST.MakeLeaf(AST.NkIntLit, s);
@@ -3079,12 +3098,17 @@ PRODUCTIONS
                                              AST.MakeLeaf(AST.NkIdent, qn));
                                            IF astNArgs = 1 THEN
                                              AST.SetChild(astNode, 2, astArgs[0])
-                                           END
+                                           END;
+                                           isConvF := TRUE
                                            ELSE astNode := AstCallNode(astD)
                                            END;
                                            astRes := astNode;
                                            t := ct2;
                                            QbeGen.CopyOp(q2, q);
+                                           IF isConvF AND QbeGen.IsImm(convQ)
+                                              AND OrdClass(convT) AND OrdClass(ct2) THEN
+                                             QbeGen.CopyOp(convQ, q)
+                                           END;
                                            sfx := FALSE; .)
         { ResultComp<t, q, sfx, astRes, mname, methCls, isM>
           [ (. astNArgs := 0; .)

Fichier diff supprimé car celui-ci est trop grand
+ 2457 - 2457
compiler/src/M2.lst


+ 9 - 0
compiler/tests/t_convconst.mod

@@ -0,0 +1,9 @@
+MODULE TConvConst;
+// ISO type conversion in a CONST initialiser: a subrange applied to a
+// constant folds to that constant (representation-preserving).
+TYPE ind = [-100..100];
+CONST low = ind(-100); high = ind(100);
+VAR ExitCode : INTEGER;
+BEGIN
+  ExitCode := low + 100 + (high - 100) + 42     (* 0 + 0 + 42 *)
+END TConvConst.

+ 8 - 4
docs/analysis_gaps.md

@@ -151,10 +151,14 @@ Two concrete, corpus-visible language gaps found while auditing those
    `Fact` emits it as the existing `VAL(T, x)` builtin, so `Lower`'s
    conversion rules apply unchanged.  Suite test `t_conv`; corpus
    **365 -> 368** (+3 files: `procedure1`, `tinyindr`, `tinyproc6`),
-   `invalid call` 28 -> 17.  Remaining for this family: a conversion in
-   a **`CONST` initialiser** (`CONST low = ind1(-200)`) is still `not
-   supported yet` (constant folding of a conversion) — `subrange10.mod`
-   is the repro.
+   `invalid call` 28 -> 17.  **CONST initialisers** (`CONST low =
+   ind1(-200)`) are folded too (2026-10-16): a conversion whose operand
+   is an immediate ordinal and whose source *and* target classes are
+   ordinal (`OrdClass`) folds to the operand.  Corpus **368 -> 372**
+   (`subrange3/9/10/12` now pass); suite test `t_convconst`.
+   Conversions that genuinely change representation (int<->real,
+   long<->int) are not folded, so `CONST r = REAL(intconst)` is still
+   `230`.
 2. **`SIZE(TYPE)` / `TSIZE(TYPE)` as expressions** — `sizes.mod`.
    **Not a gap:** already supported (grammar `Fact`: `("SIZE"|"TSIZE")
    "(" Design ")"`, lowered by `LowerBuiltinExpr`).  Keep the layout

Certains fichiers n'ont pas été affichés car il y a eu trop de fichiers modifiés dans ce diff