# expressions

URL: /kida/api/compiler/expressions/
Section: compiler
Description: Expression compilation for Kida compiler.

Provides mixin for compiling Kida expression AST nodes to Python AST expressions.

Uses inline TYPE_CHECKING declarations for host attributes.
See: plan/rfc-mixin-protocol-typing.md

---

> For a complete page index, fetch /kida/llms.txt.

Open LLM text
(/kida/api/compiler/expressions/index.txt)

Share with AI

Ask Claude
(https://claude.ai/new?q=Please%20help%20me%20understand%20this%20documentation%3A%20%2Fkida%2Fapi%2Fcompiler%2Fexpressions%2Findex.txt)

Ask ChatGPT
(https://chatgpt.com/?q=Please%20help%20me%20understand%20this%20documentation%3A%20%2Fkida%2Fapi%2Fcompiler%2Fexpressions%2Findex.txt)

Ask Gemini
(https://gemini.google.com/app?q=Please%20help%20me%20understand%20this%20documentation%3A%20%2Fkida%2Fapi%2Fcompiler%2Fexpressions%2Findex.txt)

Ask Copilot
(https://copilot.microsoft.com/?q=Please%20help%20me%20understand%20this%20documentation%3A%20%2Fkida%2Fapi%2Fcompiler%2Fexpressions%2Findex.txt)

Module

#
`compiler.expressions`

Expression compilation for Kida compiler.

Provides mixin for compiling Kida expression AST nodes to Python AST expressions.

Uses inline TYPE_CHECKING declarations for host attributes.
See: plan/rfc-mixin-protocol-typing.md

1Class1Function

## Classes

`ExpressionCompilationMixin`

36

▼

Mixin for compiling expressions.

Host attributes and cross-mixin dependencies are declared via inl…

Mixin for compiling expressions.

Host attributes and cross-mixin dependencies are declared via inline
TYPE_CHECKING blocks.

#### Attributes

Name
Type
Description

`_EXPR_DISPATCH`

`ClassVar[dict[str, str]]`

—

`_STORE_METHODS`

`frozenset[str]`

—

#### Methods

Internal Methods
34

▼

`_precomputed_ref`

1

`ast.Name`

▼

Return an ``ast.Name`` referencing a precomputed module-level binding.

Non-con…

`def _precomputed_ref(self, value: object) -> ast.Name`

Return an`ast.Name`referencing a precomputed module-level binding.

Non-constant-safe values (dict, list, set, custom objects) cannot be
stored in`ast.Constant`nodes. Instead they are collected during
compilation and injected into the`exec()` namespace as `_pc_N`.

##### Parameters

Name
Type
Description

`value`
`—`

##### Returns

`ast.Name`

`_get_filter_suggestion`

1

`str | None`

▼

Find closest matching filter name for typo suggestions.

`def _get_filter_suggestion(self, name: str) -> str | None`

##### Parameters

Name
Type
Description

`name`
`—`

##### Returns

`str | None`

`_get_test_suggestion`

1

`str | None`

▼

Find closest matching test name for typo suggestions.

`def _get_test_suggestion(self, name: str) -> str | None`

##### Parameters

Name
Type
Description

`name`
`—`

##### Returns

`str | None`

`_make_deferred_lambda`

1

`ast.Lambda`

▼

Wrap an expression in a zero-arg lambda for deferred evaluation.

Used by ``_is…

`def _make_deferred_lambda(self, expr: ast.expr) -> ast.Lambda`

Wrap an expression in a zero-arg lambda for deferred evaluation.

Used by`_is_defined`, `_default_safe`, and `_null_coalesce`
to catch`UndefinedError`at runtime without evaluating the
expression eagerly.

##### Parameters

Name
Type
Description

`expr`
`—`

##### Returns

`ast.Lambda`

`_is_potentially_string`

1

`bool`

▼

Check if node could produce a string value (macro call, filter chain).

Used to…

`def _is_potentially_string(self, node: Node) -> bool`

Check if node could produce a string value (macro call, filter chain).

Used to determine when numeric coercion is needed for arithmetic operations.
Recursively checks nested expressions to catch Filter nodes inside parentheses.

This handles cases like (a | length) + (b | length) where the left/right
operands are Filter nodes that need numeric coercion.

##### Parameters

Name
Type
Description

`node`
`—`

##### Returns

`bool`

`_wrap_coerce_numeric`

1

`ast.expr`

▼

Wrap expression in _coerce_numeric() call for arithmetic safety.

Ensures that …

`def _wrap_coerce_numeric(self, expr: ast.expr) -> ast.expr`

Wrap expression in _coerce_numeric() call for arithmetic safety.

Ensures that Markup objects (from macros) are converted to numbers
before arithmetic operations, preventing string multiplication.

##### Parameters

Name
Type
Description

`expr`
`—`

##### Returns

`ast.expr`

`_compile_expr`

2

`ast.expr`

▼

Compile expression node to Python AST expression.

O(1) dict dispatch by ``type…

`def _compile_expr(self, node: Node, store: bool = False) -> ast.expr`

Compile expression node to Python AST expression.

O(1) dict dispatch by`type(node).__name__`.

##### Parameters

Name
Type
Description

`node`
`—`

`store`
`—`

Default:`False`

##### Returns

`ast.expr`

`_compile_const`

1

`ast.expr`

▼

Compile constant literal.

`def _compile_const(self, node: Const) -> ast.expr`

##### Parameters

Name
Type
Description

`node`
`—`

##### Returns

`ast.expr`

`_compile_name`

2

`ast.expr`

▼

Compile variable reference.

`def _compile_name(self, node: Name, *, store: bool = False) -> ast.expr`

##### Parameters

Name
Type
Description

`node`
`—`

`store`
`—`

Default:`False`

##### Returns

`ast.expr`

`_compile_tuple`

2

`ast.expr`

▼

Compile tuple expression.

`def _compile_tuple(self, node: Tuple, *, store: bool = False) -> ast.expr`

##### Parameters

Name
Type
Description

`node`
`—`

`store`
`—`

Default:`False`

##### Returns

`ast.expr`

`_compile_list`

1

`ast.expr`

▼

Compile list expression.

`def _compile_list(self, node: List) -> ast.expr`

##### Parameters

Name
Type
Description

`node`
`—`

##### Returns

`ast.expr`

`_compile_list_comp`

1

`ast.expr`

▼

Compile list comprehension.

`def _compile_list_comp(self, node: ListComp) -> ast.expr`

##### Parameters

Name
Type
Description

`node`
`—`

##### Returns

`ast.expr`

`_compile_dict`

1

`ast.expr`

▼

Compile dict expression.

`def _compile_dict(self, node: Dict) -> ast.expr`

##### Parameters

Name
Type
Description

`node`
`—`

##### Returns

`ast.expr`

`_compile_getattr`

1

`ast.expr`

▼

Compile attribute access (obj.attr).

`def _compile_getattr(self, node: Getattr) -> ast.expr`

##### Parameters

Name
Type
Description

`node`
`—`

##### Returns

`ast.expr`

`_compile_getitem`

1

`ast.expr`

▼

Compile subscript access (obj[key]).

`def _compile_getitem(self, node: Getitem) -> ast.expr`

##### Parameters

Name
Type
Description

`node`
`—`

##### Returns

`ast.expr`

`_compile_slice`

1

`ast.expr`

▼

Compile slice expression (start:stop:step).

`def _compile_slice(self, node: Slice) -> ast.expr`

##### Parameters

Name
Type
Description

`node`
`—`

##### Returns

`ast.expr`

`_compile_test`

1

`ast.expr`

▼

Compile test expression (is defined, is none, etc.).

`def _compile_test(self, node: Test) -> ast.expr`

##### Parameters

Name
Type
Description

`node`
`—`

##### Returns

`ast.expr`

`_compile_func_call`

1

`ast.expr`

▼

Compile function call expression.

`def _compile_func_call(self, node: FuncCall) -> ast.expr`

##### Parameters

Name
Type
Description

`node`
`—`

##### Returns

`ast.expr`

`_compile_filter`

1

`ast.expr`

▼

Compile filter expression (value | filter_name).

`def _compile_filter(self, node: Filter) -> ast.expr`

##### Parameters

Name
Type
Description

`node`
`—`

##### Returns

`ast.expr`

`_compile_binop`

1

`ast.expr`

▼

Compile binary operation.

`def _compile_binop(self, node: BinOp) -> ast.expr`

##### Parameters

Name
Type
Description

`node`
`—`

##### Returns

`ast.expr`

`_compile_unaryop`

1

`ast.expr`

▼

Compile unary operation.

`def _compile_unaryop(self, node: UnaryOp) -> ast.expr`

##### Parameters

Name
Type
Description

`node`
`—`

##### Returns

`ast.expr`

`_compile_compare`

1

`ast.expr`

▼

Compile comparison expression.

`def _compile_compare(self, node: Compare) -> ast.expr`

##### Parameters

Name
Type
Description

`node`
`—`

##### Returns

`ast.expr`

`_compile_boolop`

1

`ast.expr`

▼

Compile boolean operation (and/or).

`def _compile_boolop(self, node: BoolOp) -> ast.expr`

##### Parameters

Name
Type
Description

`node`
`—`

##### Returns

`ast.expr`

`_compile_cond_expr`

1

`ast.expr`

▼

Compile conditional (ternary) expression.

`def _compile_cond_expr(self, node: CondExpr) -> ast.expr`

##### Parameters

Name
Type
Description

`node`
`—`

##### Returns

`ast.expr`

`_compile_await`

1

`ast.expr`

▼

Compile await expression.

`def _compile_await(self, node: Await) -> ast.expr`

##### Parameters

Name
Type
Description

`node`
`—`

##### Returns

`ast.expr`

`_compile_null_coalesce`

1

`ast.expr`

▼

Compile a ?? b to handle both None and undefined variables.

Uses _null_coalesc…

`def _compile_null_coalesce(self, node: NullCoalesce) -> ast.expr`

Compile a ?? b to handle both None and undefined variables.

Uses _null_coalesce helper to catch UndefinedError for undefined variables.
Part of RFC: kida-modern-syntax-features.

The helper is called as:

```
_null_coalesce(lambda: a, lambda: b)
```

This allows:

- a ?? b to return b if a is undefined (UndefinedError)

- a ?? b to return b if a is None

- a ?? b to return a if a is any other value (including falsy: 0, '', [])

##### Parameters

Name
Type
Description

`node`
`—`

##### Returns

`ast.expr`

`_compile_optional_getattr`

1

`ast.expr`

▼

Compile obj?.attr using walrus operator to avoid double evaluation.

obj?.attr …

`def _compile_optional_getattr(self, node: OptionalGetattr) -> ast.expr`

Compile obj?.attr using walrus operator to avoid double evaluation.

obj?.attr compiles to:
'' if (_oc := obj) is None else (_oc_val := _getattr_none(_oc, 'attr')) if _oc_val is not None else ''

The double check ensures that:

- If obj is None, return ''

- If obj.attr is None, return '' (for output) but preserve None for ??

For null coalescing to work, we need a different approach: the optional
chain preserves None so ?? can check it, but for direct output, None becomes ''.

Actually, we return None but rely on the caller to handle None → '' conversion.
For output, the expression is wrapped differently.

Simplified: Return None when short-circuiting, let output handle conversion.

Part of RFC: kida-modern-syntax-features.

##### Parameters

Name
Type
Description

`node`
`—`

##### Returns

`ast.expr`

`_compile_optional_getitem`

1

`ast.expr`

▼

Compile obj?[key] using walrus operator to avoid double evaluation.

obj?[key] …

`def _compile_optional_getitem(self, node: OptionalGetitem) -> ast.expr`

Compile obj?[key] using walrus operator to avoid double evaluation.

obj?[key] compiles to:
None if (_oc := obj) is None else _getitem_none(_oc, key)

Routes through`_getitem_none` so Mapping receivers return `None`on
missing keys (v0.8.0+ semantics), while Sequence/out-of-range accesses
still raise under`strict_undefined`.

Part of RFC: kida-modern-syntax-features.

##### Parameters

Name
Type
Description

`node`
`—`

##### Returns

`ast.expr`

`_compile_optional_method_call`

3

`ast.expr`

▼

Compile obj?.method(*args, **kwargs) with short-circuit.

When obj is None or o…

`def _compile_optional_method_call(self, opt_getattr: OptionalGetattr, args: Sequence[Any], kwargs: dict[str, Any]) -> ast.expr`

Compile obj?.method(*args, **kwargs) with short-circuit.

When obj is None or obj.method is UNDEFINED, return None without calling.
Uses _optional_call(callee, *args, **kwargs) helper.

##### Parameters

Name
Type
Description

`opt_getattr`
`—`

`args`
`—`

`kwargs`
`—`

##### Returns

`ast.expr`

`_compile_range`

1

`ast.expr`

▼

Compile range literal to range() call.

1..10 → range(1, 11) # inclusiv…

`def _compile_range(self, node: Range) -> ast.expr`

Compile range literal to range() call.

1..10 → range(1, 11) # inclusive
1...11 → range(1, 11) # exclusive
1..10 by 2 → range(1, 11, 2)

Part of RFC: kida-modern-syntax-features.

##### Parameters

Name
Type
Description

`node`
`—`

##### Returns

`ast.expr`

`_compile_inlined_filter`

1

`ast.Call`

▼

Compile inlined filter to direct method call.

Generates: _str(value).method(*a…

`def _compile_inlined_filter(self, node: InlinedFilter) -> ast.Call`

Compile inlined filter to direct method call.

Generates: _str(value).method(*args)

This replaces filter dispatch overhead with a direct method call,
providing ~5-10% speedup for filter-heavy templates.

##### Parameters

Name
Type
Description

`node`
`—`

##### Returns

`ast.Call`

`_compile_optional_filter`

1

`ast.expr`

▼

Compile expr ?| filter — skip filter if value is None.

expr ?| upper compiles…

`def _compile_optional_filter(self, node: OptionalFilter) -> ast.expr`

Compile expr ?| filter — skip filter if value is None.

expr ?| upper compiles to:
None if (_of_N := expr) is None else _filters'upper' (_of_N)

##### Parameters

Name
Type
Description

`node`
`—`

##### Returns

`ast.expr`

`_compile_pipeline`

1

`ast.expr`

▼

Compile pipeline: expr |> filter1 |> filter2.

Pipelines compile to nested filt…

`def _compile_pipeline(self, node: Pipeline) -> ast.expr`

Compile pipeline: expr |> filter1 |> filter2.

Pipelines compile to nested filter calls using the _filters dict,
exactly like regular filter chains. The difference is purely syntactic.

expr |> a |> b(x) → _filters['b'](_filters'a' (expr), x)

Validates filter existence at compile time (same as Filter nodes).

##### Parameters

Name
Type
Description

`node`
`—`

##### Returns

`ast.expr`

`_compile_safe_pipeline`

1

`ast.expr`

▼

Compile safe pipeline: expr ?|> filter1 ?|> filter2.

None-propagating: each st…

`def _compile_safe_pipeline(self, node: SafePipeline) -> ast.expr`

Compile safe pipeline: expr ?|> filter1 ?|> filter2.

None-propagating: each step checks for None before applying the filter.

expr ?|> a ?|> b(x) compiles to:
_sp_2 = None if (_sp_1 := expr) is None else _filters'a' (_sp_1)
None if _sp_2 is None else _filters['b'](_sp_2, x)

##### Parameters

Name
Type
Description

`node`
`—`

##### Returns

`ast.expr`

## Functions

`_is_constant_safe`

1

`bool`

▼

Return True if *value* can be stored in an ``ast.Constant`` node.

`def _is_constant_safe(value: object) -> bool`

##### Parameters

Name
Type
Description

`value`
`object`

##### Returns

`bool`
