This library is in flux. APIs may change without notice. Generated from source with koruc 0.1.7 on 11/4/2026.
Ctx
import std/ctxKoru Standard Library: ctx — lexical scope injection.
ctx.kz · 1 tors
Koru Standard Library: ctx — lexical scope injection. · 52 more lines
Koru Standard Library: ctx — lexical scope injection.
|> std/ctx(outer) |> my/verbs:probe()
|> std/ctx(inner) |> my/verbs:probe()
`std/ctx(X)` is the module's `default` tor — a bare-name attach, same
convention as `std/store(game)` / `std/pump(main)`. A `ctx(X)` step is a
compile-time scope: the transform walks its continuation subtree and, for
every invocation, fills params the call left unfilled from the nearest
enclosing scope providing a field of the same name AND a type that fits
the param — the author spelling `call()` while the emitted call reads
`call(a: inner.a, b: outer.b)`. Scope = downstream continuation subtree,
so a linear `ctx(A) |> ctx(B) |> call()` chain shadows A with B for the
call; arms, conditionals, and nested chains all inherit. The ctx step
itself is spliced out — zero runtime cost: injection is argument-filling
at compile time, nothing resolves at run.
precedence: explicit arg > innermost compatible ctx > outward ctx >
declared default > ordinary missing-param refusal (automatic — nothing
new)
Matching is name + exact canonical type: a same-named column whose type
cannot serve the param does NOT shadow — it falls through to outer
scopes, so `ctx(inner) |> ctx(outer)` with `inner.a:f64`/`outer.a:i64`
feeds `a: i64` params from outer and `a: f64` params from inner. A param
no compatible scope provides stays unfilled and refuses through the
ordinary missing-input path.
TODO(projection): scope spelling is planned to take a capture-shaped map —
`std/ctx { fs: theme[r].fs, sel: docs[cur] }` — presenting names bound to
arbitrary backing exprs (ScopeBinding's {name, type, value_ref} shape).
Types resolve off store-field paths; arbitrary exprs need inference or an
explicit type in the map. Clone keys + free-var lifting follow the same
rules as subscripted scopes.
TRANSITIVITY — the scope crosses the subflow boundary. When a call under
a scope targets a koru-bodied tor whose body (transitively) consumes a
scope field, the callee is cloned keyed on the scope stack:
`ctx(inner) |> needs-scope()` emits `needs-scope__ctx_inner`, whose body
is the original's with injection applied under the stack. Free variables
in scope expressions lift into clone params — `ctx(themes[i])` produces
`themes[__ctxarg0]` inside the clone, bound per call site — so `themes[i]`
and `themes[j]` share one clone. Host-proc tors have no body to clone;
their declared inputs still inject at the call site.
The scope value is a source expression naming a store — `world`,
`themes[h]`, `cfg`. Which fields a scope provides is read off the schema
of the store it names (the `std/store:new` seed block — name AND column
type); a scope that names no store provides nothing. Calls whose decl has
no input shape in this program pass through untouched.
Promoted from the libs/ctx experiment (koru-libs commit 60b20a3).
~[keyword|comptime|transform|pre_late] pub tor default {
expr: Expression,
invocation: *const Invocation,
item: *const Item,
program: *const Program,
allocator: std.mem.Allocator
} -> SiteResult~part finish koru_std/ctx.finish.kz
Koru Standard Library: the `finish` part of ctx — the clone drain and whole-program finish for `ctx:default`. Joined via `~part finish` in ctx.kz; merged into the ctx module at load. Recursive orig lookup for clone synthesis — the template decl and its impl flow may live inside a module_decl. Returns the decl, the impl flow, and the owning module's canonical path ("" = top level).