Przeglądaj źródła

language: ISO CONVERT(T, x) (a VAL sibling)

Track B: CONVERT is a standard ISO SYSTEM generic conversion.  The
grammar's VAL production now reads ( "VAL" | "CONVERT" ), so CONVERT
reuses VAL's conversion rules (and CONVERT is accepted in an import
list).  procconv2 passes and runs; corpus 388 -> 389.

Suite 235/235 (t_convert); fixpoint OK, 3,854,595 bytes.  docs/gaps
gap07 retired (no longer a gap).

Note: CONVERT is now a reserved token, like VAL/SIZE already were; the
builtins-as-identifiers issue (gap13) is unchanged and needs a parser
de-reservation.
Eric Streit 1 dzień temu
rodzic
commit
35dc2eba6b

+ 2 - 2
README.md

@@ -47,8 +47,8 @@ docs/              STATUS.md, plan.md, plan-*.md, analysis_*.md, summary_*.md
 
 ## Status (2026-10-18)
 
-- Suite **234/234**; self-hosting **fixpoint OK** (byte-identical
-  stage2/stage3, 3,843,693 bytes); corpus **388/612 compile-OK,
+- Suite **235/235**; self-hosting **fixpoint OK** (byte-identical
+  stage2/stage3, 3,854,595 bytes); corpus **389/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/`).
 - Active branch **`resolve-check`** (holds the AST/`Lower`/parse

+ 1 - 0
compiler/run_tests.sh

@@ -99,6 +99,7 @@ expect_run t_constbuiltin.mod 42
 expect_run t_constreal.mod 42
 expect_run t_constlong.mod 42
 expect_run t_procaddr.mod 42
+expect_run t_convert.mod 42
 expect_run t_procval.mod 42
 expect_run t_real64.mod 42
 expect_run t_shiftneg.mod 42

+ 2 - 2
compiler/src/M2.atg

@@ -1165,7 +1165,7 @@ PRODUCTIONS
       | "ODD" | "TRUNC" | "FLOAT"
       | "UCHR" | "CHR8" | "UORD"
       | "INC" | "DEC"
-      | "SHIFT" | "ROTATE" | "CAST" | "MIN" | "MAX"
+      | "SHIFT" | "ROTATE" | "CAST" | "CONVERT" | "MIN" | "MAX"
       | "INCL" | "EXCL" | "NEW" | "DISPOSE" | "LOC" ) .
   ImpModList<node: AST.Node>            (. VAR n: SymTab.Name; .)
     = GetIdent<n>                       (. AST.SetChild(node, AST.NChild(node),
@@ -3773,7 +3773,7 @@ PRODUCTIONS
                                         (. t := SymTab.RealType();
    IF QbeGen.IsImm(q) AND SymTab.ConstInt(q, lo) THEN QbeGen.NormReal(q, qa); QbeGen.CopyOp(qa, q)
    ELSE QbeGen.CopyOp("@", q) END; .)
-    | "VAL" "(" GetIdent<vn> (. astArg2 := AST.MakeLeaf(AST.NkIdent, vn); .) "," Expr<et, q> ")"
+    | ( "VAL" | "CONVERT" ) "(" GetIdent<vn> (. astArg2 := AST.MakeLeaf(AST.NkIdent, vn); .) "," Expr<et, q> ")"
     (. astNode := AST.MakeNode(AST.NkCall);
    AST.SetChild(astNode, 0, AST.MakeLeaf(AST.NkIdent, "VAL"));
    IF astArg2 # AST.NoNode THEN AST.SetChild(astNode, 1, astArg2) END;

+ 6 - 6
compiler/src/M2.lst

@@ -1184,7 +1184,7 @@ Listing:
  1165        | "ODD" | "TRUNC" | "FLOAT"
  1166        | "UCHR" | "CHR8" | "UORD"
  1167        | "INC" | "DEC"
- 1168        | "SHIFT" | "ROTATE" | "CAST" | "MIN" | "MAX"
+ 1168        | "SHIFT" | "ROTATE" | "CAST" | "CONVERT" | "MIN" | "MAX"
  1169        | "INCL" | "EXCL" | "NEW" | "DISPOSE" | "LOC" ) .
  1170    ImpModList<node: AST.Node>            (. VAR n: SymTab.Name; .)
  1171      = GetIdent<n>                       (. AST.SetChild(node, AST.NChild(node),
@@ -3792,7 +3792,7 @@ Listing:
  3773                                          (. t := SymTab.RealType();
  3774     IF QbeGen.IsImm(q) AND SymTab.ConstInt(q, lo) THEN QbeGen.NormReal(q, qa); QbeGen.CopyOp(qa, q)
  3775     ELSE QbeGen.CopyOp("@", q) END; .)
- 3776      | "VAL" "(" GetIdent<vn> (. astArg2 := AST.MakeLeaf(AST.NkIdent, vn); .) "," Expr<et, q> ")"
+ 3776      | ( "VAL" | "CONVERT" ) "(" GetIdent<vn> (. astArg2 := AST.MakeLeaf(AST.NkIdent, vn); .) "," Expr<et, q> ")"
  3777      (. astNode := AST.MakeNode(AST.NkCall);
  3778     AST.SetChild(astNode, 0, AST.MakeLeaf(AST.NkIdent, "VAL"));
  3779     IF astArg2 # AST.NoNode THEN AST.SetChild(astNode, 1, astArg2) END;
@@ -4111,11 +4111,11 @@ Listing:
 
 Statistics:
 
-  nr of terminals:       112 (limit   400)
+  nr of terminals:       113 (limit   400)
   nr of non-terminals:    90 (limit   210)
-  nr of pragmas:           0 (limit   388)
-  nr of symbolnodes:     202 (limit   500)
-  nr of graphnodes:     1287 (limit  1500)
+  nr of pragmas:           0 (limit   387)
+  nr of symbolnodes:     203 (limit   500)
+  nr of graphnodes:     1292 (limit  1500)
   nr of conditionsets:    12 (limit   100)
   nr of charactersets:    16 (limit   250)
 

+ 14 - 0
compiler/tests/t_convert.mod

@@ -0,0 +1,14 @@
+MODULE TConvert;
+// CONVERT(T, x): the ISO SYSTEM generic conversion (VAL's sibling).
+// Exit 42.
+FROM SYSTEM IMPORT ADDRESS, ADR;
+PROCEDURE foo; BEGIN END foo;
+VAR a : ADDRESS;
+    n : INTEGER;
+    ExitCode : INTEGER;
+BEGIN
+  a := CONVERT(ADDRESS, foo);
+  n := CONVERT(INTEGER, 'A');
+  IF (a = ADR(foo)) AND (n = 65)
+  THEN ExitCode := 42 ELSE ExitCode := 1 END
+END TConvert.

+ 7 - 7
docs/STATUS.md

@@ -4,10 +4,10 @@ This answers "where are we now?".
 
 ## Numbers
 
-- Suite **234/234** (`compiler/run_tests.sh`).
+- Suite **235/235** (`compiler/run_tests.sh`).
 - Self-hosting **FIXPOINT OK** — stage2 and stage3 images are
-  byte-identical (3,843,693 bytes).
-- Corpus **388 / 612** sources compile with 0 errors, **0 crashes**
+  byte-identical (3,854,595 bytes).
+- Corpus **389 / 612** sources compile with 0 errors, **0 crashes**
   (`tools/v3-corpus/corpus.sh` over the gm2 testsuite); the rest are
   genuine language gaps, **gm2 leniencies V3 deliberately rejects**, or
   unresolved imports.
@@ -65,9 +65,9 @@ parameters, constraints, nested generics, generic classes.
   `VAL`↔`PROC` conversions, `p := foo` into a `PROC`), SYSTEM sized
   reals (`REAL32`/`REAL64`), `FROM SYSTEM IMPORT SHIFT`/`ROTATE`/`CAST`/…
   (a builtin import is accepted), and ISO foreign modules
-  (`DEFINITION/IMPLEMENTATION MODULE FOR "C"`, `EXPORT UNQUALIFIED`):
-  corpus 382 → 398.  Fixed a `SHIFT`-by-a-negative-amount fault (wild
-  word load).
+  (`DEFINITION/IMPLEMENTATION MODULE FOR "C"`, `EXPORT UNQUALIFIED`),
+  and ISO `CONVERT(T, x)` (a `VAL` sibling): corpus 382 → 389.
+  Fixed a `SHIFT`-by-a-negative-amount fault (wild word load).
 - Clean `M2` exit codes (0 ok / 1 errors / 2 usage-IO).
 - Bug fixes: `PopPos` wiping repass diagnostics; global record data
   size (`w 0` → `l 0` for pointer/`LONGINT`/proc fields); template
@@ -114,7 +114,7 @@ is the 10 gm2-leniency files now correctly rejected).
 ```sh
 cd compiler
 ./build.sh          # M2.atg -> scanner/parser/driver -> ./M2
-./run_tests.sh      # 234/234
+./run_tests.sh      # 235/235
 cd ..
 ./bootstrap/fixpoint.sh   # FIXPOINT OK (byte-identical stage2/stage3)
 ```

+ 11 - 6
docs/analysis_gaps.md

@@ -253,13 +253,18 @@ legal pointer exception; fixpoint stays green.  Forward references to
 module-level **variables** / **procedures** from a body (the two-phase
 parse) are a separate, larger item still retained.
 
-Next (recorded, genuine only): forward *type* references in a `CONST` conversion
-(`subrange4`/`7`) and as a `VAR` type before its TYPE block
-(`subrange11`, `shift3`/`4`); `setconst3` (forward `CONST`); `procconv2`
-(`CONVERT`); `packed` (`CAST` set↔int); `aochar`/`arrayofbyte`/
+**Track B (genuine gaps), 2026-10-18:** **`CONVERT(T, x)`** (ISO SYSTEM)
+landed — the `VAL` production now accepts `( "VAL" | "CONVERT" )`, so
+`procconv2` passes and runs.  Corpus **388 -> 389**; suite test
+`t_convert`; `docs/gaps/gap07` retired.
+
+Next (recorded, genuine only): **`gap13` builtins as identifiers** (a V3
+bug; needs de-reserving the builtin keyword tokens — a parser refactor);
+**`gap08` set↔word `CAST`/`VAL`** (`packed`); **`gap15` enumeration
+literals with an imported type** (`imp*`); `aochar`/`arrayofbyte`/
 `bytearray` (scalar actual into `ARRAY OF BYTE`); variant empty arms /
-`ELSE`; builtin names as procedure names; the `imp*` qualified-import
-family (partly a corpus-harness transitive-`.def` gap).
+`ELSE`; set-span limits.  The forward-type items above are gm2
+leniency, not targets.
 
 Every gap above has a self-contained reproducer in `docs/gaps/`
 (`docs/gaps/README.md` indexes them by tag, with a **class**:

+ 2 - 3
docs/gaps/README.md

@@ -50,7 +50,6 @@ The `class` column says what a change would mean:
 | `gap04-fwd-const-bound` | `gap04_fwd_const_bound.mod` | `decl-order` | `undeclared identifier` | `setconst3` |
 | `gap05-fwd-type-size` | `gap05_fwd_type_size.mod` | `decl-order` | `undeclared identifier` | `constsize2` |
 | `gap06-fwd-setconst` | `gap06_fwd_setconst.mod` | `decl-order` | `undeclared identifier` | `setoverflow` |
-| `gap07-convert-builtin` | `gap07_convert.mod` | `iso/system` | `undeclared identifier` | `procconv2` |
 | `gap08-set-word-cast` | `gap08_val_cast_set_word.mod` | `iso/system` | `not supported yet` | `constset`, `constset2`, `constset3`, `packed` |
 | `gap09-scalar-to-bytearray` | `gap09_scalar_to_bytearray.mod` | `gm2-ext` | `invalid call` | `aochar`, `arrayofbyte`, `bytearray` |
 | `gap10-var-param-type` | `gap10_var_param_type.mod` | `gm2-ext` | `invalid call` | `testparam2`, `testparam3` |
@@ -77,7 +76,6 @@ gap03_fwd_type_heading.mod      undeclared identifier   (large)
 gap04_fwd_const_bound.mod       undeclared identifier   (n)
 gap05_fwd_type_size.mod         undeclared identifier   (t)
 gap06_fwd_setconst.mod          undeclared identifier   (CharSet / tab)
-gap07_convert.mod               undeclared identifier   (CONVERT)
 gap08_val_cast_set_word.mod     not supported yet       (VAL of a set)
 gap09_scalar_to_bytearray.mod   invalid call            (scalar -> ARRAY OF BYTE)
 gap10_var_param_type.mod        invalid call            (VAR actual type)
@@ -97,7 +95,8 @@ gap21_fwd_record_field.mod      undeclared identifier   (record field type decla
 
 ## Genuine gaps (worth fixing, standard Modula-2)
 
-- **`gap07` CONVERT** — an ISO SYSTEM generic conversion.
+- **`gap07` CONVERT — fixed** (2026-10-18): `CONVERT(T, x)` is accepted as
+  a `VAL` sibling (`procconv2` passes).
 - **`gap08` set↔word CAST/VAL** — BITSET has a machine-word
   representation in Modula-2.
 - **`gap13` builtins as identifiers** — `ORD`, `CHR`, `VAL`, `ORDL`, …

+ 0 - 10
docs/gaps/gap07_convert.mod

@@ -1,10 +0,0 @@
-MODULE Gap07Convert;
-(* Modula-2 gap (ISO SYSTEM): CONVERT(T, x) is a standard ISO generic
-   conversion; V3 implements VAL but not CONVERT.
-   Class: iso/system (a real missing feature).
-   Corpus: procconv2.
-   V3: undeclared identifier. *)
-FROM SYSTEM IMPORT ADDRESS;
-PROCEDURE foo; BEGIN END foo;
-VAR a : ADDRESS;
-BEGIN a := CONVERT(ADDRESS, foo) END Gap07Convert.

+ 22 - 5
docs/summary_set-constants-2026-10-18.md

@@ -1,12 +1,12 @@
 # Session summary — SET CONST + builtin CONST folding 2026-10-18
 
-Branch **`resolve-check`**.  Suite **234/234**; fixpoint **OK
-(3,843,693 bytes)**; corpus **388/612 compile-OK, 0 crashes**.
+Branch **`resolve-check`**.  Suite **235/235**; fixpoint **OK
+(3,854,595 bytes)**; corpus **389/612 compile-OK, 0 crashes**.
 
 Tags: `v3-set-constants`, `v3-const-builtin-fold`, `v3-const-conv-fold`,
 `v3-proc-addr`, `v3-proc-val`, `v3-real64`, `v3-shift-import`,
 `v3-foreign-module`, `v3-m2-conformance`, `v3-strict-decl-order`,
-`v3-gap-examples`.
+`v3-convert`, `v3-gap-examples`.
 
 ## Conformance note
 
@@ -155,6 +155,23 @@ 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.
 
+## Track B: CONVERT
+
+`CONVERT(T, x)` (ISO SYSTEM, a `VAL` sibling) is now accepted — the
+grammar's `VAL` production takes `( "VAL" | "CONVERT" )`, so it reuses
+`VAL`'s conversion rules; `procconv2` passes and runs.  Corpus
+**388 → 389**; suite test `t_convert`, `docs/gaps/gap07` retired.
+
+## Remaining genuine gaps (Track B)
+
+- **`gap13` builtins as identifiers** — a real V3 bug, but the builtins
+  are Coco/R keyword tokens; fixing it means de-reserving them (a
+  parser refactor), *not* a one-liner.
+- **`gap08` set↔word `CAST`/`VAL`** (BITSET as a machine word).
+- **`gap15` enumeration literals with an imported type** (ISO
+  import/export through re-exports).
+- `gap16`/`gap17` set-span limits.
+
 ## Not fixed (recorded)
 
 - **`setconst3.mod`** still fails: its `VAR mem: ARRAY [0..CARDINAL(
@@ -193,7 +210,7 @@ modules),
 ```sh
 cd .../m2compiler-V3
 git checkout resolve-check
-cd compiler && ./build.sh && ./run_tests.sh   # 234/234
+cd compiler && ./build.sh && ./run_tests.sh   # 235/235
 cd .. && TMP="$PWD/.scratch/fixpoint" ./bootstrap/fixpoint.sh
-M2FLAGS="" ./.scratch/corpusx.sh              # 388 OK, 0 crash
+M2FLAGS="" ./.scratch/corpusx.sh              # 389 OK, 0 crash
 ```