TMod-c Change Log
Rebrand (July 2026): Public name TMod-c; legacy Mod-c during transition. Compiler binary target:
tmodc(modcalias retained).
Version 0.26.5.179
Type::m(p)peel (§8.3) — qualified instance call peels the first actual when it is^Owner(same C asp.m()).Point::print(pp)→Point__print((*pp));REFPoint::scale(pp, n)→Point__scale(&(*pp), n).- Do not peel
@:TLexer::next(@p.lexer)stays&(p.lexer).(*&x)was passing a struct by value (broke selfhostTParser::advance). - Do not peel
pp^: actual is alreadyPoint(one caret wrap). - Placement: after args are resolved; only when
receiver_expr == nil(must not clearpp.getX()’s flag;argcis 0 on that form). Field call-through still clearsauto_deref. - Tests:
tests/test_smoke.mc(Point::print(pp)/Point::scale(pp, 3)/Point::getX(pp)). SelfhostTLexer::next(@p.lexer). - Still deferred (same item): parent-chain method
lookup; first formal
^Owneras instance. - Tests green. make test-all /
selfhost / bootstrap /
promote green on gcc,
clang, and tcc. Build
179. Branch
mod-c_0.26. Promoted 0.26.5.179. - Docs:
CURRENT.md,changelog.md,README.md, Language Report §8.3,docs/grok_report-20260904-type-m-peel.md.
Version 0.26.5.178
- Oberon
p[i]peel and instance method on^T(§5.3 / §8.3) — remaining auto-deref after field.(176). One implied peel per[]or per instance.method. AST flags only; no inserted caret. Explicitp^[i]/p^.methodunchanged. p[i]— peel iff pointer-to-array (^array[N] of Tor^NamewhereNameis an array typedef). Do not peel^char[]argv[i](array-of-^char). C(*(p))[i].- Anonymous
^array[N] of T—emit_type_specifieremitsT (*name)[N](no longerT name[N]/ param decayT *name). Named^Vector3was alreadyVector3 *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; owner name after the pointer test. First formal still owner value (self: Point/ref self: Point), not^Point. C by-valueType__m((*p));REF/VARauto-&outside the peel (Type__scale(&(*p), n)).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 deferred then (closed 0.26.5.179): auto-peel
of
Type::m(p). Still deferred: parent-chain method lookup; first formal^Owneras instance. - Tests green. make test-all /
selfhost / bootstrap green on
gcc, clang, and tcc.
Build 178. Branch
mod-c_0.26. Promoted 0.26.5.178. - Docs:
CURRENT.md,changelog.md,README.md, Language Report §5.3 / §5.4.0 / §6.2 / §8.3,docs/grok_report-20260904-ptr-index-method.md.
Version 0.26.5.177
- Light refactoring. Include examples/Shapes.mc, an example demonstrating EXTENDS and auto-deref.
Version 0.26.5.176
- Oberon
p.xauto-deref (§5.3) — one implied peel per.when the left side is a pointer (^Tor alias such aspNode = ^Node). Same meaning asp^.x. AST staysNODE_FIELD_ACCESS; no inserted caret node. Explicitp^.xunchanged. - Semantic —
field_access.auto_derefif the use type or itsresolved_typeis a pointer (do not chase alias first; that would drop^Childto namedChild). Field lookup /base_depthalready saw^Childby name. - Codegen —
(*(p)).field, then.base× N. No->.REF/VARformals unchanged (emit_let_identalready loads(*formal)). - Tests:
tests/test_extends.mc—c5.x/c5.y,pp.x,pg.z/pg.x,p.xintakeParentPtrbesidep^.x.tests/test_pointer_var.mc—root.value/p.next.valuebeside^.forms. - Still deferred then (closed 0.26.5.178):
p[i]peel for pointer-to-array (do not peel^char[]argv[i]); instance method on^T. - Tests green. make test-all /
selfhost / bootstrap green on
gcc, clang, and tcc.
Build 176. Branch
mod-c_0.26. Promoted 0.26.5.176. - Docs:
CURRENT.md,changelog.md,README.md, Language Report §5.3 / §5.4.0 / §6.2,docs/grok_report-20260903-auto-deref.md.
Version 0.26.5.175
- EXTENDS polish (optional #4) — three slices; Oberon
p.xauto-deref not in this build. p^.fieldparent fields —semantic_type_of_designatorpeels postfix^andASsoc5^.xgetsbase_depth(C(*c5).base.x). Child fieldsc5^.ywere already fine.- Aggregate
as→.base—g as Parentrecordsupcast_depthfrom inner vs target; codegen skips(Parent)g(invalid C for structs) and emits((g).base × N). - Pointer /
REFupcast —semantic_extends_upcast_depthwalks when both sides are pointers or both are values (mixed still 0).Node.upcast_ptr: value((expr).base × N)soREFactuals are&((c).base); pointer&((*(pc)).base × N). - Tests:
tests/test_extends.mc—c5^.x,g as Parent/g as Child,^Parentinit from^Grand,takeParentPtr/takeParentRef. - Still deferred then: Oberon
p.x/p[i]auto-deref (§5.3); instance method on pointer receiver. (Field.closed in 0.26.5.176.) - Tests green. Build 175. Branch
mod-c_0.26. - Docs:
CURRENT.md,changelog.md,README.md, Language Report §5.4.0 / §6.2,docs/grok_report-20260902-extends-polish.md.
Version 0.26.5.174
- #11 import as the one unit bind — named
.mhimport ofinteger/cardinal/real/stringrefines the prelude (once per unit). Foreign.hand include-only do not.ASalias is not the portable bind. - Codegen skips the default
typedefwhen that name is a listed.mhimport item; the pack.his the C ABI. Qualident is the bind name unlessASis present. .mhwidth spelling — type-spec tailsinteger N/cardinal N/real Non fields, formals, and results. Reader storestype_width/result_width; semantic copies onto importedTType. Old lines without a tail stay legal.- Width token: decimal, no leading zeros, at most two digits (closed
N; avoids
-Wstrict-overflowonn * 10). - Tests:
test_import_rebind+fixtures/lp64;test3_import_rebind_second/test3_import_then_rebind;test2_export_width/test2_import_width;test_import_width+fixtures/wpoint;test3_import_width. - Still deferred (#11): arch packs; build-time
defaults;
.mhalias RHS (export type integer complete integer 64). - Tests green. Build 174. Branch
mod-c_0.26. - 31 August 2026 — one Makefile:
CC ?= gcc;make CC=clang/make CC=tcc(family from theCCstring). Per-familyCFLAGS/DEBUG_FLAGS(no-lasan; tcc has no ASan).make cleanwhen switchingCC.Makefile.clangandMakefile.tccmoved toarchive/.make tarships onlyMakefile. make test-all green on gcc, clang, and tcc. - Docs:
CURRENT.md,changelog.md,README.md,AGENTS.md, Language Report §3.2 / §5.5 / §10.1,docs/syntax-ebnf.md,docs/grok_report-20260828-import-bind.md. Doc filenames:language-report.md,syntax-ebnf.md(hyphens).
Version 0.26.5.173
- Width forms —
integer N/cardinal N/real N(exact C11). Closed N: 8/16/32/64;real32/64. Decimal N only.TType.width; CintN_t/uintN_t/float/double. type integer = integer 64is the Phase A unit bind with a width RHS. Width forms are not rebindable names.- Generated
.howns the C prelude — stdint/stdbool/assert,nil/NIL,byte, portable four unless this unit bound the name. Unexported portableTYPEbinds still appear in the.h. - Generated
.c#include "UnitName.h"; no second prelude.-Cwrites a companion.h. Header always emits the unit prototype. - PROGRAM/MODULE name must match the output stem
(
#include "Name.h"). - Tests:
test_width,test_width_rebind,test3_width,test3_width_real. - Still deferred (#11 at 173): import as the one unit
bind; arch packs;
.mhwidth spelling on fields/formals. (Import-bind and.mhwidths closed in 0.26.5.174.) - make test-all, promote green on gcc, clang, and tcc. Promoted 0.26.5.173.
- Branch
mod-c_0.26; docs:CURRENT.md,changelog.md,README.md, Language Report §5.5 / §10.1 / §11,docs/syntax-ebnf.md,docs/grok_report-20260827-1548.md
Version 0.26.4.172
- Method-type
.mhRHS —export type TFn complete function (integer) : integer(andprocedure). Always(…)on the type line. - Reader:
is_func_type+ signature parse aftercompletewhen the type is notstruct/union. - Semantic: synthetic
NODE_METHOD_TYPEon import (type_decl.method_type := mt). Cross-moduleobj.field(...)call-through; import the method type and the struct. - Policy A: known function result as a statement still requires
(f()). - Tests:
test2_export_fn_type/test2_import_fn_type/test3_import_fn_type;test_import_fn_type+fixtures/fnbox. Field lists from 0.26.3.170. - make test-all, promote green on gcc, clang, and tcc. Promoted 0.26.4.172.
- Branch
mod-c_0.26; docs:CURRENT.md,changelog.md,README.md, Language Report §2.2 / §3.2 / §8.3,docs/grok_report-20260826-2130.md
Version 0.26.3.170
.mhfield lists —export type Name complete struct (f: T { , … });union; optionalextends Parent.opaqueunchanged forEXTERN TYPEandtype T = opaque.- Writer:
mh_type_opaqueno longer treats a struct body as opaque; field tail onDynBuf(same one-line@format 1as 6a signatures). - Reader: whole-file load (parse in place);
MhFieldonMhExport; barecomplete/opaquestill legal. - Semantic: synthetic
NODE_TYPE_DECL+struct_bodyon import; unknown field is an error.EXTENDSparent fields require the parent type imported. - Identifiers ≤ 255 — lexer and
.mhreader;test3_ident_long.mc. - Tests:
test2_export_struct/test2_import_struct/test3_import_struct_field; union and EXTENDS import pair;test_import_struct+fixtures/tpoint. Export.mhstill produced with-M. - Still deferred (closed in 0.26.4): method-type RHS / cross-module field call-through.
- make test-all green. Branch
mod-c_0.26.
Version 0.26.3.168
- Parser self-host closed —
parser.creplaced byparser_common.mc+parser_main.mc. - Shared helpers in
parser_common(TParser/pParser, token/EOS/error_atfamily). Dual exports:advance(p: pParser)(declaration / expression / statement) andTParser::advance(ref p: TParser)(parser_mainonly). parser_mainis the recursive-descent driver.modcincludesparser_common.h+parser_main.h.- Cyclic
.mhimports noted (parser_main ↔︎ declaration / expression / statement). Do not design until after Makefile subdirectory compilation (item 15). Interim: extract a common module. - make test-all, selfhost, bootstrap, promote green on gcc, clang, and tcc. Promoted 0.26.3.168.
- Branch
mod-c_0.26; docs:CURRENT.md,changelog.md,README.md, Language Report §3.2,docs/grok_report-20260824-parser-split.md
Version 0.26.3.167
- Conversion from parser.c to parser_main.mc complete and integrated.
Version 0.26.2.164
- Renamed struct Parser to TParser
Version 0.26.1.161
- Extract advance, check, match, error_at, consume, checkEOS, matchEOS, check_comment, match_comment, check_assignment, skip_empty_statements, skip_layout_breaks, isEOF from parser.c to parser_common.mc.
- Update declaration.mc, statement.mc, expression.mc accordingly.
Version 0.26.1.159
- REQUIRE/ENSURE statements now go through semantic_resolve_expr(...) so REF/VAR parameters are processed.
Version 0.26.1.158
- Unknown type names closed (breaking) — unbound
single-word type is an error
(
semantic_resolve_type_inner). - Still legal: prelude builtins;
IMPORT/EXTERN TYPE;.mhopaques; multi-word C (long long,unsigned int). Bareunsignedis not a type. - Automatic
<stddef.h>dropped — prelude is<stdint.h>/<stdbool.h>/<assert.h>;#define nil ((void *)0)/#define NIL nil. Importsize_t(andFILE,void, …) when used. - Tests:
test3_undef_type.mc; type import sweep onsrc/*.mc, tests, examples. - make test-all, selfhost, bootstrap, promote green on gcc, clang, and tcc. Promoted.
- Branch
mod-c_0.26; docs:CURRENT.md,changelog.md,README.md, Language Report §3.2 / §11
Version 0.26.0.156
- Free-call soft-miss closed (breaking) — unresolved
free
name(...)andType::name(...)are errors (semantic_resolve_call). - Still legal: same-unit
PROC/FUNC; namedIMPORT/EXTERN; 7a module-entry bind; method-typed values; field call-through. - Include-only
IMPORT FROMbinds no names. QuotedFROM "hdr.h"does not parse the header. - C preprocessor is copied to generated C only;
#definedoes not bind TMod-c names. Macros used from.mcbelong in a real.hplusIMPORT. - 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.mcrewritten to a realTSTRINGfunction. Compilersrc/*.mcimport sweep. - make test-all, selfhost, bootstrap, promote green on gcc, clang, and tcc. Promoted.
- Branch
mod-c_0.26; docs:CURRENT.md,changelog.md,README.md, Language Report §3.2 / §11,docs/syntax.ebnf.md,docs/grok_report-20260818-1311.md
Version 0.25.4.154
RECURSIVEenforced — direct self-call (resolved_sym.decl == enclosing_func) requiresRECURSIVEon the completing PROC/FUNC (the body).FORWARDtag on the incomplete decl alone is not enough. Mutual recursion not checked.- Compiler
.mcsweep (semantic,ttype,expression, …) so self-host stays legal. - Tests:
tests/test3_recursive.mc; factorial/fib demos already tagged. SIZEOF— type was alreadyinteger; C emit is now((integer)sizeof(...))(codegen_common_sizeof_expr).LENstill not emitted.- Lean generated prelude —
#includeonly<stddef.h>,<stdint.h>,<stdbool.h>,<assert.h>;typedef uint8_t byte;#define nil/NILNULL. No automatic<stdlib.h>(importexit). Tests, examples, andsrc/*.mcupdated. - Design notes (0.26): drop
<stddef.h>and require every non-builtin name on anIMPORT; lengths/indexes stay signedinteger;cardinalfor bits/C unsigned;size_timported. - make test-all, selfhost, bootstrap green on gcc, clang, and tcc. Promoted.
- Branch
mod-c_0.25(stem closed); docs:CURRENT.md,changelog.md, Language Report §8.1 / §10.1–§10.2 / §11,docs/syntax.ebnf.md,docs/grok_report-20260814-1645.md
Version 0.25.3.150
- Item 7a Done — module entry is a real
PROC/FUNCsymbol (same-unit and on.mhimport) - Same-unit:
MODULEname bound after pass 1; synthetic decl sharesprogram_declformals so call-site auto-&applies (ModuleName(obj)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 not bound - Names:
semantic_bind_mh_exportarena-copies bind names beforemh_module_free(fixes dangling constructor names / falseduplicate TType) - Callee ABI: module/program
emit_param_list(..., true)soVAR/REFformals lower toT*(e.g.module Lexer(ref lexer: TLexer, …)) - Tests:
tests/test_module_ref.mc;tests/test_module_entry.mc+fixtures/bumpint.mh(import TBumponly). make test green on gcc, clang, and tcc - Not 7b — no generated startup calls of imported module bodies
- Branch
mod-c_0.25; docs:CURRENT.md(Language Report / grok report later)
Version 0.25.3.149
.mhformal signatures (item 6a) Done — still@format 1/ one line per export- Writer:
( [var|ref|const] type-spec { , … } ) [ : result ]; prefer surface type names (aliases); optional multi-word C types when written that way - Reader:
MhFormal+ result fields; multi-word type-spec (long long,unsigned int); free formals on unload - Import: synthetic
NODE_PROC_DECL/NODE_FUNC_DECLwith formals (arena-copied); existing codegen call-site auto-&works cross-module forVAR/REF - Builds on 0.25.2 method Phase A
(
instance/static,import Type::name,obj.method) - Tests:
tests/test5_mh_method_import_string.mc(modc -a);tests/test4_string.mc+make string-lib/-ltmod_string(manual; not defaultmake test) - Self-host / suite:
make test/test2/test3green; selfhost path loads enriched.mh(e.g.utils.mh) - Deferred: complete struct field lists in
.mh; field call-through across modules; module-entry bind (7a) / startup init (7b) - Branch
mod-c_0.25; docs:CURRENT.md, Language Report §3.2 / §8.2–§8.3,docs/parameter-passing.md,docs/grok_report-20260811-2216.md
Version 0.25.2.146
- Cross-module method Phase A —
.mhinstance/staticOwner;import Type::name;TSymbol.is_method_instance;obj.methodacross modules - Create a small String library for testing with
make string-lib test4_*run tests for the library;test5_*semantic (-a) library import tests- String library targets must be manually run (depend on regenerated
include/*.mh+ archive)
Version 0.25.1.144
- Start conversion of parser.c to parser.mc
- Add
pDynBufto dynbuf.mc - "Mod-c" to "TMod-c" in README.md
- Update html from .md
Version 0.25.1.142
- Callable field call-through Done —
obj.field(args)whenfieldhas a method type (TYPE T = PROCEDURE/FUNCTION …) - Oberon rule: no auto-receiver on field calls; C
lowering
(obj.field)(args)(args as written) - Disambiguation: if both an instance
Type::nameand a method-typed field apply, compile-time error (useType::name(obj, …)) - Values: free call
fp(args)whenfpisVAR/PARAM/LET/CONSTof method type - AST / semantic / codegen:
call.callee_expr; helperssemantic_method_type_node,semantic_field_type_on,semantic_sym_is_method_value; instance sugar still usesreceiver_exprprepend - Tests:
tests/test_callable_field.mc,tests/test3_callable_field_ambig.mc; idiom demotests/test_Math.mc(struct ops +Type::create/ module entry factory; no vtables) - make test-all green on gcc, clang, and tcc; promote verified
- Branch
mod-c_0.25; docs:CURRENT.md,changelog.md
Version 0.25.0.140
- Item 20 Done (breaking) — formal parameter modes VAR / REF / CONST end-to-end
- Semantics: only
VARmay appear as the bare LHS of:=/INC/DEC;CONSTforbids any write through the formal (name, fields, indices);REFallows through-selectors (p.x,a[i]) but not bare-name assign - Codegen 20A:
VAR/REFon non-pointerT→T*; body loads(*p)where needed;REF p: ^Tstays one pointer level;VAR p: ^T→T** - Codegen 20B: call-site auto-
&for by-ref value formals (Swap(x, y)→Swap(&x, &y)); already-@args not double-addressed - Self-host:
arena.mc/semantic.mc/utils.mc(and related) use locals for scratch mutation of non-VARformals - 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 - Known soft spot: named open-array typedefs used as
REF/VARformals (prefer true open-array type-specifiers until alias chase lands) - Branch
mod-c_0.25; docs:CURRENT.md, Language Report §8.2,docs/grok_report-20260806-2042.md
Version 0.24.18.136
- Item #11 Phase A Done — portable unit rebind of
integer,cardinal,real,stringonly (Wirth-family names; not C type names) - One top-level
TYPEbind per name per compilation unit; second bind and rebind of fixed builtins (bool/byte/char, …) are errors - Unbound C defaults:
typedef int integer,unsigned int cardinal,float real,const char* string(rebind skips the default and emits the unit’sTYPEtypedef) - Helpers:
type_is_portable_rebindable; semantic prelude refine;codegen_c_unit_binds_portable - Tests:
tests/test_rebind.mc,tests/test3_rebind_second.mc,tests/test3_rebind_bool.mc; make test-all green - Deferred (#11): width forms
integer N/cardinal N/real N; import as the unit bind; architecture packs; compiler-build default selection - Docs:
CURRENT.md,changelog.md
Version 0.24.17.135
type Name FORWARD— incomplete TYPE in this unit; complete later withtype Name = …(symtab refine, same family as proc postfixFORWARD)- Codegen incomplete tag/typedef and method-type ordering so C accepts formals that name the type before the full layout
- Tests:
tests/test_type_forward.mc,tests/test3_type_forward_dup.mc,tests/test3_type_forward_reforward.mc(as applicable) - Docs:
CURRENT.md,changelog.md
Version 0.24.17.134
- Item 21 Done — type-bound instance
methods:
obj.method(args)→Type__method(obj, args…) - Instance vs static by first formal type (formal
name free): instance if first formal type is the owner; else static /
factory (
Type::only) - Expression + statement postfix chains (e.g.
p.print(),b.topLeft().print()) - Optional
end Type::name(and bareend name) after procedure/function bodies - Factories: e.g.
Point::new(x, y); instance call on static methods is an error - Tests:
tests/test_smoke.mc,tests/test3_smoke.mc; make test-all green on gcc, clang, and tcc - Deferred: callable function-pointer field call-through;
pointer/
VARself; parent-chain method lookup - Docs:
CURRENT.md,changelog.md, Language Report §8.3,docs/grok_report-20260803-2318.md
Version 0.24.16.130
- Self-host: declaration — hand-written
declaration.creplaced bysrc/declaration.mc; generateddeclaration.c(and build-paired header /.mhas applicable) - Conversion cleanup: stale comments removed; most obsolete receiver parse path dropped (type-qualified methods)
- EXTENDS by-value auto-upcast — child/descendant
used as ancestor → C
.base× N (option A);Node.upcast_depth; sites: typed init,:=,RETURN, same-unit call formals; multi-level - Design lock: no hidden type tags / RTTI / vtables
on structs (Modula-2 + C stance); programmer tags optional; no Oberon
ISwithout future opt-in - Deferred polish: pointer/
REFupcast; aggregateas→.base;^Tparent field lookup; richer.mhformals - make test-all green on gcc, clang, and tcc
- Docs:
CURRENT.md,changelog.md, Language Report §5.4.0,docs/syntax.ebnf.md,docs/grok_report-080126-2008.md,docs/project_bible.mdappend
Version 0.24.15.128
- Item 13b Done (Policy A) — bare call as statement
illegal when result type is known
(
semantic_type_of_expr); require(f())or use the value - Unknown result (procedure, untyped foreign import e.g. bare
printf) still allowed as bare call - Explicit discard remains
(expression)/(f())(NODE_PARENstatement) - Tests:
tests/test_discard.mc,tests/test3_discard.mc; make test-all green on gcc, clang, and tcc - Deferred: discard binding
_(item 24); C(void)hygiene optional in codegen - Docs:
CURRENT.md, Language Report §7.2,docs/syntax.ebnf.md
Version 0.24.14.126
- Item 21a Done —
semantic_type_of_expr+ simple init inference when:omitted onVAR/LET/CONST - Typing: literals; designators; paren; cast; sizeof; call returns;
unary
-/not/~/@/^; binary arith / bitwise / logical / compare; real arith - Tests:
tests/test_infer.mc(and suite); preludestringasconst char*where needed for C - Deferred: ternary
? :(and array-literal) typing — TODO 21a-ternary - Unlocks: discard (13b), EXTENDS auto-upcast,
obj.method(21),VARformals (20) - Docs:
CURRENT.mdcalm path step 4 complete
Version 0.24.14.125
- Self-host: Lexer — hand-written
lexer.c/lexer.hreplaced bysrc/Lexer.mc(moduleLexer); generatedLexer.c/Lexer.h/Lexer.mh - Tokenizer is now compiled from TMod-c source in the normal / self-host / bootstrap chain
- Exports:
TokenKindenum,TToken/TLexer,TLexer::init,TLexer::next,TokenKind::string,TToken::print - Keyword table includes correctly spelled
OPAQUE - Docs:
CURRENT.md,docs/grok_report-20260728-2052.md,docs/project_bible.mdappend
Version 0.24.13.122
- Linked-chunk arena — growth never relocates live
slabs (fixes ASan heap-use-after-free when
reallocmoved a full 1 MiB arena under AST/symtab pointers during large-aruns).ArenaChunkchain;callocnew chunks;memseteacharena_allocslice; defaultARENA_MIN_SIZE1 MiB STRUCT EXTENDSoption A (item 13d / calm path step 3) Done — unique field names on chain; synthetic embedParent base;field_access.base_depth→ C.base× depth; flatc.xin source; explicitc.base- Synthetic name
basereserved only on types that useEXTENDS(plain structs may declare a fieldbase) - Semantic helpers: designator typing for field lookup; clash / base-must-be-struct checks
- Tests:
tests/test_extends.mc,test3_extends_clash.mc,test3_extends_base_reserved.mc(plus existingtest2_extends.mc) - Auto-upcast still deferred (after 21a
type_of_expr) - Docs:
CURRENT.md, Language Report §5.4.0,docs/syntax.ebnf.md,docs/grok_report-20260725-2251.md
Version 0.24.12.118
- Bare
UNIONtypes (item 13c / calm path step 2) Done —type T = union … end; lexerUNION;struct_decl.is_union;parse_union_type; semantic (no EXTENDS on union);codegen_common_union_decl→ Cunion - Nested aggregates: define named type first, then use as field type (no anonymous nested union/struct yet)
- Tests:
test_union.mc,test3_union.mc(and opaque suite from 0.24.11) - Promoted; make test-all green on gcc, clang, and tcc
- Docs:
CURRENT.md, Language Report §5.4.1,docs/grok_report-20260723-2250.md
Version 0.24.11.116
- Remove an unnecessary space before ';' production for 'typedef'.
Version 0.24.11.115
OPAQUEtypes (item 13a / calm path step 1) Done —type T = opaque,^opaque,POINTER TO opaqueon TYPE RHS;TType.is_opaque/ parse / codegen (typedef void *Name); bareopaquerejected in type-specifier; tests green
Version 0.24.11.112
- expression.c is now selfhosted with expression.mc
Documentation (21–25 July 2026)
STRUCT EXTENDSdesign then implementation (0.24.13 / 13d) — Oberon record model + C option Aunion-typeEBNF then implementation (0.24.12) — bare C union; not language-level tagged unions- Language SSOT:
language_report.md+syntax.ebnf.md(from 18 July); session reportdocs/grok_report-20260725-2251.md
Documentation (18 July 2026)
- Language SSOT:
docs/language_report.md(Wirth-style Language Report draft);docs/syntax.ebnf.md(complete formal EBNF only) docs/grammar.md— redirect stub; full prior content archived asdocs/grammar_working_notes.md- Design captured in report:
OPAQUE, discard(f()), Oberon auto-deref intent, ownership modes, no mandatory GC,VAR/LETplacement
Version 0.24.10.110
- statement.c to statement.mc, now selfhosted.
Version 0.24.9.106
- Converted symkind.h to symkind.mc and mh_exportkind.h to mh_exportkind.mc
Version 0.24.8.104
- Named
CONSTin array bounds —array[LIMIT] of Tandarray[LIMIT+1] of TwhenLIMITis a compile-time integerCONST TType.size_expr— deferred bound until semantic fold;type_create_array_expr; parser accepts const-expr inarray[…] of TandT[…]semantic_try_eval_const_expr— soft integer fold with optional message out-parameter;semantic_eval_const_expris a thin fatal wrapper (no duplicated logic)CONSTregistration — sethas_const_value/const_valueonly when integer fold succeeds; string/pointerCONSTunchanged (e.g.const c2: ^char = "bye")- Operators — binary
modacceptsTOK_MODandTOK_KEYWORD_MOD - Review fixes — fallback message when hard eval fails without msg; typo in register error string
- Self-host, bootstrap, and promote verified green
Version 0.24.7.101
- ENUM Phase C —
MH_KIND_ENUM;.mhexport enum+ memberexport constlines; cross-module enum import - Tests:
test_mh_enum_export.mc,test2_mh_enum_import.mc,test_mh_enum_import.mc;fixtures/colors.{mh,h} .mhnegative import tests — tier-3test3_*coverage for bad imports- Makefile test CFLAGS (gcc) —
-I$(SRC_DIR) -I$(INCLUDE_DIR) -I$(LIB_DIR);include/fixturessymlink for fixture headers - Design:
WHILE … BYnot planned — usedeferat loop head for iteration step (docs/grammar.md)
Version 0.24.7.100
- ENUM Phase A/B —
parse_enum_type,NODE_ENUM_TYPE/NODE_ENUM_ITEM;semantic_register_enum_type,semantic_eval_const_expr;codegen_common_enum_type(Ctypedef enum) TSymbol.const_valuefor enum member constants; duplicate-member negative test- Experimental
src/tmodc.h— shared C ABI prelude for hand-written C including generated headers - TMod-c rebrand (documentation) —
docs/grammar.md,CURRENT.md,AGENTS.md,changelog.md; archivaldocs/grok_report-20260714-1939.md - Tests:
tests/test2_enum_parse.mc,tests/test_enum.mc,tests/test3_enum_dup.mc - Add
src/tmodc.hfor TMod-c symbol types that can be imported by C files.
Version 0.24.5.97
- Add
skip_layout_breakstoparse_param_list.
Version 0.24.5.96
- Qualident
IMPORT … FROM—import-source = string-literal | qualident - Unquoted qualident → Mod-c module (
.mhsymtab +.h#include); quoted paths unchanged mh_reader:mh_qualident_to_mh_relpath,mh_format_h_include; updated path helperstests/test2_mh_import_qual.mc;docs/grammar.mdupdated
Version 0.24.4.93
- See docs/grok_report-20260711-1911.md
- Converted codegen_header.c to codegen_header.mc (functional parity; minor 0.24.4 bump)
- docs/grammar.md: import phase 1 / phase 2 documented
Version 0.24.3.90
- See docs/grok_report-20260710-1200.md
skip_layout_breaksinparse_unary(expression operands) and insideconsume(required keywords)RETURN: newline after barereturnends statement; multiline values use parentheses- Unreachable code after
RETURN/BREAK/CONTINUEis fatal error (was warning) - Added tests/test_layout.mc, tests/test3_loop.mc
Version 0.24.3.79
- See docs/grok_report-20260709-2338.md
- Lowered
integerandcardinaldown tointandunsigned int - Updated parser so '' isn't required when statement has an explicit
end-of-statement keyword, like
IMPORT...FROM "filename". Import items can be left on one line or spread out with one item on each line. Rules spelled out in docs/grammar.md. - Added tests/test_import_layout.mc
Version 0.24.2.76
- Add counters to tests in Makefile.
- Add negative tests, (test3_*) to Makefle.
- Update many sections of Makefile.
- Update several test .mc files.
- Updated Makefile.clang and Makefile.tcc to match Makefile.
- Build number only updates when 'make version' is executed.
Version 0.24.2
- Add helper to include MODULE name in '.mh' file export list for codegen_mh.mc.
- Update codegen.mc to use corresponding '.mh' files for imports.
- Update the rest of the source files to use the corresponding '.mh' files if there is one.
- Add VERSION, VERSION_BASE, and BUILD_NUMBER to version.h, updated by Makefile everytime a build is done.
- Add changelog.md
- Update version number.