Compiler design / 09. Templates and TIR
First-class templates keep structure in AST-local TIR, then hand folded strings or neutral runtime data downstream.
Look at the page fragment again:
[$html:
<p>[greet(visitor)]</p>
]
A template is not a string with holes poked by hope. It contains structure: wrappers, slots, child values, control flow and placement order. Flatten it too early and you lose the skeleton the checker and the runtime both need.
Moth gives templates a first-class home and a temporary Template IR (TIR) that lives only while AST work runs.
The fragment wants a paragraph wrapper, an interpolation of a string-producing call and a stable place in the page's fragment order.
If the compiler treated the body as blind concatenation, it could still emit characters on a happy path. It would struggle to:
Structure earns its keep.
Diagram placeholder: Paragraph wrapper contains a dynamic name slot
Caption: teaching structure. Question: what does interpolation mean once structure exists?
One module AST build owns one TemplateIrStore. Parser emission writes text, expressions, child templates, slots, inserts, wrappers and control-flow roots directly into that store.
The phase sequence is:
Parsed -> Composed -> Formatted -> Finalized
Teaching names for the parts:
if and loop structure before it becomes ordinary CFG in HIRExact view identity includes root, phase and value context. Consumers read through that authority rather than inventing parallel overlay stacks.
Folding requires Composed or later. AST-to-HIR handoff requires Finalized.
Diagram placeholder: One template passes through four structural phases
Caption: accepted phase names, simplified records. Question: where does template structure live during AST?
AST finalisation walks prepared views and chooses a fate:
if and loop bodies stay available for lazy loweringCompile-time fragments never live in HIR. HIR receives ordinary string and control-flow work for runtime pieces only. The TIR store drops before the completed AST leaves the stage. It is temporary scaffolding, not permanent structure. No TIR id tours a public interface or backend.
For the greeting project, a fully static visitor and prefix can collapse toward the familiar fragment. If visitor were dynamic input, the structure would still check at compile time while runtime handoff carried the moving parts.
Diagram placeholder: Static pieces become a string while dynamic pieces become neutral runtime handoff data
Caption: exact boundary, simplified shape. Question: what reaches HIR?
Moth template .mtf and Markdown .md files do not invent forever-parallel compilers. They adapt into ordinary synthetic content #String declarations.
.mtf builds a private constant whose initializer is a structurally built $md template over the original body tokens.md can contribute the same declaration shape with a synthetic string-literal initializer after Markdown preparationLater ordering and folding treat both as ordinary compile-time constants. Return to the greeting project after that side path: @page.moth remains the star, and document kinds prove the "one semantic pipeline" bet.
Diagram placeholder: moth, mtf and md reach one ordinary semantic path
Caption: simplified source-kind map. Question: how does document content enter the compiler without a second IR forever?
Reactivity in Moth is a constrained template and UI source-and-sink model. It is not a general closure system and not a second semantic IR.
Durable ownership:
If you need arbitrary higher-order function values, this is the wrong language feature to stretch.
CompilerError, not a casual user typo)TIR ownership must stay distinct from AST finalisation and HIR validation. Post-TIR parser optimisation plans may discuss performance. They do not redefine the semantic handoff.
Alternative: general macros, JSX-style external transforms or a separate markup compiler with its own type system.
Choice: first-class constrained templates with AST-local TIR.
Benefit: template structure gains semantic checks without a second backend language.
Cost: TIR needs strict lifetime and handoff rules. It is not a public interface for users or backends.
post-tir-template-parser-optimization-plan.md for performance discussion, labelled queued or deferred as appropriate.You leave with finalised TIR handoff, folded fragments and neutral runtime template data. Next: how a failure should travel through all these owners.