|
|
@@ -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.
|