Ver código fonte

docs: analyse pragma options for V3

Eric Streit 3 dias atrás
pai
commit
ce0be764e3
2 arquivos alterados com 268 adições e 7 exclusões
  1. 2 2
      docs/INDEX.md
  2. 266 5
      docs/future-work-2026-10-25.md

+ 2 - 2
docs/INDEX.md

@@ -35,8 +35,8 @@ bisecting *why* a decision was made, not for reading end-to-end).
 ## Future-work analysis
 
 - **`future-work-2026-10-25.md`** — TBITSIZE, ADDRESS arithmetic, set
-  ordering, complex types, PIM vs ISO coroutines, external assembly,
-  dynamic-set design and suggested order.
+  ordering, complex types, pragmas (TopSpeed vs portable), PIM vs ISO
+  coroutines, external assembly, dynamic-set design and suggested order.
 
 ## Designs / running records
 

+ 266 - 5
docs/future-work-2026-10-25.md

@@ -2,7 +2,7 @@
 
 This note records the design discussions from 2026-10-25 so the
 questions do not have to be re-derived later.  It covers `TBITSIZE`,
-address arithmetic, set ordering, complex types, PIM versus ISO
+address arithmetic, set ordering, complex types, pragmas, PIM versus ISO
 coroutines, external assembly, and the dynamic-set design.  It is not a
 commitment to implement everything.
 
@@ -443,16 +443,277 @@ prefer small C wrappers where necessary.
 
 ---
 
-## 8. Suggested order of future work
+## 8. Pragmas: TopSpeed compatibility versus portable scoped pragmas
+
+V3 has no general pragma facility.  It currently parses and ignores two
+gm2 declaration pragmas (`__BUILTIN__` and `__ATTRIBUTE__
+__BUILTIN__ (( name ))`) after `PROCEDURE`, and its TopSpeed sidecar
+lexes `(*# ... *)` as an ordinary comment.  The local `EXCEPTIONS.def`
+therefore omits `<* noreturn *>`.
+
+There are two separate design questions:
+
+1. give V3 a native pragma facility;
+2. consume legacy TopSpeed pragmas.
+
+The recommendation is to separate them: use the portable, scoped model
+as the native design, and add a narrow TopSpeed compatibility mode.
+
+### 8.1 TopSpeed V3 pragmas
+
+TopSpeed Modula-2 pragmas are a special form of comment:
+
+```modula2
+(*# save *)
+(*# check(range => on, index => off, overflow => off) *)
+PROCEDURE P (...);
+(*# restore *)
+```
+
+They are **stateful compiler directives**:
+
+- a setting applies from that point forward;
+- `save` / `restore` maintain a stack of compiler settings;
+- a procedure's calling convention is the setting in force at its
+  definition;
+- a variable's layout is the setting in force at its declaration.
+
+They are grouped into pragma classes:
+
+- `check(...)` — range, index, overflow, NIL, stack checks;
+- `call(...)` — calling convention, register parameters, interrupt
+  handlers, open-array passing;
+- `data(...)` — segments, packing, volatile, enum size, stack/heap size;
+- `optimize(...)` — CSE, register allocation, peephole, CPU choice;
+- `module(...)` — initialization code, implementation-object rules;
+- `name(...)` — external symbol naming;
+- `debug(...)` — debug information and procedure tracing;
+- `option(...)` — language extensions such as bitwise operations on
+  cardinals;
+- `save` / `restore` — compiler-option stack;
+- `link`, `project`, `define` — project-system integration.
+
+Older `$` compiler directives are also accepted by TopSpeed for
+compatibility.
+
+**Strengths**
+
+- Pragmatic and expressive.
+- Local check overrides without recompiling the build system.
+- Historical TopSpeed code already uses the syntax.
+- Easy to lex as a comment; V3's corpus already parses `(*# ... *)`.
+
+**Problems for V3**
+
+- Much of it is tied to 16-bit x86: segments, near/far calls,
+  interrupts, `reg_param`, `iopl`, memory models, overlays, CPU and
+  coprocessor selection.  These do not map to V3's amd64/QBE target.
+- Semantics are position/state-dependent rather than attached to
+  declarations.
+- Source annotations are mixed with global build settings such as
+  optimisation and debug options.
+- It is a frozen, vendor-specific dialect, not a portable standard.
+- Because `(*# ... *)` is a comment to other compilers, ignoring it
+  silently changes checks, layout or ABI without any diagnostic.
+
+TopSpeed pragmas are therefore useful as a **compatibility adapter**,
+not as V3's native pragma model.
+
+### 8.2 Benjamin / R10 portable pragmas
+
+The portable proposal (used by Modula-2 R10/BSK) uses `<* ... *>`:
+
+```modula2
+PROCEDURE Reboot <*NORETURN*>;
+
+TYPE Header = RECORD <*PACKED*>
+  ...
+END;
+
+VAR Port <*VOLATILE*> : BYTE;
+```
+
+It defines:
+
+- standard pragmas in uppercase;
+- implementation-defined pragmas with a lowercase implementation prefix,
+  e.g. `<*v3.SomeOption=...*>`;
+- explicit scopes for module, type, record, field, procedure and
+  parameter placement, plus point-forward and no-scope placement;
+- combinable clauses in one block;
+- `PRESETS` / `UNSET` for external pragma settings instead of a
+  TopSpeed-style global `save` / `restore`;
+- a mandatory BSK subset: `DEPRECATED`, `FFI`, `FFIDENT`, `INLINE` and
+  `PRIVATETO`, plus `ENCODING` where Unicode is supported.
+
+The full proposal is much larger: `ABI`, `ADDR`, `ALIGN`, `PACKED`,
+`PADBITS`, `LEADBITS`, `VOLATILE`, `NORETURN`, `PURE`, `WEAK`, `IN`,
+`OUT`, `SINGLEASSIGN`, `ARC`, `GC`, `OWNER`, `BORROWER`, `RETAIN`,
+`RELEASE`, `MSG`, `TELL`, `TICKET` and others.  R10 itself omits some of
+these (`RANGE`, `RELEASE`, `RETAIN`).
+
+**Strengths**
+
+- Attached to syntax, not a global mutable state.
+- Deterministic and easier to validate.
+- Fits definition/implementation consistency and separate compilation.
+- `<* ... *>` aligns with ISO-style/gm2 pragma syntax.
+- Implementation-defined pragmas have a collision-free namespace.
+- Provides a path to standard annotations for ABI, layout, volatility
+  and diagnostics.
+- Much better fit for a strict, self-hosting compiler.
+
+**Problems**
+
+- The proposal is large; implementing all of it is a project of its
+  own.
+- Many pragmas are promises that require real analysis:
+  `PURE`/`WEAK`/`DETM` need effect checking, `IN`/`OUT` need
+  parameter-write analysis, `NORETURN` needs control-flow checks and
+  `SINGLEASSIGN` needs data-flow checks.
+- Some are irrelevant to V3: `ARC`, `GC`, `OWNER`, `BORROWER`,
+  `RETAIN`, `RELEASE`; `RESIDENT`, `CONTIGUOUS` and `LOWLATENCY` are
+  mostly OS/runtime hints; `ENCODING` needs scanner/Unicode work.
+- `ADDR`, `ALIGN`, `PACKED`, `PADBITS` and `LEADBITS` require real
+  layout support.
+- The proposal is still evolving; V3 should implement a versioned
+  subset, not chase every edit.
+
+### 8.3 Comparison
+
+| Aspect | TopSpeed V3 | Benjamin / portable |
+| --- | --- | --- |
+| Status | Vendor dialect | Proposed portable specification, used by R10/BSK |
+| Delimiters | `(*# ... *)` | `<* ... *>` |
+| Form | `class(name => value, ...)`, `save`, `restore` | `PRAGMA`, `PRAGMA=expr`, clause sequences |
+| Scope | Stateful from point forward | Attached to explicit syntactic scopes |
+| ABI/layout | Many 16-bit-specific directives | Portable ABI/layout annotations |
+| Unknown pragmas | Often ignored or comment-like | Standard versus implementation-defined, diagnosable |
+| Separate compilation | Needs external project-state discipline | Naturally attachable to symbols and object stamps |
+| V3 fit | Compatibility adapter | Native pragma design |
+
+TopSpeed is not a standard; the `<* ... *>` syntax is the better
+long-term direction because it is already used by ISO-style/gm2
+compilers and by the portable proposal.
+
+### 8.4 Recommended V3 design
+
+Use `<* ... *>` with explicit scope attachment as the native pragma
+syntax.  Do not make `(*# ... *)` the default; handle it only in the
+TopSpeed sidecar or behind an explicit compatibility flag.
+
+**Phase 1 — infrastructure and low-risk semantics**
+
+- scanner/parser support for `<* ... *>` and adjacent blocks;
+- AST/symbol-table pragma nodes with source locations;
+- scope validation;
+- unknown-pragma policy;
+- `DEPRECATED`;
+- `NORETURN`;
+- `NOINLINE`;
+- `INLINE` as advisory, with a warning if not honoured;
+- `MSG` / `TICKET` diagnostics if desired;
+- `PRIVATETO`.
+
+`NORETURN` is especially valuable immediately: it lets V3 consume
+standard ISO/gm2 definition files without stripping pragmas.
+
+**Phase 2 — layout and ABI**
+
+- `PACKED`;
+- `ALIGN` / `MEMALIGN`;
+- `FFI` / `FFIDENT`;
+- `ADDR` only once absolute variables and address arithmetic are
+  designed;
+- `PADBITS` / `LEADBITS` only after packed-record layout exists.
+
+Every ABI/layout pragma must participate in:
+
+- definition/implementation consistency checks;
+- the separate-compilation object ABI stamp;
+- the content hash used by `M2make --separate`.
+
+Otherwise two objects can disagree about record layout or symbol names
+and still link.
+
+**Phase 3 — contracts**
+
+- `PURE`, `WEAK`, `DETM`;
+- `IN` / `OUT`;
+- `SINGLEASSIGN`.
+
+These should not be accepted as no-ops.  If V3 cannot verify them, it
+should reject them or emit a clear "accepted but not enforced" warning.
+Silently pretending to enforce a promise is worse than not supporting
+it.
+
+**Do not implement initially**
+
+- `ARC`, `GC`, `OWNER`, `BORROWER`, `RETAIN`, `RELEASE`;
+- `RESIDENT`, `CONTIGUOUS`, `LOWLATENCY`;
+- full `PRESETS` / pragma-file machinery;
+- Unicode `ENCODING`.
+
+These need runtime support V3 does not have, or are platform hints with
+little value on the current target.
+
+### 8.5 TopSpeed compatibility
+
+Keep TopSpeed pragmas out of the default V3 grammar.  Handle them in the
+existing `TopSpeed-V3-M2.atg` sidecar, or add a
+`--topspeed-pragmas` mode to the main compiler.
+
+Map only the meaningful subset:
+
+- `check(range/index/overflow/nil/stack)`;
+- `data(packed/volatile)`;
+- `module(init_code)`;
+- `call(c_conv)`;
+- `save` / `restore`.
+
+Reject or warn about:
+
+- `near_call`, `far`, segments, `seg_name`, `ds_*`;
+- `reg_param`, `reg_saved`, `reg_return`;
+- `interrupt`, `iopl`;
+- overlays, memory models, `cpu`, `copro`;
+- Windows/OS2/DOS-specific options.
+
+TopSpeed stateful pragmas can be translated by keeping an option stack
+during parsing and snapshotting the current state onto each declaration.
+That is an adapter, not the native model.
+
+### 8.6 Never silently ignore
+
+- A TopSpeed pragma that V3 treats as a comment must produce at least a
+  warning in TopSpeed-compatibility mode.
+- An unknown standard pragma should be an error.
+- An unknown `v3.*` pragma should be a warning or informational message.
+
+Otherwise V3 will compile code with different checks or ABI and call it
+success.
+
+### 8.7 Sources
+
+- TopSpeed Developer's Guide, chapter on pragmas.
+- `trijezdci/M2-Pragmas` wiki, especially *Pragma Specification*,
+  *Pragma Placement* and *Pragma Scopes*.
+- Modula-2 R10/BSK pragma facilities chapter.
+
+---
+
+## 9. Suggested order of future work
 
 1. `TBITSIZE` (small, standard-facing).
 2. `ADDADR`/`SUBADR`/`DIFADR` (small, ISO SYSTEM).
 3. Set ordering (bounded gm2 compatibility; fixes `largeset5`).
 4. Complex types: choose ISO built-ins versus a nonstandard value-record
    library; remove the misleading `COMPLEX*` aliases.
-5. ISO `COROUTINES` subset, then interrupt/protection layer.
-6. Dynamic `SET CONST` and deep composite copies.
-7. Parser error recovery and diagnostics.
+5. Pragmas: native `<* ... *>` parser/IR plus a low-risk semantic
+   subset; later add the TopSpeed adapter and ABI/layout pragmas.
+6. ISO `COROUTINES` subset, then interrupt/protection layer.
+7. Dynamic `SET CONST` and deep composite copies.
+8. Parser error recovery and diagnostics.
 
 External assembly needs no compiler work; document it as the supported
 low-level escape hatch.