Spec M21.5 — Tier 3 follow-ups exposed by examples/lang (mechanisms only)
Source: the M22 report (2026-09-03). Each item is a generic mechanism; none mentions classes, generics, namespaces or memory policy.
- The bundle must cost zero nodes.
src/bundle_data.mc'su64 bundle_blob[] = { ... }is parsed into ~48 000N_INTnodes (5 MB of arena) every time a taught compiler includes<mc/core>, which is whyexamples/langhad to ship its own copy of the core's module list. Carry the blob as bytes:#embed bundle_blob "bundle.bin"(M15's own directive; the file is generated next tobundle_data.mcand bundled by name so<mc/core>still works from the binary alone) — zero nodes, byte-identical output.tools/bundle.mcemits both;check-bundlecompares both. Then deleteexamples/lang/lang_core.mcandlang_main.mcand point[compiler].coreback to<mc/core>(acceptance:examples/langbuilds on the bundled core with the default 32 MiB arena andmc limitsshows headroom). arena exhaustednames its caller.xalloctakes no position, so the error has none. Add a one-line context: the lasterr_at-style position seen by the parser (file:line of the current token) plus the sizes requested, e.g.mc: arena exhausted (32 MiB) while parsing x.mc:120 — raise [limits] tolerance or heap. With M23 the arena ismmap'd from the estimate, so also print the estimate that fell short.mc build --compiler-only. Builds the taught compiler from[compiler]and stops; prints its path.test.shscripts and the LSP (M28) need it.on_stmt(uptr fn). Registered inuser_init; called byparse_stmtafter every statement node is produced (core or taught), with the node index; the handler may return the same node, a replacement, or 0 (drop). Justification: any language that must wrap, rewrite or observe core statements (return/break/continue/i64 x = ...) without re-teaching them — scope tracking, instrumentation, ownership/borrow rules, coverage — exactly the class of bookkeeping M22 did by walking the tree afterwards. Order: taughtsyntax_stmthandlers first, thenon_stmthooks in registration order.parse_block()dispatches throughsyntax_stmt("{")when one is registered, so a module that tracks scopes sees every block, including the bodiesparse_functionand#ruleblockholes parse. Without a registration the behaviour is unchanged.- Core-declared locals are observable. Covered by 4 (
on_stmtsees theN_VARnode); document it as the intended way instead of a separate hook.
Acceptance: lib/user_syntax_demo.mc gains an on_stmt demo (statement counter that rewrites nothing)
and a scope-tracking demo through syntax_stmt("{") inside a #rule body; examples/lang migrates
to on_stmt for scope exits and to <mc/core> (deleting its copies); make check green; golden
rewritten once; the bundle blob file reproducible; check-obj 32/32 (mechanisms are inert).