Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

wire.expression

import wire

wire exposes this as wire.expression, so import wire is enough and the names are called as wire.expression.*. import wire.expression reaches 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:

KindWritten as
literals12, 1.5, 'text', "text", true, false, nil
collections[1, 2], { id: 1, name }
lookupuser.address.city, items.0, items[index]
callsroute('home'), user.display_name()
arithmetic+, -, *, /, %
comparison==, !=, <, <=, >, >=, in, not in
logicand, or, not (also &&, `
choicestock > 0 ? 'in stock' : 'sold out'
defaultnickname ?? name
ranges0..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

FieldTypeDescription
valueThe 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

FieldTypeDescription
nameThe 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

FieldTypeDescription
targetThe expression being read from.
nameThe 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

FieldTypeDescription
targetThe expression being read from.
keyThe 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

FieldTypeDescription
calleeThe expression giving the thing to call.
argumentsThe argument expressions, in order.
labelHow 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

FieldTypeDescription
itemsThe 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

FieldTypeDescription
entriesThe 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

FieldTypeDescription
operatorThe operator: not or -.
operandThe 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

FieldTypeDescription
operatorThe operator.
leftThe left operand.
rightThe 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

FieldTypeDescription
operatorThe operator: and, or or ??.
leftThe left operand.
rightThe 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

FieldTypeDescription
conditionThe expression being tested.
consequenceThe value when the test passes.
alternativeThe 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

FieldTypeDescription
targetThe expression giving the value being filtered.
nameThe filter’s name.
argumentsThe 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

FieldTypeDescription
type'name', 'number', 'string', 'operator' or 'end'.
valueThe token’s text, or for a string or number its decoded value.
offsetHow 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

FieldTypeDescription
tokensThe tokens left to read.
atHow far through them the parser is.
sourceThe expression’s source, for error messages.
pathThe template the expression came from.
lineThe line of the tag the expression was written on.
columnThe 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