wire.expression
import wire
wireexposes this aswire.expression, soimport wireis enough and the names are called aswire.expression.*.import wire.expressionreaches the same definitions directly.
Wire’s expression language: the thing that sits between {{ and }},
and the thing an x-if or an x-for is given.
It is deliberately a small language rather than an embedded Zuri. There is no assignment, no statement, no way to define anything and no way to reach a global, because a template is a description of a page and everything else belongs in the code that renders it. What is here is what reading a value out of a dictionary and deciding whether to show a section actually needs:
| Kind | Written as |
|---|---|
| literals | 12, 1.5, 'text', "text", true, false, nil |
| collections | [1, 2], { id: 1, name } |
| lookup | user.address.city, items.0, items[index] |
| calls | route('home'), user.display_name() |
| arithmetic | +, -, *, /, % |
| comparison | ==, !=, <, <=, >, >=, in, not in |
| logic | and, or, not (also &&, ` |
| choice | stock > 0 ? 'in stock' : 'sold out' |
| default | nickname ?? name |
| ranges | 0..pages, 1..10 |
| filters | `name |
Truthiness is Wire’s, not Zuri’s: an empty list is false and a negative
number is true. wire.values explains why, and it matters for every
and, or, not and ? here.
Missing values
Reading a name that was never supplied gives nil rather than raising,
and so does reading a key off it. {{ user.address.city }} on a request
with no user renders as nothing at all instead of failing three levels
down, which is what makes an optional section readable. Ask with x-if
when the difference matters.
Names beginning with an underscore cannot be read. Those are private in Zuri, and a template has no business reaching into them.
Constants
KEYWORDS
wire.expression.KEYWORDS = [...]
The words that are part of the language rather than names a template can bind.
LONG_OPERATORS
wire.expression.LONG_OPERATORS = [...]
Operators made of more than one character, longest first so that <= is
never read as < followed by =.
SHORT_OPERATORS
wire.expression.SHORT_OPERATORS = [...]
Operators made of a single character.
Functions
tokenize()
wire.expression.tokenize(source: string, path: string, line: number, column: number) -> list
Splits source into tokens.
path, line and column are only used to place the error when the source does not lex, and name the tag the expression was written on rather than anything inside the expression.
Parameters
source(string)path(string)line(number)column(number)
Returns list
Raises TemplateSyntaxError
parse()
wire.expression.parse(source: string, path: string, line: number, column: number) -> Expression
Compiles source into a syntax tree.
path, line and column describe the tag the expression was written on and are only used to place a syntax error.
import wire
var tree = wire.expression.parse('price * quantity', '<source>', 0, 0)
Parameters
source(string)path(string)line(number)column(number)
Returns Expression
Raises TemplateSyntaxError when source is not a valid
expression.
Classes
Expression
class wire.expression.Expression
The base of every node in a parsed expression.
Nodes are built once, when a template is compiled, and evaluated once per render. They hold no state of their own, so the same compiled template can be rendered from several places at once.
Expression.evaluate()
wire.expression.Expression.evaluate(scope) -> any
Works out this node’s value.
scope is supplied by the renderer and answers the three questions an expression cannot answer for itself: what a name is bound to, what a filter does, and how to report a failure with the position of the tag the expression came from.
Parameters
scope(Scope)
Returns any
Literal
class wire.expression.Literal < Expression
A number, a string, or one of true, false and nil.
Fields
| Field | Type | Description |
|---|---|---|
value | The value, ready to use. |
Constructor
wire.expression.Literal(value)
Parameters
value(any)
Literal.evaluate()
wire.expression.Literal.evaluate(scope) -> any
Parameters
scope(Scope)
Returns any
Variable
class wire.expression.Variable < Expression
A bare name, looked up in the variables the template was rendered with.
Fields
| Field | Type | Description |
|---|---|---|
name | The name being read. |
Constructor
wire.expression.Variable(name: string)
Parameters
name(string)
Variable.evaluate()
wire.expression.Variable.evaluate(scope) -> any
Parameters
scope(Scope)
Returns any
Member
class wire.expression.Member < Expression
A dotted lookup, as in user.name.
Fields
| Field | Type | Description |
|---|---|---|
target | The expression being read from. | |
name | The key, field or method name. |
Constructor
wire.expression.Member(target, name: string)
Parameters
target(Expression)name(string)
Member.evaluate()
wire.expression.Member.evaluate(scope) -> any
Parameters
scope(Scope)
Returns any
Index
class wire.expression.Index < Expression
A bracketed lookup, as in items[index], where the key is itself an
expression.
Fields
| Field | Type | Description |
|---|---|---|
target | The expression being read from. | |
key | The expression giving the key. |
Constructor
wire.expression.Index(target, key)
Parameters
target(Expression)key(Expression)
Index.evaluate()
wire.expression.Index.evaluate(scope) -> any
Parameters
scope(Scope)
Returns any
Call
class wire.expression.Call < Expression
A call, as in route('home') or user.display_name().
Fields
| Field | Type | Description |
|---|---|---|
callee | The expression giving the thing to call. | |
arguments | The argument expressions, in order. | |
label | How the callee was written, for the error message when it turns out not to be callable. |
Constructor
wire.expression.Call(callee, arguments: list, label: string)
Parameters
callee(Expression)arguments(list)label(string)
Call.evaluate()
wire.expression.Call.evaluate(scope) -> any
Parameters
scope(Scope)
Returns any
ListLiteral
class wire.expression.ListLiteral < Expression
A list literal.
Fields
| Field | Type | Description |
|---|---|---|
items | The item expressions, in order. |
Constructor
wire.expression.ListLiteral(items: list)
Parameters
items(list)
ListLiteral.evaluate()
wire.expression.ListLiteral.evaluate(scope) -> list
Parameters
scope(Scope)
Returns list
DictLiteral
class wire.expression.DictLiteral < Expression
A dictionary literal.
Fields
| Field | Type | Description |
|---|---|---|
entries | The entries, as a list of [key, value] expression pairs. |
Constructor
wire.expression.DictLiteral(entries: list)
Parameters
entries(list)
DictLiteral.evaluate()
wire.expression.DictLiteral.evaluate(scope) -> dict
Parameters
scope(Scope)
Returns dict
Unary
class wire.expression.Unary < Expression
not x, !x or -x.
Fields
| Field | Type | Description |
|---|---|---|
operator | The operator: not or -. | |
operand | The expression it applies to. |
Constructor
wire.expression.Unary(operator: string, operand)
Parameters
operator(string)operand(Expression)
Unary.evaluate()
wire.expression.Unary.evaluate(scope) -> any
Parameters
scope(Scope)
Returns any
Binary
class wire.expression.Binary < Expression
An arithmetic or comparison operator.
Fields
| Field | Type | Description |
|---|---|---|
operator | The operator. | |
left | The left operand. | |
right | The right operand. |
Constructor
wire.expression.Binary(operator: string, left, right)
Parameters
operator(string)left(Expression)right(Expression)
Binary.evaluate()
wire.expression.Binary.evaluate(scope) -> any
Parameters
scope(Scope)
Returns any
Logical
class wire.expression.Logical < Expression
and, or or ??, each of which decides whether to evaluate its right
side after looking at its left.
Fields
| Field | Type | Description |
|---|---|---|
operator | The operator: and, or or ??. | |
left | The left operand. | |
right | The right operand. |
Constructor
wire.expression.Logical(operator: string, left, right)
Parameters
operator(string)left(Expression)right(Expression)
Logical.evaluate()
wire.expression.Logical.evaluate(scope) -> any
Parameters
scope(Scope)
Returns any
Conditional
class wire.expression.Conditional < Expression
condition ? consequence : alternative.
Fields
| Field | Type | Description |
|---|---|---|
condition | The expression being tested. | |
consequence | The value when the test passes. | |
alternative | The value when it does not. |
Constructor
wire.expression.Conditional(condition, consequence, alternative)
Parameters
condition(Expression)consequence(Expression)alternative(Expression)
Conditional.evaluate()
wire.expression.Conditional.evaluate(scope) -> any
Parameters
scope(Scope)
Returns any
Filter
class wire.expression.Filter < Expression
A value passed through a filter, as in name|upper.
Fields
| Field | Type | Description |
|---|---|---|
target | The expression giving the value being filtered. | |
name | The filter’s name. | |
arguments | The argument expressions, in order, after the value itself. |
Constructor
wire.expression.Filter(target, name: string, arguments: list)
Parameters
target(Expression)name(string)arguments(list)
Filter.evaluate()
wire.expression.Filter.evaluate(scope) -> any
Parameters
scope(Scope)
Returns any
Token
class wire.expression.Token
One piece of an expression’s source: its kind, its value, and where in the expression it started.
Fields
| Field | Type | Description |
|---|---|---|
type | 'name', 'number', 'string', 'operator' or 'end'. | |
value | The token’s text, or for a string or number its decoded value. | |
offset | How far into the expression the token started, counting from 0. |
Constructor
wire.expression.Token(type: string, value, offset: number)
Parameters
type(string)value(any)offset(number)
Parser
class wire.expression.Parser
Builds a syntax tree from an expression’s tokens.
There is one of these per expression compiled, and it is thrown away once the tree is built.
Fields
| Field | Type | Description |
|---|---|---|
tokens | The tokens left to read. | |
at | How far through them the parser is. | |
source | The expression’s source, for error messages. | |
path | The template the expression came from. | |
line | The line of the tag the expression was written on. | |
column | The column of that tag. |
Constructor
wire.expression.Parser(source: string, path: string, line: number, column: number)
Parameters
source(string)path(string)line(number)column(number)
Parser.parse()
wire.expression.Parser.parse() -> Expression
Parses the whole expression and insists that nothing is left over.
Returns Expression
Raises TemplateSyntaxError
Parser.parse_ternary()
wire.expression.Parser.parse_ternary() -> Expression
condition ? consequence : alternative, which is the loosest binding
thing in the language.
Returns Expression
Parser.parse_coalesce()
wire.expression.Parser.parse_coalesce() -> Expression
a ?? b.
Returns Expression
Parser.parse_range()
wire.expression.Parser.parse_range() -> Expression
a..b, the same range Zuri writes the same way.
Ranges do not chain, since 1..2..3 means nothing.
Returns Expression
Parser.parse_or()
wire.expression.Parser.parse_or() -> Expression
a or b, also spelled a || b.
Returns Expression
Parser.parse_and()
wire.expression.Parser.parse_and() -> Expression
a and b, also spelled a && b.
Returns Expression
Parser.parse_equality()
wire.expression.Parser.parse_equality() -> Expression
a == b and a != b.
Returns Expression
Parser.parse_comparison()
wire.expression.Parser.parse_comparison() -> Expression
The ordering operators, plus in and not in.
Returns Expression
Parser.parse_additive()
wire.expression.Parser.parse_additive() -> Expression
a + b and a - b.
Returns Expression
Parser.parse_multiplicative()
wire.expression.Parser.parse_multiplicative() -> Expression
a * b, a / b and a % b.
Returns Expression
Parser.parse_unary()
wire.expression.Parser.parse_unary() -> Expression
not a, !a and -a.
Returns Expression
Parser.parse_filtered()
wire.expression.Parser.parse_filtered() -> Expression
A value with any filters applied to it.
Filters bind tighter than every operator, so items|length > 3 compares
the length rather than filtering the comparison.
Returns Expression
Parser.parse_filter()
wire.expression.Parser.parse_filter(target) -> Filter
One filter application, in either of the two forms it can take.
Parameters
target(Expression)
Returns Filter
Parser.parse_postfix()
wire.expression.Parser.parse_postfix() -> Expression
A value with any lookups and calls applied to it.
Returns Expression
Parser.parse_arguments()
wire.expression.Parser.parse_arguments() -> list
A comma separated argument list, up to and including its closing parenthesis.
Returns list
Parser.parse_primary()
wire.expression.Parser.parse_primary() -> Expression
A literal, a name, a bracketed expression, or a list or dictionary literal.
Returns Expression
Parser.parse_list()
wire.expression.Parser.parse_list() -> ListLiteral
A list literal, with the opening bracket already consumed.
Returns ListLiteral
Parser.parse_dict()
wire.expression.Parser.parse_dict() -> DictLiteral
A dictionary literal, with the opening brace already consumed.
A key may be a bare name, a quoted string or a bracketed expression. An
entry written as a bare name on its own is the shorthand Zuri uses: { user }
means { user: user }.
Returns DictLiteral
Parser.parse_dict_entry()
wire.expression.Parser.parse_dict_entry() -> list
One key: value pair, or the bare name shorthand.
Returns list
Parser.peek()
wire.expression.Parser.peek() -> Token
The token the parser is looking at.
Returns Token
Parser.take_operator()
wire.expression.Parser.take_operator(value: string) -> bool
Consumes the current token when it is the operator value.
Parameters
value(string)
Returns bool
Parser.take_any_operator()
wire.expression.Parser.take_any_operator(values: list) -> ?string
Consumes the current token when it is any of values, returning which
one it was or nil.
Parameters
values(list)
Returns ?string
Parser.take_keyword()
wire.expression.Parser.take_keyword(word: string) -> bool
Consumes the current token when it is the keyword word.
Parameters
word(string)
Returns bool
Parser.peek_keyword()
wire.expression.Parser.peek_keyword(word: string) -> bool
Whether the current token is the keyword word.
Parameters
word(string)
Returns bool
Parser.peek_keyword_at()
wire.expression.Parser.peek_keyword_at(ahead: number, word: string) -> bool
Whether the token ahead places further on is the keyword word.
Parameters
ahead(number)word(string)
Returns bool
Parser.expect_operator()
wire.expression.Parser.expect_operator(value: string)
Consumes the operator value or reports what was there instead.
Parameters
value(string)
Raises TemplateSyntaxError
Parser.describe_span()
wire.expression.Parser.describe_span() -> string
How the source read from the start of the value just parsed, used to name a callee that turned out not to be callable.
Returns string
Parser.describe()
wire.expression.Parser.describe(token) -> string
A readable rendering of token for an error message.
Parameters
token(Token)
Returns string
Parser.fail()
wire.expression.Parser.fail(reason: string)
Raises a syntax error naming the expression it happened in.
Parameters
reason(string)
Raises TemplateSyntaxError
2026, Richard Ore and The Zuri Contributors