TMod-c — Current Status

Rebrand (July 2026): Public project and language name is TMod-c (TYPE compiler). Mod-c is the legacy name during transition — repo directory, modc binary, and modc-mh/1 format id are unchanged until migration completes. Target compiler binary: tmodc; system ABI module: tmodc.mc / tmodc.h. Domains: tmodc.com, tmodc.org, tmodc.net.

Version: 0.26.5 (build 179)
Last updated: 2026-09-04
Active branch: mod-c_0.26
Tag: MOD-C_0.23.7 (items 5–6); 0.23.8 postfix FORWARD; 0.23.9 type-qualified methods; 0.24.0 .mh writer + reader; 0.24.2 test-tier Makefiles; 0.24.3 builtin integer/cardinal lowering; 0.24.4 codegen_header.mc self-host step; 0.24.5 qualident IMPORT … FROM; 0.24.6 ENUM Phase A/B; 0.24.7 ENUM Phase C + .mh negative import tests; 0.24.8 named CONST array bounds + const-eval; 0.24.9 symkind / mh_exportkind as .mc; 0.24.10 statement.mc; 0.24.11 expression.mc + OPAQUE (13a); 0.24.12 UNION (13c); 0.24.13 linked-chunk arena + STRUCT EXTENDS option A (13d); 0.24.14 Lexer.mc self-host + type_of_expr / init inference (21a); 0.24.15 discard enforcement (13b Policy A); 0.24.16 declaration.mc self-host + EXTENDS by-value auto-upcast; 0.24.17 instance methods (21) + static/instance by first formal; 0.24.17.135 type Name FORWARD; 0.24.18 #11 Phase A portable unit rebind; 0.25.0 item 20 VAR/REF/CONST formals (breaking); 0.25.1 callable field call-through; 0.25.2 cross-module method Phase A; 0.25.3 .mh formal signatures + 7a; 0.25.4 RECURSIVE enforce + signed SIZEOF + lean C prelude; 0.26.0 free-call soft-miss closed; 0.26.1 unknown types closed + no automatic stddef.h; 0.26.2 ParserTParser; 0.26.3 parser.cparser_common.mc + parser_main.mc; 0.26.3.170 .mh field lists; 0.26.4 method-type .mh RHS / cross-module field call-through; 0.26.5 width forms + .h prelude; 0.26.5.174 #11 import-bind + .mh widths; 0.26.5.175 EXTENDS polish (p^.x, as.base, pointer/REF upcast); 0.26.5.176 Oberon p.x auto-deref; 0.26.5.177 Shapes example + light refactor; 0.26.5.178 p[i] peel + instance method on ^T; 0.26.5.179 Type::m(p) peel.

Current Focus

Calm path (ordered — do in sequence):

Step Item Work
1 13a OPAQUE end-to-end Done (0.24.11).
2 13c Bare UNION Done (0.24.12) — parse / semantic / codegen_common_union_decl; tests green.
3 13d STRUCT EXTENDS option A Done (0.24.13) — chain clashes; synthetic base reserved only on EXTENDS; c.xc.base.x; multi-level.
4 21a type_of_expr + simple init inference Done (0.24.14) — unlocks discard (13b), auto-upcast, VAR/REF, obj.method.
5 13b Discard enforcement (Policy A) Done (0.24.15) — known result requires (f()) or use; unknown/procedure bare OK.

Suggested next language work (on mod-c_0.26):

  1. Close name soft-miss (breaking)Done. Calls 0.26.0; unknown types + drop automatic <stddef.h> 0.26.1. Prelude builtins and multi-word C spellings (long long, unsigned int) stay. size_t / FILE / void must be imported.
  2. .mh type completenessDone (0.26.3.170 field lists; 0.26.4 method-type RHS). Cross-module obj.field and obj.field(...) call-through. Import the method type and the struct (TFn + TBox). Identifiers ≤ 255; whole-file .mh load; writer DynBuf.
  3. #11 width formsDone (0.26.5). Exact integer N / cardinal N / real N (8/16/32/64; real 32/64). Generated .h owns the C prelude; -C writes a companion .h. Import as the one unit bind Done (0.26.5.174). .mh width spelling Done (0.26.5.174). Still open (same item): arch packs (tmodc.lp64, …); build-time defaults; optional .mh alias RHS (export type integer complete integer 64).
  4. Optional EXTENDS polishaggregate as.base Done (0.26.5.175); pointer/REF upcast Done (0.26.5.175); ^T parent fields (p^.x) Done (0.26.5.175); Oberon p.x auto-deref Done (0.26.5.176); p[i] peel Done (0.26.5.178); instance method on ^T Done (0.26.5.178); Type::m(p) peel Done (0.26.5.179). Still open (same item): parent-chain methods. See Recent Accomplishments (0.26.5.179).
  5. Soft item 20 — named open-array alias formals. Bare formals stay by-value — see docs/parameter-passing.md.
  6. Soft: 21a-ternary; discard _ (24); #19 CONST codegen. Self-host remains background. 7b startup auto-initCancelled (31 August 2026). Call module entries explicitly (7a). No generated main walk of imports.
  7. Later: loop-local FOR (breaking, JPL Power of Ten rule 6) — counted FOR always declares a read-only index; not a use of an enclosing VAR. See Future plan: loop-local FOR below. Not started; do not slip into 0.26.x calm-path work.
  8. Later: optional BOUND on WHILE / REPEAT / LOOP (JPL rule 2) — const trip count; loop bound 0 = idle loop. See Future plan: BOUND. Not 0.26.x.
  9. Later: drop unused IS — lexer keyword / EBNF relational op; never parsed. No type guards / RTTI. See Drop IS. IN stays reserved for SET OF membership (item 12).
  10. Later: cyclic TMod-c IMPORT — after Makefile subdirectory compilation (item 15). parser_main ↔︎ declaration / expression / statement works today via generated C headers and previously emitted .mh. Do not design a language rule until directories land. Interim: extract a shared module (parser_common).
  11. When a stdlib is designed: borrowed / pre-allocated buffers (e.g. TStringBuffer::init_at), not only malloc/realloc. See Stdlib: borrowed buffers.
  12. Later: SET OF enum (Wirth bitset, not a hash set) — IN, { … } literals, named CONST sets, + * - == !=. See Future plan: SET OF enum. Not 0.26.x.

0.26.5.179 closes Type::m(p) peel (@x not peeled). 0.26.5.178 closed p[i] peel and instance method on ^T. 0.26.5.177 is a light refactor plus examples/Shapes.mc. 0.26.5.176 closed Oberon p.x auto-deref. 0.26.5.175 closed EXTENDS polish (p^.x / as / pointer·REF). 0.26.5.174 closes import-as-bind and .mh width tails. 0.26.5.173 closed width forms and moved the C prelude into generated .h. 0.26.4.172 closed .mh type completeness. 0.26.3.168 closed parser.c self-host. 0.26.1.158 closed unknown type names and dropped automatic <stddef.h>. 0.26.0.156 closed free-call soft-miss. No hidden RTTI / type tags / vtables on structs (Modula-2 + C stance).

EOS layout rules (0.24.3) remain in force. Arena growth is pointer-stable (linked chunks; no whole-slab realloc).

Future plan: loop-local FOR (JPL Rule 6)

Status: Design locked (20 August 2026). Not implemented. Breaking when done — sole FOR form; no dual FOR i := on an existing VAR. Spec in docs/syntax-ebnf.md + Language Report (docs/language-report.md) when the bump starts.

Why: C11 for (int i = …) / Modula-3 / Ada: the index exists only for the loop. Today TMod-c is Oberon/Pascal (FOR i := assigns a predeclared var i; codegen for (i = start; …)). JPL Power of Ten rule 6 wants smallest scope.

Syntax (declaration =, same optional type as var-item / let-item):

for-statement =
    "FOR" identifier [ ":" type-specifier ] "=" expression
        ( "TO" | "DOWNTO" ) expression
        [ "BY" const-expression ]
    "DO" { invariant-clause } statement-sequence "END" ;
for i = 0 to n do … end
for i: integer = 0 to n do … end
for i = n downto 0 by 1 do … end

Semantics

Codegen — same wrapper as now; i is a new local in that block:

{
    const long long __for_end_lN = (long long)(end);
    for (integer i = start; (long long)(i) <= __for_end_lN; i++) {}
}

Start evaluated once as the initializer. End stays precalculated. i is not C const (the header does i++); read-only is a TMod-c body rule. Nested for i = … each have their own { }.

When implementing: parser (:== + optional type); semantic (define loop-scoped binding, keep write-forbid, no enclosing-VAR lookup); codegen_c_for_stmt; tests; mechanical sweep of src/*.mc and tests (for i :=for i =, drop loop-only var i). Version bump (not a quiet 0.26.x patch). Empty TO range still does not enter; BY 0 stays illegal.

Future plan: BOUND on WHILE / REPEAT / LOOP (JPL Rule 2)

Status: Design locked (31 August 2026). Not implemented. Optional in the language; a later --pot (or equivalent) may require it. Do not slip into 0.26.x. FOR does not take BOUND (it already has TO/DOWNTO).

Why: Holzmann rule 2 — every loop has a tool-visible trip ceiling, except one identified non-terminating task loop. INVARIANT is a boolean, not a max count.

Syntax (const-expression, same family as FORBY / array bounds):

while-statement =
    "WHILE" expression "DO"
        [ "BOUND" const-expression ]
        { invariant-clause }
        statement-sequence
    "END" ;

repeat-statement =
    "REPEAT"
        [ "BOUND" const-expression ]
        { invariant-clause }
        statement-sequence
    "UNTIL" expression ;

loop-statement =
    "LOOP"
        [ "BOUND" const-expression ]
        { invariant-clause }
        statement-sequence
    "END" ;
while p <> nil do
    bound 4096
    p := p^.next
end

repeat
    bound 8
    try_once
until done

loop
    bound 0
    wait_for_cmd
end

Semantics

When implementing: statement.mc + EBNF + Language Report §7.1; semantic: const-eval, BOUND 0 only on LOOP; codegen trip counter + assert; tests (including test3 for while … bound 0). Keyword BOUND. May share a version bump with loop-local FOR or land separately.

Drop IS (no type guards)

Status: Locked (31 August 2026). Not implemented. Lexer still reserves IS (TOK_KEYWORD_IS); parser never uses it. EBNF no longer lists IS (relational-op is IN only). Language Report §6.3: IN is planned set membership; IS is dropped.

Oberon IS is a runtime type test (p is T) — needs RTTI or a tag. TMod-c: no vtables / no IS on structs. Remove the keyword (lexer table, TokenKind::string, EBNF relational-op / keyword, report). is becomes a legal identifier.

IN: still reserved; unused as an operator. Keep — v1 SET OF enum membership (not a type guard). See Future plan: SET OF enum.

When implementing: small mechanical drop; any test3 that used IS as a keyword should expect an identifier. Spec in docs/syntax-ebnf.md + Language Report. Not 0.26.x calm-path.

Future plan: SET OF enum (Wirth bitset)

Status: Design locked (2 September 2026). Not implemented. After the current higher-priority list. Do not slip into 0.26.x. Spec in docs/syntax-ebnf.md + Language Report §5 / §6.3 when the bump starts (productions already drafted as Planned).

Why: IN is in the grammar for set membership, not type guards (IS is dropped). Compiler source wants named groups (LOOP_KINDS) and kind in LOOP_KINDS instead of or chains. This is Pascal/Modula-2 SET OF: a bit vector on a small ordinal, not Julia/Python Set{T} (hash table, heap, arbitrary T). Hash sets, if ever, are stdlib — not IN.

v1 surface

type NodeKindSet = set of NodeKind

const LOOP_KINDS: NodeKindSet =
    { NODE_FOR, NODE_WHILE, NODE_REPEAT_UNTIL, NODE_LOOP }

if new_parent^.kind in LOOP_KINDS then
    child.enclosing_loop := new_parent
end

Codegen — bit test / mask; no heap:

typedef uint64_t NodeKindSet;
static const NodeKindSet LOOP_KINDS =
    (1ULL << NODE_FOR) | (1ULL << NODE_WHILE) |
    (1ULL << NODE_REPEAT_UNTIL) | (1ULL << NODE_LOOP);

if (LOOP_KINDS & (1ULL << new_parent->kind))
    child.enclosing_loop = new_parent;

TMod-c still rejects mixing ColorSet with NodeKindSet even if both are 64-bit in C.

v1 rejects: SET OF integer / real / struct / string; enumerator = 1000 or more than 64 members; SET OF char (256 bits — later); FOR x IN s; CARD; hash Set. Optional later: <= subset, XOR symmetric difference, NOT complement in E, Ada-style x in (A, B) sugar.

When implementing: keyword SET; set-type in type-expression / type-specifier; IN in the relational parser (token exists); { … } set vs array in semantic; operator types; tests (test_* membership/algebra, test3_* bad base type / ordinal out of 0..63). Version bump (not a quiet 0.26.x patch). May land after IS drop so IN is the only leftover relational keyword.

7b cancelled — no startup auto-init

Status: Won’t do (31 August 2026). Item 7a (module entry as an importable symbol) stays.

Do not generate calls of imported MODULE bodies from PROGRAM / main (Modula-2 / Delphi style). Hidden init is extra control flow (JPL rule 1) and a place to hide malloc (rule 3). Authors call the bound module entry explicitly when they want it. Optional module BEGINEND remains a procedure the programmer invokes — not a constructor the compiler schedules.

Stdlib: borrowed buffers (when designed)

Not scheduled. tests/StringBuffer.mc today mallocs / reallocs / owns _data — fine for hosted tests, not a flight/Wasm default.

When a real stdlib is designed, prefer caller RAM:

procedure TStringBuffer::init_at(ref b: TStringBuffer, buf: ^char, cap: integer)

Hosted growing StringBuffer may remain for the compiler and Linux tests. Flight / --pot / wasm32 guests should not need realloc.

DbC resolve (REQUIRE / ENSURE)

Done in semantic_analyze_block_bodyrequires[] / ensures[] go through semantic_resolve_expr (same as loop INVARIANT and ASSERT). REF/VAR formals load as in the rest of the language.

Still not a nil-check of a REF T: n is the object. Nil-check ^T formals and pointer fields; check p <> nil before foo(p^). Remaining polish (not planned): side-effect-free contract lint; optional --pot “two assertions per routine” warn.

Recent Accomplishments (4 September 2026 — 0.26.5.179 / Type::m(p) peel)

Qualified instance Type::m(p) on ^Owner Done

Recent Accomplishments (4 September 2026 — 0.26.5.178 / p[i] peel + instance on ^T)

Pointer-to-array p[i] and p.method on ^T Done

Recent Accomplishments (4 September 2026 — 0.26.5.177 / Shapes + refactor)

Light refactoring already checked in. examples/Shapes.mc — tagged EXTENDS scene (no IS); field auto-deref (176); downcast p as ^Circle after a programmer tag.

Recent Accomplishments (3 September 2026 — 0.26.5.176 / Oberon p.x auto-deref)

Field auto-deref Done; p[i] and p.method on ^T not in this build (closed 0.26.5.178)

Recent Accomplishments (2 September 2026 — 0.26.5.175 / EXTENDS polish)

Optional #4 — three slices Done; Oberon p.x not in this build

Verification: user typed in; tests green. Build 175.

Recent Accomplishments (31 August 2026 — one Makefile / gcc · clang · tcc)

make                              # gcc (default)
make clean && make CC=clang test-all
make clean && make CC=tcc test-all

Recent Accomplishments (28 August 2026 — 0.26.5.174 / #11 import-bind + .mh widths)

Import as the one unit bind Done

.mh width spelling Done

Verification: user typed in; tests green. Build 174.

Recent Accomplishments (27 August 2026 — 0.26.5.173 / width forms + .h prelude)

Width forms Done (integer N / cardinal N / real N)

Generated .h owns the C prelude Done

Verification: make test-all on gcc, clang, and tcc. In-tree modules regenerated. Promoted 0.26.5.173.

Recent Accomplishments (26 August 2026 — 0.26.4.172 / method-type .mh RHS)

Method-type export / import Done

Recent Accomplishments (25 August 2026 — 0.26.3.170 / .mh field lists)

Identifiers ≤ 255 Done

.mh reader whole-file Done

Writer DynBuf prefixes Done

Field lists — writer / reader / import Done

Recent Accomplishments (24 August 2026 — 0.26.3.168 / parser self-host)

parser.cparser_common.mc + parser_main.mc Done

Cyclic .mh imports — noted, not designed

Recent Accomplishments (18 August 2026 — 0.26.1.158 / unknown types + no automatic stddef.h)

Unknown type names are errors Done (breaking)

Automatic <stddef.h> dropped Done

Verification: make test-all, selfhost, bootstrap, promote green on gcc, clang, and tcc. Promoted 0.26.1.158.

Recent Accomplishments (18 August 2026 — 0.26.0.156 / free-call soft-miss closed)

Unresolved free calls are errors Done (breaking)

Recent Accomplishments (14 August 2026 — 0.25.4.154 / RECURSIVE + signed SIZEOF + lean prelude)

RECURSIVE required on direct self-calls Done

SIZEOF is integer in C as well as in the type system Done

Lean generated C prelude Done (partial; <stddef.h> stays until 0.26)

Automatic includes: <stddef.h> (NULL, size_t), <stdint.h> (uint8_t), <stdbool.h>, <assert.h>.
typedef uint8_t byte;#define nil NULL / #define NIL NULL.
Portable four typedefs unchanged. No automatic <stdlib.h> / <stdio.h> / <string.h> / <math.h> / <limits.h> / <float.h>. exit and friends must be imported. Tests, examples, and src/*.mc updated.

Verification: make test-all, selfhost, bootstrap green on gcc, clang, and tcc. Promoted 0.25.4.154.

0.26: drop <stddef.h> / require every non-builtin nameDone (0.26.0–0.26.1). Next: .mh field lists.

Recent Accomplishments (12 August 2026 — 0.25.3.150 / 7a module-entry bind)

Item 7a — Module entry as a real symbol Done

Recent Accomplishments (11 August 2026 — 0.25.3 / formal signatures + cross-module auto-&)

Item 6a.mh formal signatures Done

Recent Accomplishments (11 August 2026 — 0.25.2 / cross-module methods Phase A)

Cross-module Type::method / obj.method Done (Phase A)

Recent Accomplishments (7 August 2026 — 0.25.1 / callable fields)

Callable field call-through Done

Recent Accomplishments (6 August 2026 — 0.25.0 / item 20)

Item 20 — VAR / REF / CONST formals Done (breaking)

Recent Accomplishments (6 August 2026 — 0.24.18 / #11 Phase A)

Item #11 Phase A — portable builtin unit rebind Done

type Name FORWARD (0.24.17.135) Done

Recent Accomplishments (3 August 2026 — 0.24.17 / item 21)

Item 21 — obj.method + instance vs static Done

Recent Accomplishments (1 August 2026 — 0.24.16 / auto-upcast)

EXTENDS by-value auto-upcast Done

Recent Accomplishments (31 July 2026 — 0.24.16 / declaration self-host)

Self-host: declaration.cdeclaration.mc Done

Recent Accomplishments (29 July 2026 — 0.24.15 / 13b)

Item 13b — discard enforcement (Policy A) Done

Recent Accomplishments (29 July 2026 — 0.24.14 / 21a)

Item 21a — type_of_expr + simple init inference Done

Design (same period)

Recent Accomplishments (28 July 2026 — 0.24.14)

Self-host: lexer.cLexer.mc Done

Self-host: lexer.cLexer.mc Done

Recent Accomplishments (25 July 2026 — 0.24.13)

Item 13d — STRUCT EXTENDS option A Done

Infrastructure — linked-chunk arena Done

Recent Accomplishments (23 July 2026 — 0.24.12)

Item 13c — bare UNION types Done

Item 13a — OPAQUE types Done (0.24.11.x)

Design discussion (future — not implemented)

Recent Accomplishments (0.24.11 — expression.mc)

Self-host: expression.cexpression.mc

Recent Accomplishments (18 July 2026 — design + self-host)

Self-host: statement.cstatement.mc (0.24.10.110)

Design — no user-facing void; OPAQUE types

Design — explicit discard of function results Implemented (0.24.15 / 13b Policy A)

Grammar + lexer groundwork

Prior same line (0.24.9)

Recent Accomplishments (16 July 2026 — 0.24.8)

Named CONST in array bounds

Integer const-eval (shared)

Release process

Recent Accomplishments (15 July 2026 — 0.24.7)

ENUM Phase C

.mh negative import tests

Test include paths (Makefile)

Design — WHILE … BY not planned

Recent Accomplishments (14 July 2026 — 0.24.6)

ENUM Phase A/B

tmodc ABI prelude (planned)

TMod-c rebrand (documentation)

Recent Accomplishments (13 July 2026 — 0.24.5)

Qualident IMPORT … FROM

Recent Accomplishments (11 July 2026 — 0.24.4)

codegen_header.mc (self-host)

Recent Accomplishments (9–10 July 2026 — 0.24.3)

Import sources — documented (phase 1 vs phase 2)

EOS / layout (expressions, statements, RETURN)

Prior — 0.24.3 (9 July 2026)

Builtin integer / cardinal lowering

Parser / layout (9 July — import/decl)

Prior — 0.24.2 infrastructure (9 July 2026)

Three-tier test targets (gcc / clang / tcc)

Negative test fixtures (test3_*)

Version / build numbering

Project housekeeping

Prior Release — 0.24.0 (7 July 2026)

.mh module linking — items 7–8

Cross-module Mod-c imports work end-to-end: EXPORT emits modc-mh/1 tables; IMPORT … FROM "*.mh" loads them at semantic analysis; generated C #includes the associated .h.

Self-host in progress: src/*.mc modules import from corresponding .mh files.

Design Decisions (still in force)

See docs/language-report.md (prose) and docs/syntax-ebnf.md (full EBNF). Filenames use hyphens (no _; syntax-ebnf.md not syntax.ebnf.md). Former monolithic docs/grammar.md is a redirect; archive in docs/grammar_working_notes.md. Highlights:

TODO / Next Actions

IMPORT / EXPORT / .mh polish

  1. Items 1–4 semantics phase 2 core. Done (0.23.3–0.23.5)
  2. Item 5 — sizeof(UserType) at parse time. Done (0.23.7)
  3. Item 6 — EXTERN TYPE | VAR | PROCEDURE | FUNCTION. Done (0.23.7)
  4. Item 7 — .mh writer on EXPORT. Done (0.24.0)
  5. Item 8 — .mh reader on IMPORT … FROM "*.mh". Done (0.24.0)
  6. .mh completeness / signature richness; method export coverage. Negative import tests. Done (0.24.7)test3_* tier. Method instance/static + import Type::name + cross-module obj.method (Phase A)Done (0.25.2). Formal signatures + cross-module auto-& (6a)Done (0.25.3). 6a. .mh formal signaturesDone (0.25.3). Type field lists / cross-module obj.fieldDone (0.26.3.170). Method-type RHS / field call-throughDone (0.26.4.172)complete function|procedure ( … ) [ : T ]; synthetic method_type; import the method type name as well as the struct.
  7. Qualident FROM. Done (0.24.5) — project-root path resolution (after Makefile subdirs); IMPORT * bulk import; IMPORT … AS … remain. 7a. Module entry as real import symbolDone (12 August 2026 / 0.25.3.150) — same-unit MODULE name + importer auto-bind of @module export; synthetic proc + formals; arena-copied names; module VAR/REF ABI. Tests test_module_ref / test_module_entry. 7b. Module startup initializationCancelled (31 August 2026). No generated calls of imported module bodies. Call the 7a-bound entry explicitly. See 7b cancelled.

Language (after .mh polish or parallel)

  1. FORWARD … END / EXTERN … END declaration blocks.
  2. type ident FORWARDDone (0.24.17.135) — incomplete types completed later in-unit.
  3. LEN — resolution done; codegen TBD (same signed integer type as SIZEOF when emitted). SIZEOF C typeDone (0.25.4)((integer)sizeof(...)). 10b. RECURSIVE on direct self-callDone (0.25.4)test3_recursive; mutual recursion later.
  4. Unit binding of bare integer / cardinal / real / string (Phase A TYPE)Done (0.24.18). Width forms integer N / cardinal N / real NDone (0.26.5). Import as the one bind Done (0.26.5.174). .mh width spelling Done (0.26.5.174). Still open: arch tmodc.* packs; build-time default selection; optional .mh alias RHS.
  5. ENUM — Phase A/B/C done (0.24.6–0.24.7). Tests: test2_enum_parse.mc, test_enum.mc, test3_enum_dup.mc, test_mh_enum_export.mc, test2_mh_enum_import.mc, test_mh_enum_import.mc.
  6. Named constants in array boundsDone (0.24.8)array[LIMIT] / array[LIMIT+1]; integer CONST fold; string CONST excluded from fold. 13a. OPAQUE typesDone (0.24.11) — TYPE RHS opaque / ^opaque / POINTER TO opaque; codegen void *; tests incl. negative bare opaque. 13b. Enforce discard form (Policy A)Done (0.24.15) — known result → (f()) or use; unknown/procedure bare OK; tests test_discard / test3_discard; gcc/clang/tcc green. 13c. UNION typesDone (0.24.12) — bare C union; is_union + codegen_common_union_decl; tests test_union / test3_union; gcc/clang/tcc green. 13d. STRUCT EXTENDS (Oberon layout / option A)Done (0.24.13) — clashes; base_depth rewrite; synthetic base (reserved only on EXTENDS); tests test_extends / test3_extends_*. By-value auto-upcastDone (0.24.16)upcast_depth; init / assign / return / same-unit call args; C .base × N. Polish: p^.x, as.base, pointer/REF upcastDone (0.26.5.175). Oberon p.x auto-derefDone (0.26.5.176). p[i] peel + instance on ^TDone (0.26.5.178). Type::m(p) peelDone (0.26.5.179). Still open: parent-chain methods.

Infrastructure

  1. Makefile test3 target — negative semantic tests. Done (0.24.2)
  2. Makefile subdirectory compilationsrc/ tree → build/; prerequisite for project-root module search paths. 15a. Cyclic IMPORT policy — after 15. Candidates later: extract-common (current), interface/implementation split, cycle ban, or interface-only first pass. Not a 0.26.x language change.
  3. Codegen: @ vs as precedence.
  4. Codegen: struct forward-declare / deferred p* typedefs.
  5. FOR end temp type from expression types.
  6. Compile-time CONST codegen — still C static const objects; intent #define / enum / literal fold at use sites. (Integer value fold for bounds done 0.24.8.)
  7. VAR / REF / CONST formalsDone (0.25.0) — codegen + semantic modes; call-site auto-&; breaking non-VAR bare-name assign. Soft: named array-alias formals. 20b. Callable field call-throughDone (0.25.1) — method-typed fields / values; Oberon no auto-self; ambiguity with instance methods; test_callable_field / test_Math.
  8. Instance methods phase 2Done (0.24.17)obj.method / chains / statements; instance vs static by first formal type; test_smoke / test3_smoke; gcc/clang/tcc green. 21a. type_of_expr + simple init inferenceDone (0.24.14)semantic_type_of_expr; init when : omitted; tests test_infer.mc; suite green. 21a-ternary. Ternary polish (later) — type cond ? a : b when both arms share one static type (and optionally array-literal inits); not required for 21a core.

Deferred

  1. Type guard selectors (IS)dropped (31 August 2026). Range expressions still deferred. IN unused as an operator; reserved.
  2. Stdlib BitSet; SET OF unlikely. Borrowed-buffer / init_at API when stdlib is designed (not malloc-only).
  3. Discard binding _ (optional sugar; distinct from (f()) statement discard).
  4. Optional BOUND on WHILE / REPEAT / LOOPplan.
  5. Drop keyword ISplan.

Strategic Direction

  1. TMod-c rebrand (in progress) — documentation and user-facing naming move to TMod-c / tmodc first; code and build artifacts keep modc aliases until deliberate cutover. tmodc system module (planned): width types and shared C ABI in tmodc.mctmodc.h; multi-TU generated C #includes tmodc.h. Language builtins stay in semantic prelude for now. Experimental src/tmodc.h exists for hand-written C that includes generated headers.
  2. Self-host with .mh imports — convert remaining src/*.c.mc (recent: parser_common / parser_main, declaration, Lexer, expression, statement, codegen_header, symkind, mh_exportkind, …); keep full chain green under make test-all.
  3. Polish .mh linking — method Phase A + formals (6a) Done (0.25.2–0.25.3); module-entry bind (7a) Done (12 August); type field lists Done (0.26.3.170); method-type RHS / field call-through Done (0.26.4.172). 7b Cancelled (explicit module-entry calls only).
  4. Declaration blocksforward/extern groups once .mh export shape is stable.
  5. Expression types / init inference (21a) Done. Discard (13b Policy A) Done. Instance methods (21) Done. VAR formals (20) Done (0.25.0). Callable fields Done (0.25.1). Cross-module method Phase A Done (0.25.2). Formal signatures / cross-module auto-& Done (0.25.3). Module-entry bind (7a) Done (12 August). RECURSIVE + signed SIZEOF + lean prelude Done (0.25.4). Free-call soft-miss Done (0.26.0). Unknown types + drop stddef.h Done (0.26.1). Parser self-host (parser_common / parser_main) Done (0.26.3). .mh field lists Done (0.26.3.170). Method-type RHS / field call-through Done (0.26.4.172). Width forms + .h prelude Done (0.26.5.173). #11 import-bind + .mh widths Done (0.26.5.174). EXTENDS polish (p^.x / as / pointer·REF) Done (0.26.5.175). Oberon p.x auto-deref Done (0.26.5.176). p[i] peel + instance on ^T Done (0.26.5.178). Type::m(p) peel Done (0.26.5.179). Remaining on this stem: CONST codegen; #11 arch packs / build-time defaults; parent-chain methods.
  6. OPAQUE (13a)0.26.5.179 Type::m(p) peel Done. Next: #11 arch packs; 21a-ternary later. Cyclic IMPORT after item 15. Later (not 0.26.x): loop-local FOR; optional BOUND; drop IS; SET OF enum.

Useful Commands

make                              # gcc (default)
make CC=clang                     # clang flags
make CC=tcc                       # tcc flags
make clean && make CC=clang test-all
make clean && make CC=tcc test-all

make test                         # test_* compile + run
make test2                        # test2_* semantic (-a)
make test3                        # test3_* negative (failure = pass)
make test-all                     # all three tiers

make version                      # manual: bump BUILD_NUMBER + src/version.h
make selfhost
make bootstrap
make promote

./bin/modc.0.25.4 tests/test_smoke.mc -C build/test/test_smoke.c
./bin/modc.0.25.4 tests/test_var_ref.mc -C build/test/test_var_ref.c
./bin/modc.0.25.4 tests/test_callable_field.mc -C build/test/test_callable_field.c
./bin/modc.0.25.4 tests/test_Math.mc -C build/test/test_Math.c
./bin/modc.0.25.4 tests/test3_var_ref1.mc -a              # expect non-zero (non-VAR assign)
./bin/modc.0.25.4 tests/test3_smoke.mc -a                 # expect non-zero (static via .)
./bin/modc.0.25.4 tests/test3_callable_field_ambig.mc -a  # expect non-zero (field vs instance)
./bin/modc.0.25.4 tests/test3_recursive.mc -a             # expect non-zero (self-call without RECURSIVE)
./bin/modc.0.25.4 tests/test_method.mc -C build/test/test_method.c
./bin/modc.0.25.4 tests/test_discard.mc -C build/test/test_discard.c
./bin/modc.0.25.4 tests/test3_discard.mc -a              # expect non-zero (tier-3 pass)
./bin/modc.0.25.4 tests/test_opaque.mc -C build/test/test_opaque.c
./bin/modc.0.25.4 -a tests/test5_mh_method_import_string.mc   # cross-module methods (needs include/*.mh)
./bin/modc.0.25.4 tests/test_module_ref.mc -C build/test/test_module_ref.c
./bin/modc.0.25.4 tests/test_module_entry.mc -C build/test/test_module_entry.c
./bin/modc.0.25.4 -a tests/test_mh_enum_import.mc
# make string-lib && link test4_string against -ltmod_string (manual; auto-& on free)
./bin/modc.0.24.17 tests/test_union.mc -C build/test/test_union.c
./bin/modc.0.24.17 tests/test_extends.mc -C build/test/test_extends.c
./bin/modc.0.24.17 tests/test3_extends_clash.mc -a           # expect non-zero (tier-3 pass)
./bin/modc.0.24.17 tests/test3_extends_base_reserved.mc -a # expect non-zero (tier-3 pass)
./bin/modc.0.24.17 tests/test3_opaque_parse.mc -a    # expect non-zero (tier-3 pass)
./bin/modc.0.24.17 tests/test3_union.mc -a           # expect non-zero if negative
./bin/modc.0.24.17 tests/test_mh_export.mc -C build/test/test_mh_export.c -M
./bin/modc.0.24.17 tests/test2_mh_import.mc -C tests/test2_mh_import.c -a
./bin/modc.0.24.17 tests/test_enum.mc -C build/test/test_enum.c
./bin/modc.0.24.17 tests/test_const.mc -C build/test/test_const.c
./bin/modc.0.24.17 tests/test3_enum_dup.mc -a    # expect non-zero (tier-3 pass)

Context & History

Prior Releases (summary)