glimr/loom/generator
Code Generator
Templates are authored in HTML with directives, but the server needs executable Gleam functions to render them. This module closes that gap by transforming the parsed AST into string-building Gleam code that calls runtime helpers, so templates get full type-checking and compile to native BEAM code with no interpretation overhead.
Types
When a parent template uses a component without supplying all props, the generator needs to fill in type-appropriate defaults. This map provides the expected fields per component so defaults can be generated at compile time rather than failing at runtime.
pub type ComponentData {
ComponentData(props: List(#(String, String)), is_live: Bool)
}
Constructors
-
ComponentData(props: List(#(String, String)), is_live: Bool)
pub type ComponentDataMap =
dict.Dict(String, ComponentData)
Components may accept a default slot, named slots, or neither. The generator needs this information to decide which slot arguments to include in the generated render call and which to supply as empty strings when the parent doesn’t provide content.
pub type ComponentSlotInfo {
ComponentSlotInfo(
has_default_slot: Bool,
named_slots: List(String),
)
}
Constructors
-
ComponentSlotInfo( has_default_slot: Bool, named_slots: List(String), )
Without knowing which slots each component expects, the generator would either omit required slot arguments (causing compile errors) or always include every possible slot (wasting code). This map lets it emit exactly the right set of slot parameters.
pub type ComponentSlotMap =
dict.Dict(String, ComponentSlotInfo)
The compiler pipeline needs both the module name (to determine the output file path) and the generated source code (to write it). Bundling them together keeps the caller from having to track which code belongs to which module.
pub type GeneratedCode {
GeneratedCode(module_name: String, code: String)
}
Constructors
-
GeneratedCode(module_name: String, code: String)
The generated handle function signature only includes special variable parameters ($value, $checked, $key) that are actually referenced. Tracking usage as bools lets the generator conditionally include each parameter and avoid unused-variable warnings.
pub type UsedSpecialVars {
UsedSpecialVars(value: Bool, checked: Bool, key: Bool)
}
Constructors
-
UsedSpecialVars(value: Bool, checked: Bool, key: Bool)
Values
pub fn extract_slot_info(
template: parser.Template,
) -> ComponentSlotInfo
Combines default slot detection and named slot collection into a single ComponentSlotInfo. The compiler calls this once per component template and caches the result so every parent template that uses the component can generate correct slot arguments.
pub fn generate(
template: parser.Template,
module_name: String,
is_component: Bool,
component_data: dict.Dict(String, ComponentData),
component_slots: dict.Dict(String, ComponentSlotInfo),
) -> GeneratedCode
Public entry point for the code generator. Wraps the internal generate_module with the GeneratedCode return type so the compiler pipeline can write the output to the correct file path based on the module name.
pub fn validate_template(
template: parser.Template,
source_path: String,
) -> Result(Nil, String)
Generated code that references undefined variables would fail to compile with confusing Gleam errors. Validating at the template level lets us produce clear, actionable error messages pointing to the template source line rather than the generated code.