This library is in flux. APIs may change without notice. Generated from source with koruc 0.1.7 on 11/4/2026.
Kernel
import std/kernelKoru Standard Library: Computation Kernels
kernel.kz · 6 tors
Koru Standard Library: Computation Kernels · 38 more lines
// KERNEL.SHAPE - Declare kernel data structure (just metadata, no execution)
//
// Declares the STRUCTURE of kernel data with explicit types.
// This is NOT a transform - it just sits in the AST for kernel.init to look up.
//
// Example:
// std/kernel:shape(Body) { x: f64, y: f64, z: f64, mass: f64 }
~[norun] pub tor shape { expr: Expression, source: Source }// Internal no-op tor for refactored flows
// (This is here for reference; the transform injects a local one into the user program)
~[norun] pub tor nop {}~[comptime|transform|claims_descendants] pub tor init {
expr: Expression,
source: Source,
invocation: *const Invocation,
item: std/compiler:*const Item,
program: std/compiler:*const Program,
reporter: std/compiler:*ErrorReporter,
allocator: std.mem.Allocator
} -> SiteResult~[comptime|transform] pub tor self {
expr: Expression,
source: Source,
invocation: *const Invocation,
item: std/compiler:*const Item,
program: std/compiler:*const Program,
allocator: std.mem.Allocator
} -> SiteResult// Kernel:step - wraps kernel ops in an outer iteration loop
// Kernel:step - wraps kernel ops in an outer iteration loop.
// The proc removes step from the AST after init's fusion consumes it.
~[comptime|transform] pub tor step {
expr: ?Expression,
invocation: *const Invocation,
item: std/compiler:*const Item,
program: std/compiler:*const Program,
allocator: std.mem.Allocator
} -> SiteResult~part body koru_std/kernel.body.kz
Koru Standard Library: the `body` part of kernel.kz. Joined via `~part body` in kernel.kz; merged into the kernel module at load. OP-BODY LOWERING — koru-authored statement text -> host source The ONE Koru expression lowering — see `codegen_utils.lowerKoruExpr`. A kernel OP BODY is Koru expression text the user wrote inside `! step` or `! pairwise`, and this transform splices it into a loop it assembles itself. That route never reached the emitter's lowering, so `@sqrt(dsq)` arrived at `node` with the `@` still on it — even though `js_emitter` has mapped `@sqrt` to `Math.sqrt` all along. The mapping was never missing; the text just never passed the pass. On Zig this is the identity. Refuses by name when the body uses an `@`-operation the vocabulary does not model, so an unrunnable JS kernel is a diagnostic rather than a syntax error in the emitted file.
~part scan koru_std/kernel.scan.kz
Koru Standard Library: the `scan` part of kernel.kz — declaration recovery. Joined via `~part scan` in kernel.kz; merged into the kernel module. These are the init transform's AST scanners: each walks program items (descending `.module_decl`) to recover the text of a declaration the transform needs after the source block is gone — a `std/kernel:shape`'s field list, a `std/store:new` store's SoA schema, a shape source's field text. Module-scope fns (not proc-local struct.call) so the pin on kernel.kz stays under its baseline — the ~part split doctrine. `ast` doesn't exist at module scope in this module (proc bodies keep it local — a module-scope `const ast` would collide under Zig's no-shadowing rule), so the parts share this alias.
~part fields koru_std/kernel.fields.kz
Koru Standard Library: the `fields` part of kernel.kz. Joined via `~part fields` in kernel.kz; merged into the kernel module. The init transform's field-list machinery: the `{ name: value }` texts it consumes — its own data block and the `std/kernel:shape` declaration it recovers — are validated by the shared field parser (the refusal below) and lowered by the comma splitter. Module-scope fns (not proc-local struct.call) so the pin on kernel.kz stays under its baseline — the ~part split doctrine, same as `scan`. `kast` is the shared alias the scan part declares (module-scope `const ast` would collide under Zig's no-shadowing rule); this part uses it without redeclaring — parts merge into one module scope. Helper: transform "x: 42, y: 0" -> ".x = 42, .y = 0" (Zig), "x: 42, y: 0" (JS object literal). A bare comma split — callers must have run the text through kernelInitFieldListRefusal first, or a fused/half-dropped field reaches the emitted static unparsed.
~part fpga koru_std/kernel.fpga.kz
Koru Standard Library: the `fpga` part of kernel.kz — `self|fpga` port shapes. Joined via `~part fpga` in kernel.kz; merged into the kernel module. This file reads the |fpga facet's scoped meet and answers the one question the emitters ask: what port does this field need — bit width, signedness, saturation claim. kernel.fpgaemit.kz turns the answer into the module; kernel.fpgatb.kz into the gating testbench. WIDTH SEMANTICS, ruled refine's own way — bounds judge, clamp normalizes: bare bounds size the port and overflow wraps (the bench notes "truncated"); a `clamp(lo,hi)` term in the meet claims the boundary saturates, so the emitter generates saturating logic and the bench notes "saturated". SIGNEDNESS is read the same way: a met range that admits negatives (`lo < 0` after clamp intersection, `== -N`, or an unbounded i64) is a signed port; `lo >= 0` is unsigned. The host stays unbounded i64 either way — divergence prints, never silently. `kast` is kernel.scan.kz's `ast` import — module-scope, shared. A `std/proto`-door invocation naming `name`? Local copy of refine's own test — this part reaches koru_refine only through the guarded `metFields` fold call below.
~part fpgatb koru_std/kernel.fpgatb.kz
Koru Standard Library: the `fpgatb` part of kernel.kz — the `self|fpga` testbench emission (`~part fpgatb`, merged into the kernel module): drive the init dataset, check ports one beat later, `$fatal` on a miss. Port semantics mirror the module's: `expw_*` computes the map signed-wide (sign- or zero-extending `in_*` to match), bare bounds slice to the port — "truncated"; a clamp claim saturates `exp_*` into the effective range — "saturated". Divergence prints, never silently.
~part fpgaemit koru_std/kernel.fpgaemit.kz
Koru Standard Library: the `fpgaemit` part of kernel.kz — `self|fpga` module emission. Joined via `~part fpgaemit` in kernel.kz; merged into the kernel module. kernel.fpga.kz owns the facet read (ports, sat claims); this file turns it into `<sym>.fpga.sv` — one pipeline stage: the mapped field combinational, every other field passed through, one register. kernel.fpgatb.kz emits the bench that gates it; Stage D's emitted build globs `*.fpga.sv`, runs iverilog + vvp + yosys check. Signed ports (`logic signed [W-1:0]`) come from met ranges admitting negatives; the wide/sat map sign-extends them, zero-extends unsigned ones — a wrong extension is a wrong circuit, not a detail. Emit `<sym>.fpga.sv` into the build root, then delegate the testbench (kernel.fpgatb.kz). The body is already parsed by the caller into (field, op, lit); every other shape field passes the stage through.
~part pairwise koru_std/kernel.pairwise.kz
Koru Standard Library: the `pairwise` part of kernel.kz. Joined via `~part pairwise` in kernel.kz; merged into the kernel module. The pairwise transform: triangular i<j pair iteration over kernel data, emitted as block-scoped `while` loops (measured 2026-10-23 on clbg_nbody: while-spelling 0.63s vs for-spelling 0.66s, checksum-identical). KERNEL.PAIRWISE - Pairwise iteration over kernel data (TRANSFORM) Iterates over all unique pairs (i, j) where i < j. The kernel variable becomes "self" and .other refers to the paired element. Example: std/kernel:pairwise { bodies.vel -= d * mag * bodies.other.mass bodies.other.vel += d * mag * bodies.mass } Generated code: const __kernel_pair = struct { inline fn call(noalias b1: *@TypeOf(bodies.ptr[0]), noalias b2: *@TypeOf(bodies.ptr[0])) void { b1.vel -= d * mag * b2.mass; b2.vel += d * mag * b1.mass; } }; for (0..bodies.len) |i| { for (i+1..bodies.len) |j| { __kernel_pair.call(&bodies.ptr[i], &bodies.ptr[j]); } }
~[comptime|transform] pub tor pairwise {
expr: ?Expression,
source: Source,
invocation: *const Invocation,
item: std/compiler:*const Item,
program: std/compiler:*const Program,
allocator: std.mem.Allocator
} -> SiteResult