Skip to content
View source

Kernel syntaxGenerated

How a Kernel is written in .ent: its declarations and expressions.

Name Kind Syntax
and expression a && b a || b !a
array expression [a, b, c] [value; n] a[i]
break expression loop n with x = init { if done { break x; } next }
budget kernel budget 100000;
compute kernel compute { return value; }
each expression [each n { body }]
enum kernel type Mode = enum { Idle, Walk, Attack = 10, Guard }; Mode.Walk match m { Mode.Idle => a, Mode.Walk | Mode.Attack | Mode.Guard => b }
fn kernel fn name(a: Float) -> Float {... } fn name<T>(a: T) -> T {... }
group kernel group 64 { let mine = f(element()); return exchange(mine, lane() ^ 1); }
if expression if condition { a } else { b } if condition { return a; }
input kernel input x: Image; = "atlas.png"; = text "ENTELECHY"; = frames "clip/" at 30;
kernel kernel kernel id@version { requires {... } input... output... compute {... } }
let expression let name = expr; let { x, y: top } = value;
loop expression loop n with x = init until done { next }
match expression match i { 0 => a, 1 | 2 => b, 8..16 => c, 16..=31 => d, _ => e }
memory kernel memory ram: Rows<Int>; put(ram, address, value)
merge kernel compute over source {... } merge(a, b) {... }
operators expression a + b a - b a * b a / b a % b a << b a >> b a >>> b a & b a ^ b a | b a == b a != b a < b a <= b a > b a >= b
output kernel output result: Grid<Vec4>; output shown <- node.port; output kept <- node.port to "saves/n.field";
param kernel param gain: Float = 1.0;
prefix kernel prefix over flags with sum { return value; }
requires kernel requires { field.read; field.write; time.read; input.read; }
reserved document let return if else match loop with until break
scan kernel scan over ticks with y = init { return next; }
scatter kernel scatter over source into target with sum { return Pair { at: address, value: v }; }
struct expression Name { a: 1.0, b: 2 } Name {..base, a: 3.0 }
type kernel type Cells = Grid<Int>; struct Cell { alive: Int; age: Float; }
a && b a || b !a

Truth: && and || ask the other side only where the first settles nothing, so a guard guards and what it guards does not run.


[a, b, c] [value; n] a[i]

A fixed-size array of one element type, or n copies of a value; a[i] takes an element, clamped, and a literal index is checked when compiled.


loop n with x = init { if done { break x; } next }

Among a loop body’s statements: the loop stops after this iteration and gives that value, which is of the type it carries; the iterations after it do not run, and a break belongs to the innermost loop around it.


budget 100000;

The loop iterations one element may run (a step of a scan, a merge of a reduction), 16777216 unless declared, a loop’s added as it finishes; an element past it fails the evaluation on every backend, as an overflow does, and the running system keeps its last state. A run of all the elements together is bounded by the Host (--work).


compute { return value; }

The map mode: the body runs once per element of the node’s domain and gives that element.


[each n { body }]

An array built element by element, the body run once per element with index() its position; a loop inside the body has its own index().


type Mode = enum { Idle, Walk, Attack = 10, Guard }; Mode.Walk match m { Mode.Idle => a, Mode.Walk | Mode.Attack | Mode.Guard => b }

Named Ints: a variant is the number written after it, else one past the variant before it, the first 0, so Mode.Guard is 11; no two are one number. Mode is a type a value, a field, a port’s element and a parameter may have, and a scene writes a variant where it writes a number. A variant whose number is kept in state, a memory or a file, is written with its number, so no variant written before it moves it.


fn name(a: Float) -> Float {... } fn name<T>(a: T) -> T {... }

A function of the document or the Kernel; a call reaches the Kernel’s own, then the document’s own, or else the one a document it uses declares; it calls others in any order, but no chain of calls comes back to it, and it may take a Field parameter. A <T> names a type parameter, bound by the type of the argument written for it, and one instance is compiled per set of types a call gives it.


group 64 { let mine = f(element()); return exchange(mine, lane() ^ 1); }

The group mode: a map whose elements run in groups of the size written (1 to 256), element e lane e % size of group e / size, the lanes of a group meeting at each exchange. The last group runs whole past the domain’s end, its lanes there giving at exchanges, failing as any element fails, and writing nothing.


if condition { a } else { b } if condition { return a; }

Both arms give one type and only the arm taken runs, which a trace shows; with no else, among a block’s statements, it guards, and the rest of the block is its other arm.


input x: Image; = "atlas.png"; = text "ENTELECHY"; = frames "clip/" at 30;

In a Kernel, a Field it reads, bound by the node that runs it (source <- other.result;); in a scene, a Field the caller supplies, or one the Host reads from a file, from text, frame by frame from a directory, every file under a directory with its path, or what the language finds wrong in, or defined by, a file’s or a directory’s documents, as text; or one a Host device feeds, named after = (= clipboard, = progress), refused as the scene loads when the Host has no such device or it gives another type.


kernel id@version { requires {... } input... output... compute {... } }

A Kernel: what it needs, its ports and parameters, and one of compute, scan, scatter, prefix or group.


let name = expr; let { x, y: top } = value;

A binding, immutable and scoped to its block; let _ = put(...) is a statement for its effect. A {... } names fields of one value instead, each under its own name or the one written after :.


loop n with x = init until done { next }

A bounded fold: n is a literal, which is its bound (at most 65536), or any Int expression read once and run whole, the element’s budget its bound; index() is the iteration, and until stops it early, as break does from inside.


match i { 0 => a, 1 | 2 => b, 8..16 => c, 16..=31 => d, _ => e }

On an Int: the arm whose values hold it, else the _ arm, which comes last; arms naming every variant of an enum need none, and a value that is no variant takes the last arm. The GPU runs it as a switch. A range is the values it holds, .. stopping before its end and ..= taking it, at most 256 to an arm.


memory ram: Rows<Int>; put(ram, address, value)

A port an ordered Kernel both reads and writes, step by step; it comes out as an output.


compute over source {... } merge(a, b) {... }

The reduce mode: compute runs per element of the input it names after over and merge folds the results pairwise into one element; the output may be written as its element type.


a + b a - b a * b a / b a % b a << b a >> b a >>> b a & b a ^ b a | b a == b a != b a < b a <= b a > b a >= b

Arithmetic on numbers and, component by component, vectors, / and % on Ints truncating toward zero; on Ints only, <<, >> keeping the sign, >>> filling with zeros, and &, ^, | bit by bit; a comparison gives a Bool. From the tightest: unary - and !; * / %; + -; the shifts; &; ^; |; the comparisons; &&; ||.


output result: Grid<Vec4>; output shown <- node.port; output kept <- node.port to "saves/n.field";

In a Kernel, a Field it writes, an element per element of its domain (a map may write several); in a scene, a named result: the first picture given no device is what it shows; one given to a Host device by its name goes there (to sound, a block of samples each frame joined to the last, rate() over the frame rate keeping it in time; to pointer, to pointer_tip, to clipboard; a name the Host has not, or a Field of another structure, is refused with what the device takes); one written to a file is saved after each evaluation that changed it, where allowed; one written to files a directory is a list of operations on its files (write, remove, rename), done once each time it changes.


param gain: Float = 1.0;

In a Kernel, a value the node that runs it may set (gain = 0.5;), with its default; in a scene, a value the caller sets (--param, the protocol’s param) and its nodes read by name.


prefix over flags with sum { return value; }

The prefix mode: the body runs once per element of the input it names after over, a Rows, and that element of the output is its value combined with every value before it by sum, min or max. The rule must give one answer whatever order it is folded in, so a float sum is refused (a scan walks that in element order) and a device folds the row in blocks rather than walking it.


requires { field.read; field.write; time.read; input.read; }

The capabilities a Kernel uses, and no others: reading inputs, writing outputs, the clock, the pointer, keys and window.


let return if else match loop with until break

The words the language keeps for itself, each beginning a statement or an expression or going between its parts: a Kernel, node, port, param, function, struct or binding may not be named one. The words that begin items (kernel, input, type, from and the rest) name things anywhere else; a Kernel’s param is not named domain or async, which a node sets itself.


scan over ticks with y = init { return next; }

The ordered mode: one element per element of the input it names after over, in order, carrying y from the step before; memory ports are read and written step by step.


scatter over source into target with sum { return Pair { at: address, value: v }; }

The scatter mode: the body runs once per element of the node’s domain, which has the shape of the input it names after over (element() and coord() read it), and gives a struct the document declares, of two fields, an address into the target and a value of its element (struct Pair { at: Int; value: Float; }); the value is combined into the target at the address with sum, min, max or last, in element order.


Name { a: 1.0, b: 2 } Name {..base, a: 3.0 }

A value of a declared struct, or a copy of one with some fields replaced.


type Cells = Grid<Int>; struct Cell { alive: Int; age: Float; }

A name for a port type, an enum, or a struct of named fields, shared by the Kernels of a document.