lift
Emits a value from inside an anonymous logic block to
the surrounding context. The scrml-flavored
yield
— renamed to avoid collision with JavaScript
generators.
What it means
lift
emits a value from within a
${ }
logic context up to the parent context. The lifted value
is coerced according to the parent's expected type —
markup, CSS, or a scalar (in value-lift mode). Execution
continues after
lift;
it is not a return statement.
Two modes per §10.1:
-
Accumulation mode.
Inside a bare
${ }whose parent is a markup or style context, eachliftappends one item to the block's accumulator array. On block exit, the array is coerced per the parent (per §10.2 coercion table). -
Value-lift mode.
Inside an if-as-expression arm (§17.6), one
liftper arm designates the expression's result. Multiple lifts on a single execution path through one arm firesE-LIFT-002.
Syntax
Statement form:
lift <li value=name>;
Chain form (per §10.3) — equivalent:
users.select(userName).get().lift(<li value=userName>)
Worked example: building markup from an array
The classic accumulation case — one
lift
per loop iteration, accumulator coerced to a markup
sequence by the parent
<ul>:
<contacts> = [
{ name: "Alice", email: "alice@example.com" },
{ name: "Bob", email: "bob@example.com" },
}
<ul>
${ for (let c of @contacts) { lift <li>${c.name} — ${c.email}</li> } }
</ul>
The
${ }
block sits as a child of the markup
<ul>.
Each
lift
appends one
<li>
element to the accumulator. On block exit, the array of
<li>
elements coerces to a markup sequence — rendered
inside the
<ul>.
Worked example: if-as-expression value-lift
An if-as-expression (§17.6) produces a single value
per evaluation. Each arm body contains exactly one
lift
designating that arm's result:
const <message> = ${
if (@count == 0) { lift "no items" }
else if (@count == 1) { lift "one item" }
else { lift "${@count} items" }
}
Notice: the lifted value is NOT accumulated into an array
here. The if-as-expression's surrounding
${ }
is a value-lift context (per §10.2 row 4), not an
accumulation context. The lifted scalar becomes the
const binding's value.
Coercion by parent context
| Parent context | Expected type | Coercion |
|---|---|---|
| Markup | markup[] | Rendered as a markup sequence; non-coercible items are E-TYPE-010. |
Style
#{ } |
cssClass[] | Coerced to CSS class list; non-CSS items are E-TYPE-011. |
| Logic | any | No coercion; passes through as array. |
| If-as-expression arm | scalar | Lifted value IS the expression's result; not accumulated. |
Where
lift
is allowed
lift
is valid in anonymous
${ }
logic blocks and in
fn
bodies (where it accumulates into the fn's
~,
returned via return ~).
It is NOT valid in a bare
function
body. Per §10.4 + §48.5:
-
liftinsidefunction name() { ... }isE-SYNTAX-002. Named functions return markup as a return value; callers lift the return if needed. -
A
fn name { ... }body, by contrast, DOES permitlift— it accumulates into the fn's~and is returned viareturn ~(§48.5). E-SYNTAX-002 fires only on a barefunction. -
liftoutside any${ }context isE-SYNTAX-001. -
Multiple lifts on the same execution path through one
if-as-expression arm is
E-LIFT-002. -
Heterogeneous lifted values that aren't mutually
coercible is
E-TYPE-012.
lift
under markup-as-value
Per §10.1.1, scrml's L1 pillar puts markup as a
first-class value type — markup may sit on the RHS
of any binding (
let,
const,
<x> =,
function returns, function arguments, slot fills).
lift
is one path by which markup becomes a value
— specifically, when the surrounding context is an
anonymous accumulating
${ }.
It is not the only path. Markup-typed derived cells
(§6.6.17), markup-typed function returns, and inline
markup-as-expression all produce markup values without
lift.
Related
-
derived
— markup-typed
const <x> = <markup>is a markup value via reactive binding, noliftinvolved. -
<program>
— the root container; multi-page composition
is via filesystem-routed
<page>, NOTlift.
Specification
Normative text: SPEC §10 in full (semantics §10.1, L1 reframe §10.1.1, coercion §10.2, syntax §10.3, use-site restrictions §10.4) + §17.6 (if-as-expression value-lift). Spec lives at compiler/SPEC.md .