Skip to content

AST Nodes

All AST node types are dataclasses defined in pyrx_nlt.nodes. The tokenizer produces these nodes, and the renderer walks them to produce final HTML output.

python
from pyrx_nlt.nodes import (
LiteralNode, ExpressionNode, IfNode, ForNode,
ListNode, TableNode, AggregateNode, SetNode,
RawNode, DefineMacroNode, UseMacroNode,
BlockNode, ExtendsNode, ParentNode,
ConditionClause, CompoundCondition,
ListConfig, TableConfig,
)

ASTNode Union Type

The ASTNode type alias is the union of all 14 node types. Use it for type annotations when working with node lists:

python
from pyrx_nlt.nodes import ASTNode
 
ASTNode = (
LiteralNode
| ExpressionNode
| IfNode
| ListNode
| TableNode
| AggregateNode
| ForNode
| SetNode
| RawNode
| DefineMacroNode
| UseMacroNode
| BlockNode
| ExtendsNode
| ParentNode
)

Node Types

LiteralNode

Raw HTML/text that passes through unchanged.

python
@dataclass
class LiteralNode:
text: str
FieldTypeDescription
textstrThe literal text content. Not processed or escaped by the renderer.

Template syntax: Any text outside {...} blocks.


ExpressionNode

A {the user's ...} variable substitution.

python
@dataclass
class ExpressionNode:
raw: str
raw_block: str
FieldTypeDescription
rawstrInner text for re-parsing in the render path. E.g. the user's First Name, or "Customer".
raw_blockstrFull {..} original text, used for pass-through on parse error. E.g. {the user's First Name, or "Customer"}.

Template syntax: {the user's First Name}, {the Amount from the trigger event, as "currency"}, etc.

Note

The expression is not parsed during tokenization -- only during rendering. This allows the renderer to attempt multiple resolution strategies (loop variables, macro parameters, local variables, ternary, builtins) before falling back to parse_nlt_expression().


IfNode

Represents {if ...}...{else}...{end if} blocks.

python
@dataclass
class IfNode:
condition: AnyCondition
then_nodes: list[ASTNode] = field(default_factory=list)
else_nodes: list[ASTNode] = field(default_factory=list)
FieldTypeDescription
conditionAnyConditionA ConditionClause or CompoundCondition. See Condition Types below.
then_nodeslist[ASTNode]Nodes to render when the condition is true.
else_nodeslist[ASTNode]Nodes to render when the condition is false. Includes {else if} chains as nested IfNode structures.

Template syntax: {if the user's Plan is premium}...{else}...{end if}


ForNode

Represents {for <var> in <source>}...{else}...{end for} blocks.

python
@dataclass
class ForNode:
item_var: str
source: str
attribute_path: str
event_name: str | None = None
limit: int | None = None
body_nodes: list[ASTNode] = field(default_factory=list)
else_nodes: list[ASTNode] = field(default_factory=list)
FieldTypeDescription
item_varstrVariable name for the current item, e.g. "item", "product".
sourcestrData source: "user", "trigger_event", or "named_event".
attribute_pathstrThe attribute containing the list to iterate over.
event_namestr | NoneEvent name for named_event source.
limitint | NoneMaximum items to iterate, from show first N.
body_nodeslist[ASTNode]Nodes to render for each item in the list.
else_nodeslist[ASTNode]Nodes to render if the list is empty or null.

Template syntax: {for item in the user's Orders, show first 3}...{else}...{end for}


ListNode

Renders an array as an HTML list or comma-separated string.

python
@dataclass
class ListNode:
config: ListConfig
FieldTypeDescription
configListConfigConfiguration for the list display. See ListConfig below.

Template syntax: {list the user's Tags}, {list the user's Tags, as comma list}


TableNode

Renders structured data as an inline-styled HTML table.

python
@dataclass
class TableNode:
config: TableConfig
FieldTypeDescription
configTableConfigConfiguration for the table display. See TableConfig below.

Template syntax: {table the user's Orders with columns: Date, Item, Amount}


AggregateNode

Computes sum, average, or count of an array attribute.

python
@dataclass
class AggregateNode:
function: Literal["sum", "average", "count"]
source: str
attribute_path: str
event_name: str | None = None
format_spec: str | None = None
pluralize_word: str | None = None
FieldTypeDescription
functionLiteral["sum", "average", "count"]The aggregate function to compute.
sourcestrData source: "user", "trigger_event", or "named_event".
attribute_pathstrThe attribute containing the array to aggregate.
event_namestr | NoneEvent name for named_event source.
format_specstr | NoneOptional format spec, e.g. "currency".
pluralize_wordstr | NoneOptional word to pluralize for count, e.g. "item".

Template syntax: {sum of the user's Order Amounts}, {count of the user's Items, pluralize "item"}


SetNode

Variable assignment via {set <name> to <expression>}.

python
@dataclass
class SetNode:
var_name: str
raw_expression: str
FieldTypeDescription
var_namestrThe variable name to assign.
raw_expressionstrThe raw expression text to evaluate and assign.

Template syntax: {set discount to the user's Subtotal times 0.1}


RawNode

Content between {raw}...{end raw} -- emitted verbatim with no processing.

python
@dataclass
class RawNode:
content: str
FieldTypeDescription
contentstrThe raw content. Not HTML-escaped by the renderer.

Template syntax: {raw}{end raw}


DefineMacroNode

Registers a reusable macro. Produces no output.

python
@dataclass
class DefineMacroNode:
name: str
params: list[str]
body_nodes: list[ASTNode] = field(default_factory=list)
FieldTypeDescription
namestrThe macro name.
paramslist[str]Positional parameter names.
body_nodeslist[ASTNode]The macro body to render on invocation.

Template syntax: {define greeting(name, title)}Hello {name}, {title}!{end define}


UseMacroNode

Invokes a registered macro with positional arguments.

python
@dataclass
class UseMacroNode:
name: str
args: list[str]
FieldTypeDescription
namestrThe macro name to invoke.
argslist[str]Positional arguments. Each arg is either a literal string or an NLT expression that gets resolved.

Template syntax: {use greeting("Jane", "Manager")}


BlockNode

A named content block for template inheritance.

python
@dataclass
class BlockNode:
block_name: str
body_nodes: list[ASTNode] = field(default_factory=list)
FieldTypeDescription
block_namestrThe block name used for matching between parent and child templates.
body_nodeslist[ASTNode]Default content for the block (can be overridden by child templates).

Template syntax: {block title}Default Title{end block}


ExtendsNode

Declares template inheritance from a base template.

python
@dataclass
class ExtendsNode:
template_name: str
FieldTypeDescription
template_namestrThe name of the base template to extend. Resolved by the TemplateLoader protocol.

Template syntax: {extends "base.html"}


ParentNode

Marker node that renders parent block content inside a child block override.

python
@dataclass
class ParentNode:
pass

No fields. When encountered inside a BlockNode in a child template, it is replaced with the parent template's block content.

Template syntax: {parent}


Condition Types

ConditionClause

A single condition from an {if ...} block.

python
@dataclass
class ConditionClause:
source: str
attribute_path: str
event_name: str | None = None
operator: str = "eq"
value: str | float | None = None
value2: str | float | None = None
FieldTypeDescription
sourcestr"user", "trigger_event", or "named_event".
attribute_pathstrThe attribute to compare.
event_namestr | NoneEvent name for named_event source.
operatorstrComparison operator. One of: eq, neq, gt, lt, gte, lte, between, is_set, not_set, contains, not_contains, is_today, is_this_week, is_this_month, within_last_days, within_last_weeks, within_last_months, date_before, date_after.
valuestr | float | NoneRight-hand side of the comparison.
value2str | float | NoneSecond bound for the between operator.

CompoundCondition

Compound condition with AND/OR logical operators.

python
@dataclass
class CompoundCondition:
operator: Literal["and", "or"]
children: list[ConditionClause | CompoundCondition] = field(default_factory=list)
FieldTypeDescription
operatorLiteral["and", "or"]The logical operator combining the children.
childrenlist[ConditionClause | CompoundCondition]Child conditions. Can be nested for complex logic.

AnyCondition

Type alias for either a simple or compound condition:

python
AnyCondition = ConditionClause | CompoundCondition

Config Dataclasses

ListConfig

Configuration for a {list ...} block.

python
@dataclass
class ListConfig:
source: str
attribute_path: str
event_name: str | None = None
limit: int | None = None
style: Literal["ul", "ol", "comma"] = "ul"
FieldTypeDescription
sourcestrData source: "user", "trigger_event", or "named_event".
attribute_pathstrThe attribute containing the list to display.
event_namestr | NoneEvent name for named_event source.
limitint | NoneMaximum items to show, from show first N.
styleLiteral["ul", "ol", "comma"]Display style. Default is "ul" (unordered list).

TableConfig

Configuration for a {table ...} block.

python
@dataclass
class TableConfig:
source: str
attribute_path: str
event_name: str | None = None
columns: list[str] = field(default_factory=list)
FieldTypeDescription
sourcestrData source: "user", "trigger_event", or "named_event".
attribute_pathstrThe attribute containing the data to tabulate.
event_namestr | NoneEvent name for named_event source.
columnslist[str]Column names to display. Empty list means auto-discover from first row's keys.