Tokenizer & Parser
The tokenizer converts template strings into AST node lists (Phase 1). The parser converts individual expression text into structured NLTExpression dataclasses.
tokenize()
Parse a template string into a list of AST nodes. This is Phase 1 of the two-phase pipeline.
Parameters
| Parameter | Type | Description |
|---|---|---|
template | str | The full template string containing NLT expressions, control flow, and literal text. |
Returns
list[ASTNode] -- a list of AST nodes ready for rendering. See AST Nodes for all node types.
Processing Steps
- Normalize apostrophes -- convert Unicode apostrophe-like characters (smart quotes
\u2018\u2019, backticks, acute accents, etc.) to ASCII'. This ensures templates pasted from Google Docs, macOS, or rich text editors work correctly. - Extract
{raw}...{end raw}content to placeholders (preserves literal content) - Strip comments (
{# ... #}) - Clean HTML tags from inside
{...}expressions (handles rich text editor artifacts) - Extract all
{...}blocks into a flat token list - Build nested AST from if/else/end-if, for/end-for, and other block structures
Graceful Degradation
Malformed blocks (e.g., {if} without {end if}) degrade to LiteralNode rather than raising errors. The tokenizer always produces a valid AST.
Example
parse_nlt_expression()
Parse the inner text of a {...} block into a structured expression. This function handles source identification, math operator extraction, and modifier/filter parsing.
Parameters
| Parameter | Type | Description |
|---|---|---|
raw | str | Inner text of the expression, e.g. the user's First Name, or "Customer" |
Returns
NLTExpression -- a frozen dataclass with the parsed source, attribute path, and all modifiers.
Raises
NLTParseError -- if the source keyword cannot be identified (i.e., the expression does not match the user's ..., the ... from the trigger event, or the ... from the ... event).
Example
NLTExpression
A frozen (immutable) dataclass representing a parsed NLT variable expression.
Fields
| Field | Type | Description |
|---|---|---|
source | str | Data source: "user", "trigger_event", or "named_event" (also "latest_event" for legacy compat). |
attribute_path | str | The attribute name, e.g. "First Name", "Reference Number". Supports dot notation. |
event_name | str | None | Event name for named_event source, e.g. "payment". None for user and trigger sources. |
fallback | str | None | Default value from the or "..." modifier. |
required | bool | True if the required modifier is present. Suppresses the entire email if the value is missing. |
format_spec | str | None | Format string from the as "..." modifier. E.g. "currency", "currency EUR", "short date", "DD MMM YYYY". |
transform | str | None | Text transform: "uppercase", "lowercase", "titlecase", or "capitalize". |
pluralize | bool | Legacy pluralize flag (backward compatibility). |
pluralize_word | str | None | Word to pluralize, from pluralize "item". |
math_op | str | None | Math operation: "add", "subtract", "multiply", "divide", or "modulo". |
math_operand | float | None | Numeric operand for the math operation. |
filters | tuple[tuple[str, str | None], ...] | Chain of (filter_name, argument) pairs. Argument is None for no-argument filters. Multi-argument filters encode args with | separators. |
The filters field uses a tuple of tuples (not a list) because NLTExpression is frozen. Multi-argument filters like replace "a" with "b" are stored as ("replace", "a|b") and where "key" is "value" as ("where", "key|value").
NLTParseError
Raised by parse_nlt_expression() when the source keyword cannot be identified. The renderer catches this error internally and falls back to emitting the original {...} text unchanged.
NLTConditionParseError
Raised by the condition parser when an {if ...} condition cannot be parsed. The tokenizer catches this and degrades the block to literal text.