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,
modcbinary, andmodc-mh/1format 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
Parser → TParser;
0.26.3 parser.c →
parser_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 |
|---|---|---|
OPAQUE end-to-end |
||
UNIONcodegen_common_union_decl; tests
green. |
||
STRUCT EXTENDS option Abase reserved
only on EXTENDS; c.x →
c.base.x; multi-level. |
||
type_of_expr + simple init inferenceobj.method. |
||
(f()) or use;
unknown/procedure bare OK. |
Suggested next language work (on
mod-c_0.26):
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/voidmust be imported.— Done (0.26.3.170 field lists; 0.26.4 method-type RHS). Cross-module.mhtype completenessobj.fieldandobj.field(...)call-through. Import the method type and the struct (TFn+TBox). Identifiers ≤ 255; whole-file.mhload; writerDynBuf.#11 width forms— Done (0.26.5). Exactinteger N/cardinal N/real N(8/16/32/64;real32/64). Generated.howns the C prelude;-Cwrites a companion.h.Import as the one unit bindDone (0.26.5.174).Done (0.26.5.174). Still open (same item): arch packs (.mhwidth spellingtmodc.lp64, …); build-time defaults; optional.mhalias RHS (export type integer complete integer 64).- Optional EXTENDS polish —
aggregateDone (0.26.5.175);as→.basepointer/Done (0.26.5.175);REFupcastDone (0.26.5.175);^Tparent fields (p^.x)OberonDone (0.26.5.176);p.xauto-derefDone (0.26.5.178);p[i]peelinstance method onDone (0.26.5.178);^TDone (0.26.5.179). Still open (same item): parent-chain methods. See Recent Accomplishments (0.26.5.179).Type::m(p)peel - Soft item 20 — named open-array alias formals.
Bare formals stay by-value — see
docs/parameter-passing.md. - Soft: 21a-ternary; discard
_(24); #19CONSTcodegen. Self-host remains background.7b startup auto-init— Cancelled (31 August 2026). Call module entries explicitly (7a). No generatedmainwalk of imports. - Later: loop-local
FOR(breaking, JPL Power of Ten rule 6) — countedFORalways declares a read-only index; not a use of an enclosingVAR. See Future plan: loop-local FOR below. Not started; do not slip into 0.26.x calm-path work. - Later: optional
BOUNDonWHILE/REPEAT/LOOP(JPL rule 2) — const trip count;loop bound 0= idle loop. See Future plan: BOUND. Not 0.26.x. - Later: drop unused
IS— lexer keyword / EBNF relational op; never parsed. No type guards / RTTI. See DropIS.INstays reserved forSET OFmembership (item 12). - Later: cyclic TMod-c
IMPORT— after Makefile subdirectory compilation (item 15).parser_main↔︎declaration/expression/statementworks 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). - When a stdlib is designed: borrowed / pre-allocated
buffers (e.g.
TStringBuffer::init_at), not onlymalloc/realloc. See Stdlib: borrowed buffers. - Later:
SET OFenum (Wirth bitset, not a hash set) —IN,{ … }literals, namedCONSTsets,+*-==!=. 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
FORalways introducesi(may shadow). AfterEND,iis gone — no “last index” unless copied inside.- Body cannot
i :=,INC(i),DEC(i), or passias aVARactual. Only the compiler writesi(init + step). - No hint → type is
integer(signed index/length lock). Do not infercardinalfrom acardinalbound. Hint, if present, must be integer-kind allowed for indexes (integer, laterinteger N). Start/end must fit that type. Not a C three-clausefor.
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 FOR … BY / 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
- Bound is compile-time; not a runtime
nthat changes. - Codegen: a local counter; reaching the bound is a failed
assert(same abort as DbC), not a silentbreak. BOUND 0only onLOOP: “non-terminating on purpose” (the idle / task loop). Illegal onWHILE/REPEAT.- Omitted
BOUND: legal in ordinary TMod-c.--pot(later, not scheduled) may require a bound except oneloop bound 0per task.
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:
SET OF EwhereEis an enum. Every enumerator value is a distinct constant in 0 .. 63. Onecardinal 64/uint64_tmask. - Constructor: Modula-2
{ a, b, c }— same braces asarray-literal; semantic picks set vs array from the expected type / element types. Empty{}needs a type ascription. - Named sets:
type NodeKindSet = set of NodeKindthenconst LOOP_KINDS: NodeKindSet = { NODE_FOR, NODE_WHILE, NODE_REPEAT_UNTIL, NODE_LOOP }. x IN s—xisE,sisSET OF E.s + tunion,s * tintersection,s - tdifference,s == t/s != t. Include/exclude vias := s + { x }/s := s - { x }.- Do not use
|/&on sets (those stay integer/enum flags).SET OF EandSET OF Fare different types.
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 BEGIN…END 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)
require buf <> nilandcap > 0; nomalloc/realloc; append fails (bool orassert) at capacity.freeof_dataonly if an optional hostedinitset an owns-flag;init_atdoes not own.- Same pattern for other containers:
ARRAY[N], orinit_at(p, n), never “grow until the heap says no.”
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_body —
requires[] / 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
Point::print(pp)=pp.print()whenppis^Point. First actual only; pointee name must be the owner. Reusescall.auto_deref; codegen peelsargs[0]when there is noreceiver_expr.- C — by-value
Point__print((*pp));REFPoint__scale(&(*pp), n). - Do not peel
@:TLexer::next(@p.lexer)stays&(p.lexer).(*&x)passed a struct by value (selfhostTParser::advance). - Do not peel
pp^: already a value (one caret wrap). - After
semantic_resolve_expron args. Only ifreceiver_expr == nil— an unconditionalauto_deref := falsewipedpp.getX()(argcis 0). - Tests:
tests/test_smoke.mc(Point::print(pp)/Point::scale(pp, 3)/Point::getX(pp)). Selfhost lexer@calls. - Still open (same item): parent-chain method lookup.
- Verification: user typed in; make test-all / selfhost / bootstrap / promote green on gcc, clang, and tcc. Build 179. Promoted 0.26.5.179.
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
p[i]=p^[i]when the left side is a pointer-to-array (^array[N] of Tor^NamewithNamean array typedef). One implied peel per[]. AST staysNODE_ARRAY_INDEX(array_index.auto_deref); no inserted caret.- Do not peel
^char[]—argv[i]is^char(array-of-pointer, not pointer-to-array). - C —
(*(p))[i]. Anonymous^array[N] of TemitsT (*name)[N](caret was previously ignored). Named^Vector3staysVector3 *p. - Explicit
p^[i]— postfix^emits(*(expr))so C[]does not bind tighter than unary*(*p[i]was*(p[i])). p.methodon^T—call.auto_deref; first formal still owner value (self: Point/ref self: Point), not^Point. C by-valueType__m((*p));REF/VAR&(*p).Type::m(p)closed in 179. No->.- Tests:
tests/test_array.mc(pv[i]/pv^[i]/pa[i]/argv[0]);tests/test_smoke.mc(pp.getX()/pp.print()/pp.scale(2)/Point::print(pp^)). - Still open then (closed 0.26.5.179): auto-peel of
Type::m(p). Still open: parent-chain method lookup. - Verification: user typed in; make test-all / selfhost / bootstrap green on gcc, clang, and tcc. Build 178. Promoted 0.26.5.178.
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)
p.x=p^.xwhen the left side is a pointer (^Tor named alias). One implied peel per.. AST staysNODE_FIELD_ACCESS(field_access.auto_deref); no inserted caret. Explicitp^.xunchanged.- Pointer test — use type or
resolved_typeis a pointer. Do not chase the alias first (^Childwould become namedChildand drop the flag). - C —
(*(p)).field, then.base×base_depth. No->.REF/VARformals still go throughemit_let_ident((*formal)); those are not TMod-c^T. - EXTENDS — parent fields work:
c5.x→(*(c5)).base.x(samebase_depthasc5^.x). - Tests:
tests/test_extends.mc(c5.x/pp.x/pg.z,p.xintakeParentPtr);tests/test_pointer_var.mc(root.value,p.next.valuebeside^.forms). - Still open then (closed 0.26.5.178):
p[i]peel for pointer-to-array — do not peel^char[]argv[i]; instance method on^T. - Verification: user typed in; make test-all / selfhost / bootstrap green on gcc, clang, and tcc. Build 176. Promoted 0.26.5.176.
Recent Accomplishments (2 September 2026 — 0.26.5.175 / EXTENDS polish)
Optional
#4 — three slices Done; Oberon p.x
not in this build
p^.xparent fields —semantic_type_of_designatorhandles postfix^andAS.c5^.xsetsbase_depth; C(*c5).base.x. (c5^.yalready worked.)g as Parent—upcast_depthfrom inner type vsAStarget; codegen omits(Parent)gand uses.base× N. Pointeras((@g) as ^Child) stays a C pointer cast unless it is an ancestor upcast (thenupcast_ptr).- Pointer /
REFupcast — both-pointer or both-value insemantic_extends_upcast_depth.Node.upcast_ptr: value((expr).base × N)soREF Parent+ Child actual is&((c).base);^Childwhere^Parentis needed is&((*(pc)).base). - Sites already wired: typed init,
:=,RETURN, same-unit call formals, plusAS. - Tests:
tests/test_extends.mc(user typed; green). - Still open then (field
.closed in 0.26.5.176;p[i]/p.methodclosed in 0.26.5.178):p[i]peel for pointer-to-array; instancep.methodon pointer receivers. Do not peel^char[]argv[i].
Verification: user typed in; tests green. Build 175.
Recent Accomplishments (31 August 2026 — one Makefile / gcc · clang · tcc)
- Single
Makefile—CC ?= gcc;CC_FAMILYfromclang/tcc/ else gcc (paths andclang-18/gcc-14included). - Flags: gcc keeps
-pedantic-errorsand-Wcast-align=strict; clang same minus the GCC-only align flag; tcc matches the oldMakefile.tccset (no pedantic/conversion;-Wswitch-enum). debug: gcc/clang-fsanitize=addresson compile and link (no-lasan); tcc-g -O0only.make tarno longer copiesMakefile.clang/Makefile.tcc. Those files moved toarchive/.- Switch compiler:
make cleanfirst sobuild/cobjects are not mixed. - Verification:
make test-allgreen on gcc, clang, and tcc.
make # gcc (default)
make clean && make CC=clang test-all
make clean && make CC=tcc test-allRecent
Accomplishments (28 August 2026 — 0.26.5.174 / #11 import-bind +
.mh widths)
Import as the one unit bind Done
- Named
.mhimport ofinteger/cardinal/real/stringis the unit bind (Language Report §5.5). Preludedecl == nil; second bind is an error. - Only
.mhTYPE exports. Include-only and foreign.himports do not skip the defaulttypedef.import integer as i64does not bindinteger. codegen_unit_binds_portablewalks.mhimport items (qualident, elseASalias). Pack.hsupplies the C ABI.- Tests:
test_import_rebind+fixtures/lp64(lean header);test3_import_rebind_second/test3_import_then_rebind.
.mh width spelling
Done
- Writer:
integer 32(andcardinal/real) on field, formal, and result type-spec. Name staysinteger;TType.widthis separate. - Reader:
type_width/result_width; optional decimal N before multi-word C names; closed N; two-digit cap (no signed overflow under-Wstrict-overflow=4). - Semantic: imported field/formal/result types keep the width.
- Tests:
test2_export_width/test2_import_width;test_import_width+fixtures/wpoint;test3_import_width(integer 99). - Still open (#11): arch packs; build-time defaults;
.mhalias RHS.
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)
- Exact C11 widths. Closed N: 8 / 16 / 32 /
64 (
real32 / 64). Decimal N only. TType.width;type_c_spelling→intN_t/uintN_t/float/double.type integer = integer 64is the Phase A unit bind with a width RHS.- Tests:
test_width,test_width_rebind,test3_width,test3_width_real.
Generated .h
owns the C prelude Done
codegen_emit_c_preludein the header (after the include guard): stdint/stdbool/assert,nil/NIL,byte, portable four unless this unit bound the name.- Unexported portable
TYPEbinds still appear in the.h. - Generated
.c#include "UnitName.h"; no second prelude.-Cwrites a companion.h. - Header always emits the unit prototype (PROGRAM and MODULE).
- PROGRAM/MODULE name must match the output stem
(
#include "Name.h"). tmodc.hremains optional for hand-written C..mhwidth spelling still deferred.
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
- Writer:
export type TFn complete function (integer) : integer(always(…)on the type line;procedurelikewise). Same physical@format 1line as field tails. - Reader:
is_func_type+ reusemh_parse_signatureaftercompletewhen the type is notstruct/union. - Semantic: synthetic
NODE_TYPE_DECL.method_type(NODE_METHOD_TYPE+ formals). Must assignmethod_type := mt(notnil). - Field call-through uses existing
semantic_method_type_node/ Policy A discard ((f())as a statement when the result is known). - Import both the method type and the owner struct
(
TFnandTBox). - Tests:
test2_export_fn_type/test2_import_fn_type((b.fn(1)));test3_import_fn_type(noTFnimport);test_import_fn_type+fixtures/fnbox.{mc,mh,h}(b.fn := twice;assert b.fn(21) == 42). - Verification:
make test-allon gcc, clang, and tcc. Promoted 0.26.4.172.
Recent
Accomplishments (25 August 2026 — 0.26.3.170 / .mh field
lists)
Identifiers ≤ 255 Done
- Lexer:
IDENT_MAX_LEN255; longer names areTOK_ERROR(identifier longer than 255 characters). parser_commonerror_atprintserror_msgforTOK_ERROR..mhmh_read_identsame bound. MangledOwner__namemay be 512 (not a source identifier).- Test:
tests/test3_ident_long.mc.
.mh reader whole-file
Done
mh_reader_load: file size →malloc(n+1)→ parse in place (no 4096fgetscap).MhModule.sourceowned untilmh_module_free. Layout/formal strings may point into that buffer.
Writer DynBuf prefixes Done
- Export lines (including
@module, type/enum/binding/unit entry, methodOwner__name) built onDynBuf.snprintf256 only for the short generated-by comment.
Field lists — writer / reader / import Done
export type Name complete struct (f: T { , … });union; optionalextends Parent.export type Name opaqueunchanged (EXTERN TYPE,type T = opaque).mh_type_opaque: no longer treatsstruct_body <> nilas opaque.- Reader:
MhFieldonMhExport; oldopaque/ barecompletestill legal. - Semantic: synthetic
NODE_TYPE_DECL+struct_bodyon import (arena-copied names). Unknown field on a complete imported struct is an error. Parent fields need the parent type imported (not flattened). - Tests:
test2_export_struct/test2_import_struct/test3_import_struct_field; union and EXTENDS pair;test_import_struct+fixtures/tpoint.{mc,mh,h}(compile + run). Writer.mhfortest2_*still generated with-M(not a Makefile golden). - Verification:
make test-allgreen. Method-type RHS Done (0.26.4).
Recent Accomplishments (24 August 2026 — 0.26.3.168 / parser self-host)
parser.c
→ parser_common.mc + parser_main.mc
Done
- Shared parser state and token helpers live in
parser_common:TParser/pParser, type-name registry,advance/check/match/consume/ EOS / comments / assignment / skip helpers /error_at/isEOF. parser_mainis the recursive-descent driver (TParser::init/parse/parse_expr/parse_stmt/ blocks / types).- Each common helper has two exports: old
advance(p: pParser)(still used bydeclaration/expression/statement) and newTParser::advance(ref p: TParser)(used byparser_mainonly). Migrate the other three units later. - Hand-authored
parser.c/parser.hreplaced.modcincludesparser_common.h+parser_main.h. - Verification:
make test-all, selfhost, bootstrap, promote green on gcc, clang, and tcc. Promoted 0.26.3.168.
Cyclic .mh
imports — noted, not designed
parser_mainimports parse entry points fromdeclaration/expression/statement; those units importTParser::parse_expr/parse_stmt/ … fromparser_main.- This is legal today because C headers can include
each other and
.mhis loaded from a prior generate. As.mhgrows (field lists, signatures), mutual TMod-c imports will get fragile — a problem almost every new module language hits. - Do not address until after item 15 (Makefile subdirectory compilation / module directories). Interim: keep extracting a common module rather than closing a cycle.
Recent Accomplishments (18 August 2026 — 0.26.1.158 / unknown types + no automatic stddef.h)
Unknown type names are errors Done (breaking)
semantic_resolve_type_inner: unbound single-word type name is fatal (unknown type).- Still legal: prelude builtins (
bool,int,integer,long, …); namedIMPORT/EXTERN TYPE;.mhopaques; multi-word C spellings (long long,unsigned int). Bareunsignedis not a type — writeunsigned intor a typedef. size_t,FILE,void, and compiler types (Node,Parser, …) must be listed onIMPORT(or declared). That import also emits the C#include.- Tests:
test3_undef_type.mc(var f: FILE). Compiler / test / example type import sweep.
Automatic
<stddef.h> dropped Done
- Generated prelude:
<stdint.h>,<stdbool.h>,<assert.h>only. #define nil ((void *)0)/#define NIL nil.byteremainsuint8_t.size_tis no longer free via the prelude;import size_t from "stddef.h"where used.
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)
semantic_resolve_call:sym == nilon a freename(...)orType::name(...)is fatal (undefined procedure or function/undefined type-bound method).- Still legal: same-unit
PROC/FUNC; namedIMPORT/EXTERN; 7a module-entry bind; method-typed locals (fp(...)); field call-through; prelude type names. - Include-only
IMPORT FROM sourcestill binds no names. QuotedFROM "hdr.h"does not parse the header. - C preprocessor is pass-through only.
#definedoes not create TMod-c symbols. A macro used from.mcbelongs in a real.hand on anIMPORT. - Not this bump: unknown type names
(
size_t,FILE) still soft-miss; automatic<stddef.h>stays. - Tests:
test3_undef_call.mc,test3_undef_method.mc;test_tmodc.mcuses a realTSTRINGfunction (no dummy import / same-file#define). Compilersrc/*.mcimport sweep so self-host stays legal. - Verification:
make test-all, selfhost, bootstrap, promote green on gcc, clang, and tcc. Promoted 0.26.0.156.
Recent Accomplishments (14 August 2026 — 0.25.4.154 / RECURSIVE + signed SIZEOF + lean prelude)
RECURSIVE
required on direct self-calls Done
- A call whose
resolved_sym.declis the enclosingNODE_PROC_DECL/NODE_FUNC_DECLis a direct self-call. The completing declaration (the one with the body) must haveRECURSIVE. - Field call-through (
resolved_symnil) and the unitNODE_PROGRAMbody are not treated as self-calls. Mutual recursion is not checked (later analyzer). - Tag belongs on the body decl after
FORWARDrefine (symtab_refine_symbolreplaces the symbol). - Sweep:
semantic.mc,ttype.mc,expression.mc, and other compiler.mcself-calls tagged. - Tests:
tests/test3_recursive.mc; positive:test_FactorialDemo/test_FibonacciDemo.
SIZEOF
is integer in C as well as in the type system
Done
- Semantic type was already
integer. Emit is now((integer)sizeof(...))incodegen_common_sizeof_expr(headers and-C). - Follows the unit’s
integertypedef (defaultint; rebind applies when that typedef is in scope). LENnot emitted yet — same type and cast when implemented.- Design lock (not implemented as a hard mix-ban yet): lengths /
indexes /
SIZEOF/LENare signed (integer);cardinalis for bits / wrap / C unsigned ABI;size_tstays an imported C name.
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 — Done
(0.26.0–0.26.1). Next: <stddef.h> /
require every non-builtin name.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
- Same-unit:
MODULEname is registered asPROC/FUNCafter pass 1;sym.declis a syntheticNODE_PROC_DECL/NODE_FUNC_DECLwhosePARAM_LISTaliasesprogram_decl.paramsso existing auto-&applies (test_module_ref(b, 1)needs no@). - Import: any named import from an
.mhalso binds the@moduleunit-entry export (skip if already in scope or no matching export; include-onlyimport from "x.mh"unchanged).PROGRAMnames are not bound. - Names:
.mhstrings are arena-copied insemantic_bind_mh_exportbeforemh_module_free(auto-bound constructor names must not dangle). - Callee ABI (same arc): module/program
emit_param_list(..., true)soVAR/REFformals lower toT*(Lexermodule Lexer(ref lexer: TLexer, …)). - Tests:
tests/test_module_ref.mc;tests/test_module_entry.mc+tests/fixtures/bumpint.mh/include/fixtures/bumpint.h(import TBumponly;bumpint(n)auto-bound + auto-&). make test green on gcc, clang, tcc. - Not 7b — no generated startup calls of imported module bodies. 7b cancelled 31 August 2026 (explicit 7a calls only).
Recent
Accomplishments (11 August 2026 — 0.25.3 / formal signatures +
cross-module auto-&)
Item 6a —
.mh formal signatures Done
- Writer (
codegen_mh): one-line@format 1tails —( [var|ref|const] type-spec { , … } ) [ : result ]; surface type names preferred (aliases likelong_long); multi-word C spellings only when written that way. - Reader (
mh_reader):MhFormal/has_signature/ result fields; multi-word type-spec (long long,unsigned int); free formals on unload. - Import (
semantic): syntheticNODE_PROC_DECL/NODE_FUNC_DECL+ param list from export (arena-copied strings);sym.declis the synthetic node so existing codegen auto-&applies cross-module. - Phase A (0.25.2) retained:
instance/staticOwner;import Type::name;is_method_instance;obj.methodacross modules. - Tests:
tests/test5_mh_method_import_string.mc(-a);tests/test4_string.mc+make string-lib(linklibtmod_string.a); auto-&onsb.free()/TStringBuffer::free(sb)without@. Not wired into defaultmake test(needsinclude/*.mh+ archive). - Then still deferred: field lists / complete struct
export; field call-through across modules; 7b (later
cancelled);
^Tinstance receivers. Field lists / call-through Done 0.26.3–0.26.4.
Recent Accomplishments (11 August 2026 — 0.25.2 / cross-module methods Phase A)
Cross-module
Type::method / obj.method Done (Phase
A)
.mhwriter (A1): type-bound exports emit optionalinstance Owner/static Ownerafter completeness (still@format 1)..mhreader (A2):MhExportstoresis_method,is_instance,method_owner/method_owner_len.- Import (A3):
import-itemmay beType::name(or mangledType__name); lookup mangled export; bind mangled name (orASalias); setTSymbol.is_method_instance. - Semantic (A4):
obj.method(...)treatssym.is_method_instancelike same-unit instance methods. - Module entries (
String(...),StringBuffer()):free-call soft-miss— 7a Done (12 August). - Superseded for formals by 0.25.3 (above).
Recent Accomplishments (7 August 2026 — 0.25.1 / callable fields)
Callable field call-through Done
obj.field(args)whenfieldhas a method type (TYPE T = PROCEDURE/FUNCTION …) → C(obj.field)(args); no auto-receiver (Oberon procedure variables).- Disambiguation: instance
Type::namevs method-typed field — if both apply, compile-time error (useType::name(obj, …)). - Locals / params:
fp(args)whenfpisVAR/PARAM/LET(orCONST) of method type. - AST / codegen:
call.callee_exprfor call-through; instance sugar still usesreceiver_exprprepend. - Semantic:
semantic_method_type_node,semantic_field_type_on,semantic_sym_is_method_value;semantic_resolve_callreclassifies dot-calls. - Tests:
tests/test_callable_field.mc,tests/test3_callable_field_ambig.mc(as applicable);tests/test_Math.mc— struct “object” with method-typed fields +Type::create/ module entry as factory (compile-time only; no vtables). - make test-all, selfhost / bootstrap / promote as verified by user; gcc / clang / tcc green.
- Still deferred: parent-chain method lookup;
^T/VARself auto-&on instance methods.
Recent Accomplishments (6 August 2026 — 0.25.0 / item 20)
Item 20 — VAR / REF / CONST formals Done (breaking)
- Only
VARmay use the bare formal name as LHS of:=/INC/DEC. REF: through-designator writes OK (p.x,a[i]); bare-name assign illegal (scalarREF n: integeris effectively read-only for updates).CONST: deep freeze — no write through the formal root (name, fields, indices).- Bare formals: no bare-name assign; still largely by-value in C (not full Oberon “default REF”).
- Codegen: non-pointer
VAR/REF→T*;REF ^T→ one*;VAR ^T→T**; call-site auto-&for by-ref value formals (Swap(x, y)). - Self-host: scratch mutation of non-
VARformals uses locals (arena/semantic/utils, etc.). - Tests:
test_var_ref,test_var_pointer,test_const_param,test3_var_ref*,test3_const_param*,test3_var_pointer*; make test-all, selfhost, bootstrap, promote green. - Soft spot: named open-array typedef as
REF/VARformal (prefer true open-array type-specifiers until alias chase). - Docs: Language Report §8.2;
docs/grok_report-20260806-2042.md.
Recent Accomplishments (6 August 2026 — 0.24.18 / #11 Phase A)
Item #11 Phase A — portable builtin unit rebind Done
- Only the four Wirth-family names may be bound once per
compilation unit via top-level
TYPE:integer,cardinal,real,string. - Unbound defaults in generated C:
int,unsigned int,float,const char *(portable names remain the typedef aliases; C names are not rebindable prelude slots). type_is_portable_rebindable; semantic first-bind refines prelude (decl == nil); second bind and rebind of fixed builtins (bool/byte/char/ C-ish prelude names) are errors.- Codegen skips the default
typedeffor a portable name when the unit supplies a completeTYPEbinding. - Tests:
tests/test_rebind.mc,tests/test3_rebind_second.mc,tests/test3_rebind_bool.mc; suite green. - Width forms Done (0.26.5). Import-as-bind
and
.mhwidth tails Done (0.26.5.174). Still open (same item #11): architecture packs (tmodc.lp64, …); compiler-build default selection; optional.mhalias RHS.
type Name FORWARD
(0.24.17.135) Done
- Incomplete type in-unit:
type TString forwardthen complete withtype TString = …. - Completes prior incomplete TYPE via symtab refine (same family as
proc postfix
FORWARD). - Codegen: incomplete tag/typedef as needed; method-type typedefs ordered after layout types where required for C.
- Tests:
tests/test_type_forward.mc,tests/test3_type_forward_dup.mc,tests/test3_type_forward_reforward.mc(as applicable).
Recent Accomplishments (3 August 2026 — 0.24.17 / item 21)
Item 21 —
obj.method + instance vs static Done
- Instance sugar:
obj.method(args)→Type__method(obj, args…)when static type ofobjisTypeand the method is an instance method. - Always available:
Type::method(args…)(Phase 1 since 0.23.9). - Instance vs static (first formal type only; formal
name free, Oberon-style):
- Instance: first formal’s type is the owner type →
Type::m(obj, …)andobj.m(…). - Static / factory: no formals, or first formal type
≠ owner →
Type::m(…)only (e.g.Point::new(x, y);p.new(…)is an error).
- Instance: first formal’s type is the owner type →
- Statement path: designator + postfix chain (calls,
.,[],^) sop.print()andb.topLeft().print()work as statements. - Optional
endtags:end,end name,end Type::name(parse_optional_end_taginparse_block). - Helper:
semantic_method_is_instance; codegen prependsreceiver_expr. - Tests:
tests/test_smoke.mc,tests/test3_smoke.mc(static via.fails); make test-all green on gcc, clang, tcc. Callable field call-through— Done (0.25.1). Still deferred: parent-chain method lookup;^T/VARself auto-&.
Recent Accomplishments (1 August 2026 — 0.24.16 / auto-upcast)
EXTENDS by-value auto-upcast Done
- Child (or further descendant) used where an ancestor is required → C
.base× N (option A); not a blind struct cast. Node.upcast_depth;semantic_extends_upcast_depth/semantic_maybe_upcast; sites: typed init,:=,RETURN(enclosing_func), same-unit call formals.- Codegen:
codegen_common_exprappends.baseafter the expression when depth > 0. - Multi-level verified (e.g.
Grand→Parent= two.basesteps). Tests:tests/test_extends.mc. - Deferred polish (1 August):
pointer/
REFupcast; aggregateas→.base;^Tparent fields (c5^.x). Closed 0.26.5.175. Oberonp.xauto-deref Closed 0.26.5.176.p[i]peel and instance method on^TClosed 0.26.5.178. Still later: parent-chain methods; cross-module formals (richer.mh); hard assignability errors. - Design lock: no compiler-inserted type tags /
vtables; programmer may add tags manually (enum+union style). No Oberon
ISwithout opt-in runtime identity later.
Recent Accomplishments (31 July 2026 — 0.24.16 / declaration self-host)
Self-host:
declaration.c → declaration.mc
Done
- Converted declaration parsing to
src/declaration.mc; generateddeclaration.c(and paired header /.mhas in the build). - Hand-authored
declaration.creplaced by compiler output from the.mcsource. - Conversion cleanup: stale comments removed; most obsolete receiver parse path dropped (type-qualified methods own that story).
- Version 0.24.16 (build 130); make test-all green on gcc, clang, and tcc.
Recent Accomplishments (29 July 2026 — 0.24.15 / 13b)
Item 13b — discard enforcement (Policy A) Done
- Bare
NODE_CALLasNODE_EXPR_STMT: ifsemantic_type_of_expryields a known result type → fatal; require(f())or use the value (x := f(), arg, …). - Unknown result (procedure, untyped foreign import
such as bare
printf) → bare call still allowed. - Explicit discard:
(expression)/(f())(NODE_PAREN) always allowed as a statement. - Tests:
tests/test_discard.mc,tests/test3_discard.mc; make test-all green on gcc, clang, and tcc. - Optional later: discard binding
_(item 24); thin wrapper procedures if an API later gains a known result and callers never care.
Recent Accomplishments (29 July 2026 — 0.24.14 / 21a)
Item 21a —
type_of_expr + simple init inference
Done
semantic_type_of_expr— thin expression typing (not full type-check / not Hindley–Milner).- Coverage: literals; designators; paren; cast; sizeof; call return
type; unary
-/not/~/@/^; binary arith / bitwise / logical / compare; real arith. - Init inference — when
:is omitted onVAR/LET/CONST, type from initializer; error if unknown. - Tests:
tests/test_infer.mc(and related); suite green. - Deferred polish: ternary
cond ? a : b(and array-literal) typing — item 21a-ternary (both arms must share one static type). - Unlocked:
13b discardDone (0.24.15); still open: EXTENDS auto-upcast, 21obj.method, 20VARformals.
Design (same period)
- Portable builtins Option A locked in Language Report §5.5 / §10.1 (not implemented).
Recent Accomplishments (28 July 2026 — 0.24.14)
Self-host: lexer.c
→ Lexer.mc Done
Self-host:
lexer.c → Lexer.mc Done
- Converted the full tokenizer to
src/Lexer.mc(moduleLexer); generatedLexer.c/Lexer.h/Lexer.mh. - Hand-written
lexer.c/lexer.hreplaced; capitalLexermodule name matches self-host naming for large units. - Exports include
TokenKindenum,TToken/TLexer,TLexer::init/TLexer::next,TokenKind::string,TToken::print. - Keyword table includes
OPAQUE(spelling fixed vs olderOPQAUEtypo note). - Version 0.24.14 (build 125); self-host / bootstrap path exercises the lexer as TMod-c source.
Related (same period — exploratory, not calm-path)
- Experimental
src/String.mc—TStringwrapper for const C strings; documents deferredtype … forward, callable fields, and futureobj.method/ builtinstringdirection. - Discussed: callable function-pointer fields vs
Type::method/ plannedobj.method(item 21 after 21a); neither call path fully enables vtable-style dispatch yet.
Recent Accomplishments (25 July 2026 — 0.24.13)
Item 13d —
STRUCT EXTENDS option A Done
- Oberon model: unique field names on the extension chain; flat
c.xin TMod-c source. - C option A: embed
Parent baseat offset 0; field rewrite viafield_access.base_depth→ emit.base× depth. - Synthetic
basefor explicit parent value (c.base); reserved only on types that useEXTENDS(plain structs may use a field namedbase). - Semantic:
semantic_find_field_depth,semantic_type_of_designator(designator-only), clash / base-must-be-struct checks. - Tests:
tests/test_extends.mc(multi-level +c.base);test3_extends_clash.mc;test3_extends_base_reserved.mc; existingtest2_extends.mc. - Auto-upcast child → parent still deferred (needs 21a).
Infrastructure — linked-chunk arena Done
- Replaced single-slab
reallocgrowth (ASan UAF when analyzing large units such assemantic.mcwith-a). ArenaChunklist: never relocate live slabs;arena_alloczeros returned bytes;callocfor new chunks;ARENA_MIN_SIZE= 1 MiB default.- Stress-tested with small min size (multi-chunk creates); production min restored to 1 MiB.
Recent Accomplishments (23 July 2026 — 0.24.12)
Item 13c — bare
UNION types Done
type Value = union … endon TYPE RHS (sibling ofSTRUCT).- Lexer
TOK_KEYWORD_UNION;struct_decl.is_union;parse_union_type; noEXTENDS/ noPACKEDin v1. - Semantic resolves field types; rejects
EXTENDSon unions. - Codegen:
codegen_common_union_decl→ Cunion(separate from struct emitter for consistency). - Nested use: define named type first, then field type = name (no anonymous nested unions yet).
- Tests:
tests/test_union.mc,tests/test3_union.mc(and related); full suite green on gcc, clang, tcc.
Item 13a —
OPAQUE types Done (0.24.11.x)
- End-to-end:
type T = opaque,^opaque,POINTER TO opaque; Ctypedef void *Name. - Bare
opaquein type-specifier rejected (test3_opaque_parse.mc). - Note: unknown type names still allowed as possible foreign C types (pre-existing policy).
Design discussion (future — not implemented)
- Language-level tagged unions / ADTs (constructors +
match/
is) explored as pseudocode; distinct from bareUNION. Manual pattern remains: enum tag + struct + union (as in compilerNode). - Embed of struct/union in another: name the nested type first, then use as field type.
Recent
Accomplishments (0.24.11 — expression.mc)
Self-host:
expression.c → expression.mc
- Converted
src/expression.mc; compiles; all tests run; promoted through 0.24.11.x builds.
Recent Accomplishments (18 July 2026 — design + self-host)
Self-host:
statement.c → statement.mc (0.24.10.110)
- Converted
src/statement.mc(paired.c/.h/.mhas needed). - Full rebuild, test suite, self-host, bootstrap, and promote — green at 0.24.10.110.
Design — no
user-facing void; OPAQUE types
- Prefer procedure vs function (no result type) over a void return type.
type T = opaque— named type with no language-visible layout (Wirth-style; Windows-style handles as user-chosen names).type address = ^opaque(orPOINTER TO opaque) — Cvoid *equivalent via user-defined alias, not a baked-invoid.OPAQUEonly on TYPE RHS (opaque-type-expression); not intype-specifier(var x: opaqueillegal — name first).- Distinct from
type T FORWARD(incomplete, completed later in-unit) and from.mhcompleteness flagexport type name opaque. - Reserved keyword
OPAQUEreplacesOBJECT(Language Report +syntax-ebnf.md).
Design — explicit discard of function results Implemented (0.24.15 / 13b Policy A)
- Grammar:
expr-statement = "(" expression ")"— intentional drop of a result. - Policy A: bare call as statement illegal when
result type is known; require
(f())or use the value. Unknown result / procedure → bare OK. - C source / generated C may use
(void) call(...); TMod-c source uses parentheses, not a cast-to-void type. - Item 24 (
_) still deferred — distinct sugar from(f()).
Grammar + lexer groundwork
docs/language-report.md+docs/syntax-ebnf.md— SSOT split (18 July 2026);OPAQUEin report + EBNF; formergrammar.mdarchived asgrammar_working_notes.md.TOK_KEYWORD_OPAQUE— keyword table now lives insrc/Lexer.mc(self-hosted 0.24.14); spelling isOPAQUE.
Prior same line (0.24.9)
symkind.h→symkind.mc,mh_exportkind.h→mh_exportkind.mc.
Recent Accomplishments (16 July 2026 — 0.24.8)
Named CONST in array
bounds
array[LIMIT] of Tandarray[LIMIT+1] of TwhenLIMITis a compile-time integerCONST(and general integer const-exprs).TType.size_expr— parser stores unevaluated bound; semantic folds toarray_sizein place before codegen (char l[100], not openl[]).type_create_array_expr; parser paths forarray[…] of Tand suffixT[…].
Integer const-eval (shared)
semantic_try_eval_const_expr— soft fold; optionalmsgout-parameter for distinct errors;nilmsg for quiet non-integerCONST.semantic_eval_const_expr— thin fatal wrapper over try (single implementation).CONSTregistration —has_const_valueonly when integer fold succeeds; string/pointerCONST(e.g.const c2: ^char = "bye") unchanged.TOK_MOD/TOK_KEYWORD_MODboth accepted in const-exprs.- Review fixes: fallback error message when hard eval fails without
msg;
semantic_register_var_declerror string.
Release process
- Version 0.24.8.104; rebuilt, tested, self-hosted, bootstrapped, and promoted.
Recent Accomplishments (15 July 2026 — 0.24.7)
ENUM Phase C
MH_KIND_ENUMinmh_exportkind.h;.mhwriter emitsexport enum Type completeplusexport const Member completelines per member.mh_readerparsesexport enum; maps toSYM_KIND_TYPE; cross-module enum import via explicit item list.- Tests:
tests/test_mh_enum_export.mc,tests/test2_mh_enum_import.mc,tests/test_mh_enum_import.mc; fixturestests/fixtures/colors.{mh,h}.
.mh negative import
tests
- Tier-3
test3_*convention: eachtests/test3_*.mcruns throughmodc -a; non-zero exit = pass.
Test include paths (Makefile)
INCLUDE_DIR(include/) withinclude/fixtures→tests/fixtures/symlink;CFLAGSadds-I$(SRC_DIR) -I$(INCLUDE_DIR) -I$(LIB_DIR)so generated#include "fixtures/…"and experimentaltmodc.hresolve in tier-1 host C builds. Test-harness aid — not a substitute for item 15 (subdir compilation). Host compiler isCC(default gcc;CC=clang/CC=tcc).
Design — WHILE … BY
not planned
- Iteration step at loop head via
defer(seetests/test_defer.mc); documented indocs/grammar.md.
Recent Accomplishments (14 July 2026 — 0.24.6)
ENUM Phase A/B
TYPE name = ENUM … END— parse (parse_enum_type), semantic (semantic_register_enum_type,semantic_eval_const_expr), codegen (codegen_common_enum_type→ Ctypedef enum).TSymbol.const_valuefor enum member integers; duplicate-member error.- Tests:
tests/test2_enum_parse.mc,tests/test_enum.mc,tests/test3_enum_dup.mc. - Phase C completed in 0.24.7 (see above).
tmodc ABI prelude
(planned)
- Experimental
src/tmodc.hfor hand-written C including generated headers. - Target:
tmodc.mc→tmodc.hsystem module (width types,nil); multi-TU#includeinstead of inlined prelude.
TMod-c rebrand (documentation)
- Public project/language name: TMod-c (TYPE
compiler; Pascal
Tprefix alignment). - Target compiler binary:
tmodc; Mod-c /modcretained as legacy aliases during transition. - Docs:
docs/grammar.md,CURRENT.md,changelog.md,AGENTS.md,docs/grok_report-20260714-1939.md; appenddocs/project_bible.md.
Recent Accomplishments (13 July 2026 — 0.24.5)
Qualident
IMPORT … FROM
import-source = string-literal | qualident— parser, semantic, and codegen.- Unquoted qualident names a Mod-c module: dots →
slashes,
.mhfor symtab, paired.hfor#include. - Quoted string unchanged for foreign/C and explicit
"path.mh"paths. - Path resolution: relative to compiling
.mcfile directory (project-rootsrc/search paths still deferred). mh_reader:mh_qualident_to_mh_relpath,mh_format_h_include; updatedmh_path_is_mh,mh_resolve_import_path.- Tests:
tests/test2_mh_import_qual.mc(qualident form offixtures.minimod). docs/grammar.mdupdated (0.24.5).
Recent Accomplishments (11 July 2026 — 0.24.4)
codegen_header.mc
(self-host)
src/codegen_header.mc— converted from.c; behaviour unchanged (minor release 0.24.4, not 0.25).
Recent Accomplishments (9–10 July 2026 — 0.24.3)
Import sources — documented (phase 1 vs phase 2)
IMPORT FROM "path"— include-only form in grammar (optional empty item list); notIMPORT *.- Two worlds: quoted string = foreign/C; unquoted
qualident = Mod-c module (
utils.dynbuf→utils/dynbuf.mh+#include "utils/dynbuf.h"). QualidentFROMimplemented 0.24.5. - Quoted paths still valid for foreign/C and explicit
"codegen_header.mh"spelling. - Still deferred: project-
src/-root paths,import * from M.Nbulk.mhimport; blocked until subdirectory compilation in Makefiles. - Policy: paths and identifiers
case-sensitive; generated C
#includes.honly, never.mh. docs/grammar.md— full Phase 1 / Phase 2 import section.
EOS / layout (expressions, statements, RETURN)
parse_unary—skip_layout_breaksat entry; trailing operators (or,and,+, …) may continue on the next line.consume— callsskip_layout_breaksbefore matching;matchunchanged (EOS /matchEOSmust seeNEWLINEas-is).RETURN— newline after barereturnends the statement; multiline return values use(...). No layout skip before optional expression (avoids swallowing the next statement).- Unreachable code — statements after
RETURN/BREAK/CONTINUEin the same sequence → fatal error (was warning); dead nodes still excluded from AST. - Tests:
tests/test_layout.mc(tier-1 smoke);tests/test3_loop.mc(tier-3: unreachable afterbreak/continue).
Prior — 0.24.3 (9 July 2026)
Builtin integer
/ cardinal lowering
integerlowers to Cint;cardinaltounsigned int(Oberon-like everyday types on typical LP64 targets — not pointer-sized).- Changed in
codegen_cprelude typedefs; verified withmake test-allon gcc, clang, and tcc (no new errors/warnings). printf:%d/%umatch Mod-cinteger/cardinalon LP64. Forsize_tor pointer-sized values, use C imports or future width-qualified types.docs/grammar.mdupdated (0.24.3): builtin policy, generated width typedefs (int8…uint64), EOS rules.
Parser / layout (9 July — import/decl)
- End-of-statement rules documented;
IMPORT … FROManchor layout;skip_layout_breaksfor multi-line import/declaration lists. tests/test_import_layout.mc— multi-lineimport/varlayout smoke test.
Prior — 0.24.2 infrastructure (9 July 2026)
Three-tier test targets (gcc / clang / tcc)
test—test_*: modc compile → host C compile → run; stdout to/dev/null; summaryN run, M failed; includestest_Pidiff check.test2—test2_*:modc -asemantic pass expected; counted summary.test3—test3_*: negative tests — non-zero exit = pass; counted summary.test-all— runs all three tiers;distdepends ontest-all.- Then (0.24.2): three files (
Makefile,Makefile.clang,Makefile.tcc). Now (31 August 2026): oneMakefile,CC=gcc|clang|tcc; old files inarchive/.
Negative test fixtures
(test3_*)
tests/test3_dup.mc— duplicate declarationtests/test3_undef.mc— undefined identifiertests/test3_for_assign.mc— invalidforassignmenttests/test3_let_over_var.mc—letovervarconflicttests/test3_loop.mc— unreachable code afterbreak/continue
Version / build numbering
make version— manual only; incrementssrc/build.numberand regeneratessrc/version.h.BUILD_NUMBERstored insrc/build.number(survivesmake clean, which removesbin/andbuild/).- Modc displays
0.24.12 (118)style (release stem + build in parentheses); generated headers useVERSION_BASEonly.
Project housekeeping
AGENTS.mdrefreshed at repo root (canonical agent instructions); duplicate.grok/AGENTS.mdremoved.
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.
- Writer:
src/codegen_mh.mc—TARGET_MH,-M, auto-emit with-C. - Reader:
src/mh_reader.mc— parsemodc-mh/1;semantic_register_importloads real symbol kinds from.mh. - Codegen:
codegen_common_import—.mhimports emit#include "…h". - Semantic fix:
NODE_IMPORT_ITEMbranch insemantic_resolve_type_innerfor.mhtype imports. - Module entry:
mh_emit_unit_entry()emitsmoduleproc/func in.mhexport table. - Tests:
test_mh_export.mc,test2_mh_import.mc,fixtures/minimod.{mh,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:
.mh/.hsplit —.mhfor modc semantics (export table);.hfor C ABI (#includein generated C). Same stem/path layout rule.- Import sources — quoted
"stdio.h"/"symbols/foo.h"= foreign; unquoted qualident (symtab,fixtures.minimod,codegen.codegen_header) = Mod-c module (0.24.5). Resolution relative to compiling unit directory; project-rootsrc/search paths deferred.import from "…"/import from M.N= include-only, no symtab.import * from …= bulk.mhimport (deferred). EXTERN— prefix only; never a body in this unit; refinesIMPORT.FORWARD— postfix on proc/func;type ident FORWARDincomplete types Done (0.24.17.135) (complete later in the same unit).- Blocks —
extern … end/forward … enddeferred until.mhshape stabilizes. CONSTdeclarations — compile-time named constants (Pascal/Oberon); not C read-only objects.LET— runtime immutable binding. ParameterCONST— deep read-only qualifier, not compile-timeCONST.CONSTcodegen (today vs intent) — still lowers to Cstatic constobjects; intent isenum/#define/ literal fold (item 19). Integer values now fold for array bounds viahas_const_value(0.24.8).- No user-facing
void—OPAQUEimplemented (13a): TYPE RHS only; user aliases; Ctypedef void *Name; procedures have no result type. - Discard (13b Policy A — Done 0.24.15) —
(expression)as statement; bare call only when result type unknown; known results require(f())or use. C may lower with(void). OPAQUEvs.mhopaque— source type constructor vs export completeness flag (same word, different grammars).STRUCT EXTENDS— Oberon-shaped record layout (single base at offset 0, unique field names, flatc.xin source); C lowering option A (Parent base;, emitc.base.xfor parent fields). Syntheticbasereserved only on EXTENDS types. Not class/vtable; no hidden RTTI. See Language Report §5.4.0. 13d Done (0.24.13); by-value auto-upcast Done (0.24.16);p^.x/as→.base/ pointer·REFupcast Done (0.26.5.175); Oberonp.xauto-deref Done (0.26.5.176);p[i]peel + instance on^TDone (0.26.5.178);Type::m(p)peel Done (0.26.5.179). Still open: parent-chain methods.type_of_expr/ init inference (21a) — Done (0.24.14). Ternary/? :typing deferred (21a-ternary).- Bare
UNION— C overlapping members;codegen_common_union_decl; no EXTENDS; not language-level tagged unions. Embed nested aggregates by naming a type first, then using it as a field type. - Arena — linked chunks (pointer-stable); no
whole-buffer
reallocof live AST/symtab storage. - Portable builtins (Option A — Phase A Done 0.24.18; widths
Done 0.26.5; import-bind /
.mhwidths Done 0.26.5.174) — Onlyinteger,cardinal,real,stringmay be bound once per compilation unit via top-levelTYPEor a named.mhimport of that name. Unbound → defaultsint/unsigned int/float/const char *. Width formsinteger N/cardinal N/real Nare exact, RHS-only constructors (closed N);.mhtype-spec may carry the same tail. Still open: arch packs; build-time defaults. Not C rank. See Language Report §5.5 / §10.1. RECURSIVE(0.25.4) — required on a direct self-call (same PROC/FUNC node asenclosing_func). Review/lint flag for JPL rule 1; mutual recursion not checked.SIZEOF(0.25.4) — TMod-c typeinteger; C emit((integer)sizeof(...)). Not Csize_t.- Generated C prelude (0.26.1 / 0.26.5) —
<stdint.h><stdbool.h><assert.h>only;byte=uint8_t;#define nil ((void *)0)/#define NIL nil. No automatic<stddef.h>. 0.26.5: prelude and unit prototype live in the generated.h;.cincludes"Unit.h";-Cwrites a companion.h. - Name soft-miss — closed. Calls 0.26.0; types 0.26.1.
- Cyclic TMod-c
IMPORT(later) — known from parser split (0.26.3). Address after item 15. See Language Report §3.2. - Identifiers ≤ 255 (0.26.3.170) — lexer /
.mherror if longer. MangledOwner__namemay be 512. See Language Report §2.2. .mhtype layouts (0.26.3.170 / 0.26.4 / 0.26.5.174) — one physical line; field tail oncomplete struct/union/extends; method-typecomplete function|procedure ( … ) [ : T ]; type-spec may beinteger N/cardinal N/real N; whole-file reader;DynBufwriter; synthetic struct /NODE_METHOD_TYPEon import. See Language Report §3.2.
TODO / Next Actions
IMPORT / EXPORT / .mh
polish
Items 1–4 semantics phase 2 core.Done (0.23.3–0.23.5)Item 5 —Done (0.23.7)sizeof(UserType)at parse time.Item 6 —Done (0.23.7)EXTERN TYPE | VAR | PROCEDURE | FUNCTION.Item 7 —Done (0.24.0).mhwriter onEXPORT.Item 8 —Done (0.24.0).mhreader onIMPORT … FROM "*.mh"..mhcompleteness / signature richness; method export coverage.Negative import tests.Done (0.24.7) —test3_*tier.Method instance/static +— Done (0.25.2).import Type::name+ cross-moduleobj.method(Phase A)Formal signatures + cross-module auto-— Done (0.25.3). 6a.&(6a)— Done (0.25.3)..mhformal signaturesType field lists / cross-module— Done (0.26.3.170).obj.fieldMethod-type RHS / field call-through— Done (0.26.4.172) —complete function|procedure ( … ) [ : T ]; syntheticmethod_type; import the method type name as well as the struct.QualidentDone (0.24.5) — project-root path resolution (after Makefile subdirs);FROM.IMPORT *bulk import;IMPORT … AS …remain. 7a.Module entry as real import symbol— Done (12 August 2026 / 0.25.3.150) — same-unitMODULEname + importer auto-bind of@moduleexport; synthetic proc + formals; arena-copied names; moduleVAR/REFABI. Teststest_module_ref/test_module_entry. 7b.Module startup initialization— Cancelled (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)
FORWARD … END/EXTERN … ENDdeclaration blocks.— Done (0.24.17.135) — incomplete types completed later in-unit.type ident FORWARDLEN— resolution done; codegen TBD (same signedintegertype asSIZEOFwhen emitted).— Done (0.25.4) —SIZEOFC type((integer)sizeof(...)). 10b.— Done (0.25.4) —RECURSIVEon direct self-calltest3_recursive; mutual recursion later.Unit binding of bare— Done (0.24.18).integer/cardinal/real/string(Phase ATYPE)Width forms— Done (0.26.5).integer N/cardinal N/real NImport as the one bindDone (0.26.5.174).Done (0.26.5.174). Still open: arch.mhwidth spellingtmodc.*packs; build-time default selection; optional.mhalias RHS.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.Named constants in array bounds— Done (0.24.8) —array[LIMIT]/array[LIMIT+1]; integerCONSTfold; stringCONSTexcluded from fold. 13a.— Done (0.24.11) — TYPE RHSOPAQUEtypesopaque/^opaque/POINTER TO opaque; codegenvoid *; tests incl. negative bareopaque. 13b.Enforce discard form (Policy A)— Done (0.24.15) — known result →(f())or use; unknown/procedure bare OK; teststest_discard/test3_discard; gcc/clang/tcc green. 13c.— Done (0.24.12) — bare CUNIONtypesunion;is_union+codegen_common_union_decl; teststest_union/test3_union; gcc/clang/tcc green. 13d.— Done (0.24.13) — clashes;STRUCT EXTENDS(Oberon layout / option A)base_depthrewrite; syntheticbase(reserved only on EXTENDS); teststest_extends/test3_extends_*.By-value auto-upcast— Done (0.24.16) —upcast_depth; init / assign / return / same-unit call args; C.base× N.Polish:— Done (0.26.5.175).p^.x,as→.base, pointer/REFupcastOberon— Done (0.26.5.176).p.xauto-deref— Done (0.26.5.178).p[i]peel + instance on^T— Done (0.26.5.179). Still open: parent-chain methods.Type::m(p)peel
Infrastructure
MakefileDone (0.24.2)test3target — negative semantic tests.- Makefile subdirectory compilation —
src/tree →build/; prerequisite for project-root module search paths. 15a. CyclicIMPORTpolicy — after 15. Candidates later: extract-common (current), interface/implementation split, cycle ban, or interface-only first pass. Not a 0.26.x language change. - Codegen:
@vsasprecedence. - Codegen: struct forward-declare / deferred
p*typedefs. - FOR end temp type from expression types.
- Compile-time
CONSTcodegen — still Cstatic constobjects; intent#define/enum/ literal fold at use sites. (Integer value fold for bounds done 0.24.8.) — Done (0.25.0) — codegen + semantic modes; call-site auto-VAR/REF/CONSTformals&; breaking non-VAR bare-name assign. Soft: named array-alias formals. 20b.Callable field call-through— Done (0.25.1) — method-typed fields / values; Oberon no auto-self; ambiguity with instance methods;test_callable_field/test_Math.Instance methods phase 2— Done (0.24.17) —obj.method/ chains / statements; instance vs static by first formal type;test_smoke/test3_smoke; gcc/clang/tcc green. 21a.— Done (0.24.14) —type_of_expr+ simple init inferencesemantic_type_of_expr; init when:omitted; teststest_infer.mc; suite green. 21a-ternary. Ternary polish (later) — typecond ? a : bwhen both arms share one static type (and optionally array-literal inits); not required for 21a core.
Deferred
Type guard selectors (— dropped (31 August 2026). Range expressions still deferred.IS)INunused as an operator; reserved.- Stdlib
BitSet;SET OFunlikely. Borrowed-buffer /init_atAPI when stdlib is designed (notmalloc-only). - Discard binding
_(optional sugar; distinct from(f())statement discard). - Optional
BOUNDonWHILE/REPEAT/LOOP— plan. - Drop keyword
IS— plan.
Strategic Direction
- TMod-c rebrand (in progress) — documentation and
user-facing naming move to TMod-c /
tmodcfirst; code and build artifacts keepmodcaliases until deliberate cutover.tmodcsystem module (planned): width types and shared C ABI intmodc.mc→tmodc.h; multi-TU generated C#includestmodc.h. Language builtins stay in semantic prelude for now. Experimentalsrc/tmodc.hexists for hand-written C that includes generated headers. - Self-host with
.mhimports — convert remainingsrc/*.c→.mc(recent:parser_common/parser_main,declaration,Lexer,expression,statement,codegen_header,symkind,mh_exportkind, …); keep full chain green undermake test-all. - Polish
.mhlinking — 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).7bCancelled (explicit module-entry calls only). - Declaration blocks —
forward/externgroups once.mhexport shape is stable. Expression types / init inference (21a)Done.Discard (13b Policy A)Done.Instance methods (21)Done.Done (0.25.0).VARformals (20)Callable fieldsDone (0.25.1).Cross-module method Phase ADone (0.25.2).Formal signatures / cross-module auto-Done (0.25.3).&Module-entry bind (7a)Done (12 August).Done (0.25.4).RECURSIVE+ signedSIZEOF+ lean preludeFree-call soft-missDone (0.26.0).Unknown types + dropDone (0.26.1).stddef.hParser self-host (Done (0.26.3).parser_common/parser_main)Done (0.26.3.170)..mhfield listsMethod-type RHS / field call-throughDone (0.26.4.172).Width forms +Done (0.26.5.173)..hprelude#11 import-bind +Done (0.26.5.174)..mhwidthsEXTENDS polish (Done (0.26.5.175).p^.x/as/ pointer·REF)OberonDone (0.26.5.176).p.xauto-derefDone (0.26.5.178).p[i]peel + instance on^TDone (0.26.5.179). Remaining on this stem:Type::m(p)peelCONSTcodegen; #11 arch packs / build-time defaults; parent-chain methods.…OPAQUE(13a)0.26.5.179Done. Next: #11 arch packs; 21a-ternary later. CyclicType::m(p)peelIMPORTafter item 15. Later (not 0.26.x): loop-localFOR; optionalBOUND; dropIS;SET OFenum.
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
- Latest (4 September 2026 / 0.26.5.179 /
Type::m(p)peel):docs/grok_report-20260904-type-m-peel.md - Prior (4 September 2026 / 0.26.5.178 /
p[i]+ instance on^T):docs/grok_report-20260904-ptr-index-method.md - Prior (3 September 2026 / 0.26.5.176 / Oberon
p.xauto-deref):docs/grok_report-20260903-auto-deref.md - Prior (2 September 2026 / 0.26.5.175 / EXTENDS
polish):
docs/grok_report-20260902-extends-polish.md - Prior (28 August 2026 / 0.26.5.174 / #11 import-bind +
.mhwidths):docs/grok_report-20260828-import-bind.md - Prior (27 August 2026 / 0.26.5.173 / width forms +
.hprelude):docs/grok_report-20260827-1548.md - Prior (26 August 2026 / 0.26.4.172 / method-type
.mhRHS):docs/grok_report-20260826-2130.md - Prior (25 August 2026 / 0.26.3.170 /
.mhfield lists):docs/grok_report-20260825-mh-field-lists.md - Prior (24 August 2026 / 0.26.3 / parser self-host):
docs/grok_report-20260824-parser-split.md - Prior (18 August 2026 / 0.26.0 / free-call
soft-miss):
docs/grok_report-20260818-1311.md - Prior (14 August 2026 / 0.25.4 / RECURSIVE + SIZEOF +
prelude):
docs/grok_report-20260814-1645.md - Prior (11 August 2026 / 0.25.3 / formals + cross-module
methods):
docs/grok_report-20260811-2216.md - Prior (6 August 2026 / 0.25.0 / item 20):
docs/grok_report-20260806-2042.md - Prior (3 August 2026 / 0.24.17 / item 21 methods):
docs/grok_report-20260803-2318.md - Prior (1 August 2026 / 0.24.16 / declaration +
auto-upcast):
docs/grok_report-080126-2008.md - Prior status (31 July 2026 /
declaration.mc): this file;changelog.md - Prior session report (30 July 2026 / 0.24.15 / 21a + 13b
Policy A):
docs/grok_report-20260730-1800.md - Prior (28 July 2026 / 0.24.14 Lexer):
docs/grok_report-20260728-2052.md - Prior (25 July 2026 / 0.24.13 arena + EXTENDS 13d):
docs/grok_report-20260725-2251.md - Prior (23 July 2026 / 0.24.12 OPAQUE + UNION):
docs/grok_report-20260723-2250.md - Prior (18 July 2026 /
statement.mc+OPAQUEdesign):docs/grok_report-20260718-1906.md - Prior (0.24.10 /
statement.mcself-host): this file; build 110 - Prior (0.24.9 /
symkind+mh_exportkind.mc): changelog - Prior (0.24.8 / CONST array bounds):
docs/grok_report-20260716-2236.md - Prior (0.24.7 / ENUM Phase C):
docs/grok_report-20260715-2248.md - Prior (0.24.6 / ENUM + TMod-c rebrand):
docs/grok_report-20260714-1939.md - Prior (0.24.5 / qualident FROM):
docs/grok_report-20260713-1200.md - Prior (0.24.4 / self-host):
docs/grok_report-20260711-1911.md - Prior (0.24.3 layout):
docs/grok_report-20260710-1200.md - Prior (0.24.3 builtins/infra):
docs/grok_report-20260709-2338.md - Prior (0.24.2 infra): pending
docs/grok_report-*.md - Prior (0.24.0):
docs/grok_report-20260707.1439.md - Prior (0.23.9):
docs/grok_report-20260704-2239.md - Prior (0.23.7 → 0.23.8):
docs/grok_report-20260703-2321.md - Language report:
docs/language-report.md(hyphen; notlanguage_report.md) - Complete EBNF:
docs/syntax-ebnf.md(hyphen; notsyntax.ebnf.md) - Grammar redirect:
docs/grammar.md→ report + syntax; archivedocs/grammar_working_notes.md - Long-term knowledge:
docs/project_bible.md - Agent instructions:
AGENTS.md
Prior Releases (summary)
- 0.26.5.179:
Type::m(p)peel whenpis^Owner; do not peel@x. make test-all / selfhost / bootstrap / promote on gcc, clang, tcc. Date 4 September 2026. - 0.26.5.178:
p[i]peel (not^char[]) + instance method on^T; caret(*(expr))forp^[i].Type::m(p)closed in 179. make test-all / selfhost / bootstrap on gcc, clang, tcc. Date 4 September 2026. - 0.26.5.177: Light refactor;
examples/Shapes.mc. Date 4 September 2026. - 0.26.5.176: Oberon
p.xauto-deref —field_access.auto_deref; C(*(p)).field.p[i]/ instance on^Tclosed in 178. make test-all / selfhost / bootstrap on gcc, clang, tcc. Date 3 September 2026. - 0.26.5.175: EXTENDS polish —
p^.xparent fields; aggregateas→.base; pointer/REFupcast (upcast_ptr). Field auto-deref closed in 176. Tests green. Date 2 September 2026. - 0.26.5.174: #11 import as the one unit bind;
.mhwidth tails on fields/formals/results. Tests green. Date 28 August 2026. 31 August: oneMakefile(CC=gcc|clang|tcc);Makefile.clang/Makefile.tcc→archive/;test-allgreen on all three. - 0.26.5.173: Width forms + generated
.hprelude;-Ccompanion header. make test-all / promote on gcc, clang, tcc. Date 27 August 2026. - 0.26.4.172: Method-type
.mhRHS; cross-module field call-through; field lists from 0.26.3.170. make test-all / promote on gcc, clang, tcc. Date 26 August 2026. - 0.26.3.170:
.mhstruct/union field lists; ident ≤ 255; whole-file.mhreader; DynBuf export lines; synthetic layout on import. make test-all green. Date 25 August 2026. - 0.26.3.168:
parser.c→parser_common.mc+parser_main.mc; dualpParser/TParser::helpers; cyclic.mhIMPORTnoted (after item 15). make test-all / selfhost / bootstrap / promote on gcc, clang, tcc. Date 24 August 2026. - 0.26.1.158: Unknown type names closed; automatic
<stddef.h>dropped;nilis((void *)0). Date 18 August 2026. - 0.26.0.156: Free-call soft-miss closed. Date 18 August 2026.
- 0.25.4.154:
RECURSIVErequired on direct self-calls;SIZEOFemits((integer)sizeof(...)); lean C prelude (stddef/stdint/stdbool/assert;byte=uint8_t; no autostdlib.h). make test-all / selfhost / bootstrap on gcc, clang, tcc. Date 14 August 2026. Closes branchmod-c_0.25. - 0.25.3.150: 7a module-entry bind —
same-unit + importer auto-bind; arena-copied
.mhnames; moduleVAR/REFABI;test_module_ref/test_module_entry; gcc / clang / tcc. Date 12 August 2026. - 0.25.3.149:
.mhformal signatures (6a) — one-line formals + result; multi-word type-spec; synthetic proc on import; cross-moduleVAR/REFauto-&;test4/test5+ string lib; build 149. Date 11 August 2026. - 0.25.2: Cross-module method Phase
A —
.mhinstance/staticOwner;import Type::name;is_method_instance;obj.methodacross modules; string lib Makefile; build 146. Date 11 August 2026. - 0.25.1: Callable field
call-through — method-typed fields/values; Oberon no auto-self;
ambiguity with instance methods;
test_callable_field/test_Math. Date 7 August 2026. - 0.25.0: Item 20 VAR/REF/CONST
formals (breaking); call-site auto-
&; non-VAR bare-name assign illegal. Date 6 August 2026. - 0.24.17: Item 21 —
obj.method/ statement chains; instance vs static by first formal type; factoriesType::new(...); optionalend Type::name;test_smoke/test3_smoke; build 134; test-all on gcc, clang, tcc. Date 3 August 2026. - 0.24.16:
declaration.mcself-host (31 July) + EXTENDS by-value auto-upcast (1 August) —upcast_depth/.base× N; no hidden RTTI; build 130; test-all on gcc, clang, tcc. - 0.24.15: Discard enforcement (13b Policy
A) — known call result requires
(f())or use; unknown/procedure bare OK;test_discard/test3_discard; test-all on gcc, clang, tcc; build 128. Date 29 July 2026. - 0.24.14: Lexer.mc self-host;
type_of_expr/ init inference (21a); builds 125–126. Date 28–29 July 2026. - 0.24.13: Linked-chunk arena
(pointer-stable growth);
STRUCT EXTENDSoption A (13d) — clashes,base_depth, syntheticbasereserved only on EXTENDS; teststest_extends/test3_extends_*; build 121. Date 25 July 2026. - 0.24.12: Bare
UNIONtypes (13c);codegen_common_union_decl; promote build 118; test-all on gcc, clang, tcc. Date 23 July 2026. - 0.24.11:
expression.mcself-host;OPAQUEtypes (13a); builds through 115–116. - 0.24.10 + design (18 July):
statement.mc;OPAQUEdesign; language SSOT; discard plan. - 0.24.10:
statement.c→statement.mc; build 110. - 0.24.9:
symkind.h→symkind.mc;mh_exportkind.h→mh_exportkind.mc(build 106). - 0.24.8: Named
CONSTin array bounds;size_expr+ const-eval try/hard split; integerhas_const_valueonCONST; stringCONSTsafe; self-host/bootstrap/promote. Date 16 July 2026. - 0.24.7: ENUM Phase C (
.mhexport enum, cross-module);.mhnegative import tests; testINCLUDE_DIR/-Ipaths (gcc Makefile);WHILE … BYdropped (usedefer). Date 15 July 2026. - 0.24.6: ENUM Phase A/B (parse, semantic, codegen);
tmodc.hprelude experiment; TMod-c rebrand documentation. Date 14 July 2026. - 0.24.5: Qualident
IMPORT … FROM(parser, semantic, codegen,mh_readerhelpers);test2_mh_import_qual.mc. Date 13 July 2026. - 0.24.4:
codegen_header.mcself-host step (patch/minor; no API break). Date 11 July 2026. - 0.24.3: Builtin
integer→int,cardinal→unsigned int; EOS layout; import sources documented (phase 1 strings, phase 2 qualidents);test_layout.mc,test3_loop.mc,IMPORT FROMinclude-only. Dates 9–10 July 2026. - 0.24.2: Three-tier test targets
(
test/test2/test3/test-all) in three Makefiles; fourtest3_*negative fixtures; manualmake version;src/build.numbersurvivesmake clean;AGENTS.mdrefresh. Date 9 July 2026. (Host compilers later unified into oneMakefile+CC=.) - 0.24.0:
.mhwriter (codegen_mh,-M, auto-emit with-C);.mhreader (mh_reader);.mh→.h#includemapping;mh_exportkind.h;pcchar; if-body scoping fix;test_mh_export.mc,test2_mh_import.mc,fixtures/minimod.{mh,h}. Date 7 July 2026. - 0.23.9: Phase 1
Type::methodstatic calls; removedobj:methodsugar. Date 4 July 2026. - 0.23.8: Postfix
FORWARDon proc/func; mutual recursion. Date 3 July 2026. - 0.23.7: Item 5
sizeofregistry; item 6EXTERN; tagMOD-C_0.23.7. Date 3 July 2026. - Older:
docs/grok_report-*.md.