소스 검색

docs: polish summary (UString concat/LEN, IOChan seek) + CLASS lowering design

- summary_polish-ustr-iochan: the two landed polish items; 137/137,
  fixpoint OK (2,156,095 bytes).
- summary_class-lowering: the remaining item scoped as its own step
  (record-like layout, hidden THIS receiver, static calls, vtable
  dispatch later, acceptance + risks).
- features.md refreshed.
Eric Streit 1 주 전
부모
커밋
06265f1f9d
3개의 변경된 파일과 150개의 추가작업 그리고 10개의 파일을 삭제
  1. 13 10
      docs/features.md
  2. 88 0
      docs/summary_class-lowering.md
  3. 49 0
      docs/summary_polish-ustr-iochan.md

+ 13 - 10
docs/features.md

@@ -1,4 +1,4 @@
-# m2compiler-V3 — feature status (at `v3-ustring-files`, 135/135 green)
+# m2compiler-V3 — feature status (at `v3-polish-ustr-iochan`, 137/137 green)
 
 
 Pipeline: Coco/R `M2.atg` (1748 lines, 73 productions) → `gm2`-built
 Pipeline: Coco/R `M2.atg` (1748 lines, 73 productions) → `gm2`-built
 `M2` → QBE `.ssa` → `qbe` → `cc` → run. `SymTab.mod` 1623 lines,
 `M2` → QBE `.ssa` → `qbe` → `cc` → run. `SymTab.mod` 1623 lines,
@@ -27,9 +27,10 @@ Legend: ✅ done · 🔄 partial · ⏸ not started / deferred.
 - ✅ `SET OF` bool/char/subrange (multi-word masks).
 - ✅ `SET OF` bool/char/subrange (multi-word masks).
 - ✅ `POINTER TO`, `NIL` as a real type.
 - ✅ `POINTER TO`, `NIL` as a real type.
 - ✅ `UCHAR` (32-bit codepoint) + `U'a'`/`U"…"` literals (strict
 - ✅ `UCHAR` (32-bit codepoint) + `U'a'`/`U"…"` literals (strict
-  RFC3629 decode → 234 on bad bytes), `UCHR`/`CHR8`/`UORD`, and
-  `U"…"` whole-string assignment to a 1-D `ARRAY OF UCHAR` (content
-  copy, terminator slot reserved like CHAR arrays).
+  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.
 - ✅ Opaque `TYPE T;` + completion in the implementation.
 - ✅ Variant records (`RECORD CASE … OF … END`); ⏸ whole-record
 - ✅ Variant records (`RECORD CASE … OF … END`); ⏸ whole-record
   equality/assignment for variants is 236 (overlapping storage).
   equality/assignment for variants is 236 (overlapping storage).
@@ -95,14 +96,16 @@ Legend: ✅ done · 🔄 partial · ⏸ not started / deferred.
 - ✅ `runtime/syslib`: `SysShim`, `FileIO`, `Utf8` (UTF-8 codec).
 - ✅ `runtime/syslib`: `SysShim`, `FileIO`, `Utf8` (UTF-8 codec).
 - ✅ `stdlib`: `SysIO`, `TextIO` (+ UTF-8 `U*`), `WholeIO`, `Math`,
 - ✅ `stdlib`: `SysIO`, `TextIO` (+ UTF-8 `U*`), `WholeIO`, `Math`,
   `Strings`, `CharClass`, `Files` (layered on `IOChan`),
   `Strings`, `CharClass`, `Files` (layered on `IOChan`),
-  `Conversions`, `RealIO`, `ProgramArgs`, `IOChan` (streams + files),
-  `Storage`.
+  `Conversions`, `RealIO`, `ProgramArgs`,
+  `IOChan` (streams + files; `Position`/`Seek`/`Rewind`), `Storage`.
 
 
 ## Not started
 ## Not started
-- ⏸ Clarion `CLASS` lowering (declared + checked only); `IOChan`
-  position/seek; UString concatenation/`Length`. (ISO `ConvResults`
-  enumerations are now expressible.) The TopSpeed legacy grammar
-  (`TopSpeed-V3-M2.atg`) is a separate sidecar, not merged.
+- ⏸ Clarion `CLASS` lowering — declared and checked only (fields,
+  methods, single inheritance, `VIRTUAL`); bodies/dispatch need a
+  receiver-passing design (see `docs/summary_class-lowering.md`).
+  (ISO `ConvResults` enumerations are now expressible.) The TopSpeed
+  legacy grammar (`TopSpeed-V3-M2.atg`) is a separate sidecar, not
+  merged.
 
 
 (Self-hosting is reached: `bootstrap/fixpoint.sh` builds a
 (Self-hosting is reached: `bootstrap/fixpoint.sh` builds a
 byte-identical compiler image; `stdlib/` + `runtime/syslib` are in
 byte-identical compiler image; `stdlib/` + `runtime/syslib` are in

+ 88 - 0
docs/summary_class-lowering.md

@@ -0,0 +1,88 @@
+# Step: Clarion CLASS lowering — design (not yet implemented)
+
+Status: **not started** (scoped here). Suite **137/137**; fixpoint OK.
+
+## Current state
+
+Classes *parse, scope and check* — fields, methods, `=` consts,
+single/multiple parent lists, `VIRTUAL`, and `CLASS IMPLEMENTATION`
+blocks with nested procedures — but every class/method ends in error
+**230** and method bodies are suppressed (`QbeGen.SetNoEmit(TRUE)` +
+`AbortFunc` in `MethodImpl`). See `docs/OOP.txt` for the grammar.
+
+## Goal
+
+Make a class a usable **value** with callable methods:
+
+```modula-2
+TYPE
+  CLASS Point;
+    x, y : INTEGER;
+    PROCEDURE Set(a, b : INTEGER);
+    PROCEDURE Get() : INTEGER;
+  END Point;
+CLASS IMPLEMENTATION Point;
+  PROCEDURE Set(a, b : INTEGER);
+  BEGIN x := a; y := b END Set;
+  PROCEDURE Get() : INTEGER;
+  BEGIN RETURN x + y END Get;
+END Point;
+VAR p : Point;
+BEGIN p.Set(3, 4); ExitCode := p.Get() END
+```
+
+## Design sketch
+
+1. **Layout** — a class is a record: fields get declaration-order
+   offsets via the existing `ComputeOffsets`/`FieldOffset` machinery
+   (already shared with `RECORD`; `PushRecord` already accepts
+   `FClass`). `obj.field` then works through the record field path.
+   Single inheritance prepends the parent's fields (offset by the
+   parent's size); multiple parents stay 230.
+
+2. **Receiver** — each method gets a **hidden first parameter** `THIS`
+   of type `POINTER TO <class>`. Inside a method body, a bare field
+   name `f` is an implicit `THIS^.f`; the class scope already holds the
+   fields as `KindField`, so `Design` needs a "current receiver"
+   addressing mode (like `WITH`): push the receiver register at method
+   entry, add `FieldOffset` to it, load/store.
+
+3. **Calls** — `obj.M(args)` binds statically to the method's mangled
+   symbol and passes `ADR obj` as the hidden first argument, then the
+   user arguments. `QbeGen.CallBegin`/`ArgList` gain a flag for the
+   implicit receiver. Non-virtual first; `VIRTUAL` accepts but
+   dispatches statically with a `230`-free path.
+
+4. **Dispatch (later)** — a per-class vtable (one static array of code
+   pointers, parent entries first) stored as a hidden first field;
+   `VIRTUAL` calls load the slot and call indirectly (procedure types
+   + indirect calls already exist from step 8.5). This can be a
+   follow-on increment.
+
+5. **`WITH`-style field binding** — reuse `PushRecord`/`PushWith`; the
+   receiver is the `WITH` base, so `WITH p DO x := 1 END` works for
+   free once (2) lands.
+
+## Acceptance (planned)
+
+- The `Point` program above compiles and exits 7.
+- `obj.field` read/write, method calls with value and `VAR` params,
+  methods returning values.
+- Single inheritance: child methods see parent fields.
+- Suite green; fixpoint still byte-identical.
+
+## Risks
+
+- `Design`'s addressing is threaded through several productions;
+  adding a receiver mode must not change existing `RECORD`/`WITH`
+  codegen (fixpoint is the guard).
+- `VIRTUAL`/vtable must not perturb layout for non-virtual classes.
+
+## Files (planned)
+
+`compiler/src/M2.atg` (`ClassRest`/`ClassImplRest`/`MethodImpl`
+lowering, `Design` receiver mode, call-site receiver),
+`compiler/src/SymTab.def`/`.mod` (receiver scope, parent field
+offsets, vtable), `compiler/src/QbeGen.def`/`.mod` (receiver param,
+vtable emission, indirect `VIRTUAL` calls),
+`compiler/tests/t_class*.mod`, `docs/OOP.txt`.

+ 49 - 0
docs/summary_polish-ustr-iochan.md

@@ -0,0 +1,49 @@
+# Step: UString concat/LEN + IOChan position/seek
+
+Tag `v3-polish-ustr-iochan`. Suite **137/137**; fixpoint **OK**
+(image **2,156,095 bytes**).
+
+Two of the three remaining polish items; Clarion `CLASS` lowering is
+scoped separately (`docs/summary_class-lowering.md`).
+
+## UString concatenation and length
+
+- `U"a" + U"b"` concatenates descriptors: `QbeGen.UStrCat` →
+  shim `m2ustrcat` (static buffer; consume before the next concat).
+- A **single-codepoint** operand (`U"x"` is a `UCHAR`) becomes a
+  1-codepoint UString via `QbeGen.UStrFrom` → `m2ustrfrom`. The shim
+  uses a small rotating pool so an expression can supply both
+  operands before `m2ustrcat` reads them.
+- `LEN`/`LENGTH`/`HIGH` of a `U"…"` literal read the descriptor
+  header: `QbeGen.UStrLen` → `m2ustrlen` (and `DecQ` for `HIGH`).
+  A single-codepoint literal is `LEN = 1`, `HIGH = 0`.
+- `+` handles `UString+UString`, `UString+UCHAR`, `UCHAR+UString` and
+  `UCHAR+UCHAR`; the result type is `ClUStr`.
+
+Note: `LEN(expr)` where the operand is a computed expression (e.g.
+`LEN(U"a" + U"b")`) is not accepted — `LEN`/`HIGH` take a designator
+or a literal, as before.
+
+## IOChan positioning
+
+- `Position(cid):INTEGER`, `Seek(cid, pos):BOOLEAN`,
+  `Rewind(cid):BOOLEAN`.
+- Over `SysShim.ftell`/`fseek` → shim `m2ftell`/`m2fseek`
+  (`fseek(..., SEEK_SET)` + `clearerr` on rewind).
+
+## Tests
+
+- `t_ustrcat.mod` (63): `LEN`/`LENGTH`/`HIGH` of literals,
+  `U"ab"+U"cd"`, `U"x"+U"é"`.
+- `iochanseek_prog.mod` (15): write 6 bytes, `Position`, reopen,
+  `Position` after reads, `Rewind`, `Seek(3)`, read line back.
+
+## Files
+
+`compiler/src/{QbeGen.def,QbeGen.mod}` (`UStrCat`/`UStrFrom`/
+`UStrLen`/`DecQ`), `compiler/src/{SymTab.def,SymTab.mod}`
+(`UStrCompat`), `compiler/src/M2.atg` (UString `+` and `LEN`),
+`runtime/syslib/shim.c` (`m2ustrcat`/`m2ustrfrom`/`m2ustrlen`/
+`m2ftell`/`m2fseek`), `runtime/syslib/SysShim.def`/`.mod`,
+`stdlib/iochan.def`/`.mod`, `compiler/tests/{t_ustrcat,iochanseek_prog}.mod`,
+`compiler/run_tests.sh`, `docs/features.md`.