/// Token and AST types for the template engine.
///|
/// A token produced by the lexer.
pub(all) enum Token {
/// Raw text content (HTML outside of {{ }})
Text(String)
/// Variable interpolation: {{ name }}
Var(String)
/// Block open: {{#if condition}} or {{#unless condition}}
Open(String, String)
/// Block close: {{/if}} or {{/unless}} or {{/each}}
Close(String)
/// Raw/unescaped interpolation: {{{ html }}}
Unescaped(String)
/// Comment: {{!-- text --}}
Comment(String)
}
///|
/// An AST node produced by the parser.
pub(all) enum Node {
/// Raw text, rendered as-is
Text(String)
/// Escaped variable: {{ name }}
Var(String)
/// Unescaped variable: {{{ html }}}
Unescaped(String)
/// Conditional block: {{#if condition}}...{{/if}}
If(String, Array[Node])
/// Conditional block with else: {{#if condition}}...{{else}}...{{/if}}
IfElse(String, Array[Node], Array[Node])
/// Negated conditional: {{#unless condition}}...{{/unless}}
Unless(String, Array[Node])
/// Negated conditional with else
UnlessElse(String, Array[Node], Array[Node])
/// Loop block: {{#each items}}...{{/each}}
Each(String, String, Array[Node])
/// Root node
Root(Array[Node])
}
/// Template context is an array of (key, value) pairs.
/// Use `[("name", "value")]` to construct.
// ------- Enhanced Context -------
///|
/// A template context value: either a string or a nested array.
pub(all) enum ContextValue {
Str(String)
List(Array[ContextValue])
Object(Array[(String, ContextValue)])
} derive(Eq)
///|
/// Build context from a flat array of string pairs.
pub fn context_from_pairs(
pairs : Array[(String, String)],
) -> Array[(String, ContextValue)] {
let result : Array[(String, ContextValue)] = []
for pair in pairs {
result.push((pair.0, ContextValue::Str(pair.1)))
}
result
}
///|
/// Lookup a key in a context array (returns empty string if not found).
pub fn context_lookup(
key : String,
ctx : Array[(String, ContextValue)],
) -> String {
for i in 0.. return v
_ => return "[complex]"
}
}
}
""
}
///|
/// Flatten a ContextValue to a simple key-value array (for nested each).
pub fn context_flatten(value : ContextValue) -> Array[(String, ContextValue)] {
match value {
Str(_) => []
List(items) => {
let result : Array[(String, ContextValue)] = []
for item in items {
result.push(("this", item))
}
result
}
Object(_) => []
}
}
// ------- Error Diagnostics -------
///|
/// A template error with location info.
pub(all) struct TemplateError {
message : String
line : Int
column : Int
} derive(Eq)
///|
/// Create a template error.
pub fn template_error(
message : String,
line : Int,
column : Int,
) -> TemplateError {
{ message, line, column }
}
///|
/// Format a template error for display.
pub fn format_template_error(err : TemplateError) -> String {
"line \{err.line}, col \{err.column}: \{err.message}"
}
// ------- Partial & Helper Support -------
///|
/// A partial template loaded by name.
pub(all) struct Partial {
name : String
template : String
} derive(Eq)
///|
/// A helper function that takes a string argument and returns a string.
pub(all) struct Helper {
name : String
func : (String) -> String
}