glimr/loom/handler_parser

Handler Expression Parser

Template event handlers (l-on:click, l-on:input) are written as inline assignment strings that need to become typed Gleam code. This module bridges that gap by parsing handler expressions into structured data so the code generator can emit correct function bodies with proper prop assignments, tuple destructuring, and special variable injection ($value, $key, etc.).

Example:

“count = count + 1” “count = counter.increment(count)” “#(count, total) = counter.increment_both(count, total)”

Types

Code generation needs to know which props a handler updates and what expression produces the new values. Bundling event metadata (name, modifiers), assignment targets, and the expression together lets the generator emit a complete handler function in one pass without re-parsing the original string.

pub type Handler {
  Handler(
    event: String,
    modifiers: List(String),
    targets: List(String),
    expression: String,
    original: String,
    line: Int,
  )
}

Constructors

  • Handler(
      event: String,
      modifiers: List(String),
      targets: List(String),
      expression: String,
      original: String,
      line: Int,
    )

    Arguments

    event

    The event name (click, input, submit, etc.)

    modifiers

    Event modifiers (prevent, stop, immediate, etc.)

    targets

    Props being assigned to (single or tuple destructure)

    expression

    The Gleam expression that produces the new value(s)

    original

    Original handler string for error messages

    line

    Line number in source

Handler expressions are user-authored strings that can easily contain syntax mistakes. Structured error variants let the compiler point to the exact problem — a missing assignment operator, an empty target, or malformed tuple syntax — so the user can fix their template quickly.

pub type HandlerError {
  EmptyTarget(handler: String, line: Int)
  EmptyExpression(handler: String, line: Int)
  InvalidTupleSyntax(handler: String, line: Int)
}

Constructors

  • EmptyTarget(handler: String, line: Int)

    Empty target in assignment

  • EmptyExpression(handler: String, line: Int)

    Empty expression in assignment

  • InvalidTupleSyntax(handler: String, line: Int)

    Invalid tuple syntax

Values

pub fn collect_handlers(
  template: parser.Template,
) -> Result(List(#(String, Handler)), HandlerError)

The code generator needs a flat list of all handlers in the template to emit handler functions and a dispatch map. Walking the AST here centralizes that collection so the generator doesn’t need its own traversal logic. l-model attributes are desugared into input handlers to keep the generator’s output uniform.

pub fn get_special_vars(handler: Handler) -> List(String)

Handler expressions can reference browser event data via special variables ($value, $checked, $key). The generated handler function needs to extract these from the JS event object and pass them as arguments, so we scan for their presence to know which extractions to emit.

pub fn handler_id(event: String, index: Int) -> String

Multiple handlers of the same event type can exist in a single template. A deterministic ID based on event name and index ensures each generated handler function has a unique name that the client-side runtime can resolve.

pub fn parse(
  event: String,
  modifiers: List(String),
  handler_str: String,
  line: Int,
) -> Result(Handler, HandlerError)

Entry point for turning a raw handler string into a structured Handler. Supports both assignment expressions (prop = expr) and side-effect expressions (expr) that execute code without updating props.

Search Document