glimr/loom/lexer
Template Lexer
Converts template source text into a stream of tokens. Recognizes variables, directives, components, and plain text for the parser to process.
Types
Component and element tags support several attribute flavors that need different code generation strategies. Separating them here lets the generator handle each without re-parsing attribute strings.
pub type ComponentAttr {
StringAttr(name: String, value: String)
ExprAttr(name: String, value: String)
BoolAttr(name: String)
ClassAttr(value: String)
StyleAttr(value: String)
LmIf(condition: String, line: Int)
LmElseIf(condition: String, line: Int)
LmElse
LmFor(
collection: String,
items: List(String),
loop_var: option.Option(String),
line: Int,
)
LmOn(
event: String,
modifiers: List(String),
handler: String,
line: Int,
)
LmModel(prop: String, line: Int)
LmShow(condition: String, line: Int)
}
Constructors
-
StringAttr(name: String, value: String) -
ExprAttr(name: String, value: String) -
BoolAttr(name: String) -
ClassAttr(value: String) -
StyleAttr(value: String) -
LmIf(condition: String, line: Int) -
LmElseIf(condition: String, line: Int) -
LmElse -
LmFor( collection: String, items: List(String), loop_var: option.Option(String), line: Int, ) -
LmOn( event: String, modifiers: List(String), handler: String, line: Int, )l-on:event handler (e.g., l-on:click=“count = count + 1”)
-
LmModel(prop: String, line: Int)l-model two-way binding (e.g., l-model=“name”)
-
LmShow(condition: String, line: Int)l-show conditional visibility (e.g., l-show=“active”)
Surfacing specific error variants allows the compiler to produce actionable messages with position info, so users can quickly locate malformed template syntax.
pub type LexerError {
UnterminatedExpression(position: Int)
EmptyExpression(position: Int)
UnterminatedDirective(position: Int)
InvalidDirective(directive: String, position: Int)
InvalidLmForSyntax(content: String, position: Int)
UnterminatedComponent(position: Int)
InvalidComponentSyntax(content: String, position: Int)
InvalidPropsDirective(content: String, line: Int)
InvalidImportDirective(content: String, line: Int)
UnterminatedPropsDirective(line: Int)
UnterminatedImportDirective(line: Int)
}
Constructors
-
UnterminatedExpression(position: Int) -
EmptyExpression(position: Int) -
UnterminatedDirective(position: Int) -
InvalidDirective(directive: String, position: Int) -
InvalidLmForSyntax(content: String, position: Int) -
UnterminatedComponent(position: Int) -
InvalidComponentSyntax(content: String, position: Int) -
InvalidPropsDirective(content: String, line: Int) -
InvalidImportDirective(content: String, line: Int) -
UnterminatedPropsDirective(line: Int) -
UnterminatedImportDirective(line: Int)
The parser needs a structured representation of template syntax to build the AST. Each variant captures a distinct construct so the parser can pattern match on it directly.
pub type Token {
Text(String)
Variable(name: String, line: Int)
RawVariable(name: String, line: Int)
Slot(name: option.Option(String))
SlotDef(name: option.Option(String))
SlotDefEnd
Attributes
Component(
name: String,
attributes: List(ComponentAttr),
self_closing: Bool,
)
ComponentEnd(name: String)
Element(
tag: String,
attributes: List(ComponentAttr),
self_closing: Bool,
)
ElementEnd(tag: String)
ImportDirective(import_str: String, line: Int)
PropsDirective(props: List(#(String, String)), line: Int)
}
Constructors
-
Text(String) -
Variable(name: String, line: Int) -
RawVariable(name: String, line: Int) -
Slot(name: option.Option(String)) -
SlotDef(name: option.Option(String)) -
SlotDefEnd -
Attributes -
Component( name: String, attributes: List(ComponentAttr), self_closing: Bool, ) -
ComponentEnd(name: String) -
Element( tag: String, attributes: List(ComponentAttr), self_closing: Bool, ) -
ElementEnd(tag: String) -
ImportDirective(import_str: String, line: Int)@import directive for importing types/modules
-
PropsDirective(props: List(#(String, String)), line: Int)@props directive declaring template parameters
Values
pub fn tokenize(input: String) -> Result(List(Token), LexerError)
Entry point for the lexer. Wraps the recursive loop so callers don’t need to supply internal state like position, line number, or the tag stack.