features.md 8.6 KB

m2compiler-V3 — feature status (at v3-string-variant-nested, 169/169 green)

Pipeline: Coco/R M2.atg (1748 lines, 73 productions) → gm2-built M2 → QBE .ssa → qbe → cc → run. SymTab.mod 1623 lines, QbeGen.mod 2193 lines. Regenerate with cd compiler && ./build.sh && ./run_tests.sh.

Legend: ✅ done · 🔄 partial · ⏸ not started / deferred.

Lexical / syntax

  • ✅ Classic idents (no _), 0x/0X hex (no H), reals with E exponents, # < <= > >= =, // + nested (* *), strings '…'/"…", 0x array bounds.
  • ✅ NOT/AND/OR (no ~/&), unary minus at expr start, no octal B/C suffixes.

Types

  • ✅ INTEGER/CARDINAL/SHORTINT/LONGINT (one family, QBE w), REAL/LONGREAL (d, widened), BOOLEAN, CHAR.
  • ✅ Named types, aliases, integer/char subranges (folded bounds), enumerations (literals carry ordinals; usable in expressions, CASE labels, CONST and as parameter/value types).
  • ✅ ARRAY [lo..hi,…] (multi-dim) and open ARRAY OF formals.
  • ✅ Array constructors T{…} (GNU Modula-2): a CONST of an array type fills a pooled static descriptor (copied/indexed like a declared array); scalar elements, nested Sub{…}, string elements for nested ARRAY OF CHAR, and the expr BY n repeat form.
  • ✅ Record constructors Rec{…} (fields in declaration order) and runtime construction: any non-constant element builds the array/ record descriptor on the stack and fills it in place, so constructors also work outside CONST (a := arr{i, i+1}, p := Person{"Blaise Pascal", d}); a CONST with all-constant elements still bakes a static descriptor. Set fields, and constant string concatenation folded into a CHAR-array element, included.
  • ✅ Index-type arrays ARRAY <ordinalType> OF T; enum values usable as array indices.
  • ✅ MIN/MAX over any ordinal type, array or set; REAL/LONGREAL and LONGINT bounds too.
  • ✅ gm2 sized/scalar names: LONGCARD, SHORTREAL, INTEGER8/16/32/64, CARDINAL8/16/32/64.
  • ✅ FROM libc IMPORT printf, exit, …: intrinsic permissive external C procedures (varargs, no result); string/CHAR-array actuals pass as descriptor+8.
  • ✅ Set builtins INCL/EXCL and SHIFT/ROTATE; SET OF <enum> and SET OF <char-range>; set spans up to 65536.
  • ✅ Module-level forward type references (a global may name a type declared further down; emission deferred).
  • ✅ RECORD (flat blobs, nested inline, array fields as pointers), including variant records (RECORD … ; CASE tag : T OF … END): plain fields pack before the tag, each branch's fields overlay after it.
  • ✅ SET OF bool/char/subrange (multi-word masks).
  • ✅ POINTER TO, NIL as a real type, ADDRESS ↔ any pointer assignment (p := ADR(x)).
  • ✅ UCHAR (32-bit codepoint) + U'a'/U"…" literals (strict RFC3629 decode → 234 on bad bytes), UCHR/CHR8/UORD, U"…" whole-string assignment to a 1-D ARRAY OF UCHAR, + concatenation of U"…" (and single-codepoint operands), and LEN/LENGTH/HIGH of a UString.
  • ✅ Opaque TYPE T; + completion in the implementation.
  • ✅ Variant records (RECORD CASE … OF … END); whole-record assignment is a flat byte blit (correct for overlapping fields) and whole-record = is 213.
  • ✅ Opaque/forward types used as values: an unresolved (opaque or forward) alias is pointer-like (assign NIL, copy, compare, pass). gm2's String is not built in — it is an opaque type imported from a definition module (DynamicStrings, or a local opaque); an undeclared type name is an error as in gm2.

Declarations

  • ✅ CONST (integer/char/real literals, folded), VAR, TYPE, PROCEDURE headings + bodies, FORWARD.
  • ✅ DEFINITION/IMPLEMENTATION modules, IMPORT/FROM … IMPORT, EXPORT (parsed), nested local MODULE (including EXPORT lists, nested-nested modules, and bodies lowered as startup init functions).
  • ✅ Opaque completion; opaque/forward types used as pointer-like values; module BEGIN init bodies.
  • ✅ Strict impl-vs-def signature checks (error 235): result type, formal count, formal types and VAR-ness are compared against the DEFINITION (was arity-only).

Statements

  • ✅ Assignment, IF/ELSIF/ELSE, CASE (labels, ranges, ELSE), WHILE, REPEAT/UNTIL, LOOP/EXIT, FOR/TO/BY (static sign), WITH (single/multi/nested), RETURN (232-checked), NEW/DISPOSE (builtins), bare and parenthesized calls.
  • ✅ HIGH/LEN; ⏸ GOTO/labels.

Expressions

  • ✅ Full precedence, + - * / DIV MOD, comparisons, eager AND/OR/NOT, IN, set ops (+ - * / = union/diff/inter/symdiff), pointer =/#, int→real conversion, ^ deref, indexing, field access, qualified L.x/L.P.
  • ✅ String =/# (content), string + (concatenation for literals, CHAR arrays and CHAR operands), string assignment (content copy, truncated to the array capacity, NUL-terminated), LEN/LENGTH of arrays and string literals. UString +/LEN likewise.
  • ✅ NIL comparisons/assignment.
  • ✅ VAL/ADR/TSIZE/SIZE/HIGH/LEN work. ✅ Result suffixes (F()^, F()[i], F().field): components after a call result, loaded like Design components.

Procedures & modules

  • ✅ Value + VAR params, function results, recursion, mutual recursion (FORWARD), nested procedures with static-link display (any depth), array/record/set/pointer params, open-array VAR formals.
  • ✅ Separate compilation: lib.def lib.mod prog.mod → one image; module init functions; opaque completion; strict 235 signature checks between a definition and its implementation.
  • ⏸ Procedure-type variables / indirect calls, per-file object emission, import cycles.

Backend (QBE)

  • ✅ Length-prefixed arrays (count + elements), deep record copy, count-checked whole-array assign, runtime bounds/span traps ($abort, rc 134), multi-word sets, alloc8 heap (malloc/free), static-link frames, deterministic %tN/@LN, whole-image buffering.
  • ✅ REAL runtime const flush, string literals as descriptors.
  • ⏸ runtime/syslib/Trap (traps are $abort for now), recursive DISPOSE.

Error codes

  • ✅ 200/201/202, 210–222, 223 (declared), 230, 231, 232, 233 invalid call, 234 invalid UTF-8 in U-literal, 235 implementation does not match definition, plus file:line:col console format.

Library

  • ✅ runtime/syslib: SysShim, FileIO, Utf8 (UTF-8 codec).
  • ✅ stdlib: SysIO, TextIO (+ UTF-8 U*), WholeIO, Math (incl. log10/atan2/sinh/cosh/tanh/hypot/ floor/ceil/trunc/round/fmod; ln/arctan wrap log/atan), Strings (incl. Slice (Python-style), Insert, Replace, Capitalize), CharClass, Files (layered on IOChan), Conversions (ISO ConvResults statuses + BOOLEAN shortcuts), RealIO, ProgramArgs, SysClock, IOChan (streams + files; Position/Seek/Rewind), Storage.
  • ✅ gm2/ISO text + conversion library added: ConvTypes, IOConsts, SIOResult, TERMINATION, StrIO, InOut, StdIO, WholeStr, RealStr, LongStr, LongMath, STextIO, SWholeIO, SRealIO, DynamicStrings (core subset), SysStorage.

Coroutines

  • ✅ PIM/SYSTEM coroutines: PROCESS, NEWPROCESS, TRANSFER, IOTRANSFER (the last degrades to a transfer without an interrupt subsystem). Bind to ucontext helpers in the shim; coroutine bodies are called with a 0 static link (module-level procedures).

Not started

  • ✅ Clarion CLASS: fields, methods (value/VAR formals, results), single inheritance, WITH, a hidden THIS receiver, VIRTUAL dynamic dispatch via vtables (with subtype pointer assignment), bare sibling-method calls (a call on THIS), and a class BEGIN … END init body (runs at startup). ⏸ Multiple parents (deliberately single inheritance only; a Tier-1/Tier-2 cost breakdown for future MI is recorded in docs/OOP.txt). See docs/summary_class-lowering.md, docs/summary_virtual-dispatch.md, docs/summary_class-finish.md.
  • ✅ VAL conversions across INTEGER/CHAR/BOOLEAN/enum, INTEGER↔LONGINT (widen/narrow), INTEGER/LONGINT↔REAL (truncate/widen) and pointer↔pointer. The TopSpeed legacy grammar (TopSpeed-V3-M2.atg) is a separate sidecar, not merged.

(Self-hosting is reached: bootstrap/fixpoint.sh builds a byte-identical compiler image; stdlib/ + runtime/syslib are in use. See docs/summary_selfhosting.md.)

Next: variant records, UString assignment, Files on IOChan. Roadmap: docs/plan.md, docs/blaise-phases-map.md.