docs/language: a page for every keyword and attribute the vocabulary has

Keywords: module uses friend export internal numbers unsafe mut port bind action
reducer registry of as from def open alias component prop view (structure),
shows lasts then loads (scenes), system (ecs), dispatch (control), true false
null (operators). Attributes: @Ref @OneOf @Range @Unit @Asset @Color, @Node /
@Clip / @Material, @Tint @Derived, @Text / @Multiline, @Key, @AppendOnly /
@ByKey, @PerMap / @Chunked, @frame @max, @owns / @creates / @releases,
@deterministic @alloc_ok. Each is in tools/docgen/inventory.json; every fence
that is not marked skip parses (ludicc --fmt). annot-clearcolor's token loses its
quotes, which no reader strips.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Orkun ÇAKILKAYA 2026-09-29 23:59:47 +03:00
parent eb2d6106af
commit e2528c1b10
49 changed files with 746 additions and 7 deletions

View file

@ -0,0 +1,12 @@
---
id: annot-alloc_ok
name: @alloc_ok
category: annotations
kind: annotation
tokens: @alloc_ok
sig: @alloc_ok("why") function f() / @alloc_ok("why") statement
tip: Allocates in a frame on purpose; the reason is required.
order: 80
---
<code>@alloc_ok("a memo miss, bounded by MM_CAP")</code> on a function or a single statement marks an allocation reachable from a frame as deliberate: the fence lets it through and <code>ludic deps</code> does not count it. The reason is required and greppable.

View file

@ -0,0 +1,18 @@
---
id: annot-appendonly
name: @AppendOnly
category: annotations
kind: annotation
tokens: @AppendOnly @ByKey
sig: @AppendOnly @ByKey registry Name of Record ...
tip: How a registry's entries may change: only appended (their index is saved), or saved by key.
order: 74
---
<code>@AppendOnly</code> on a registry says an entry's index is stored somewhere that outlives the build, so entries are only ever appended; <code>@ByKey</code> says entries are saved by key, so their order is free. Editors keep to what each says.
```ludic
# doc-check: skip — the file it names is beside the example
@AppendOnly @ByKey
registry Tools of Tool as TL from "data/tools.lres"
```

View file

@ -0,0 +1,12 @@
---
id: annot-asset
name: @Asset
category: annotations
kind: annotation
tokens: @Asset
sig: @Asset("kind"[, map[, optional]]) field: string = ""
tip: A path to a file of that kind; with map, under each map's directory.
order: 67
---
<code>@Asset("gltf")</code> says a string field names a file of that kind. With <code>map</code> the path is under each map's directory and <code>ludicc --check</code> looks for it in every map, refusing one that lacks it unless the field says <code>optional</code>.

View file

@ -3,7 +3,7 @@ id: annot-clearcolor
name: "@ClearColor"
category: annotations
kind: annotation
tokens: "@ClearColor"
tokens: @ClearColor
sig: "@ClearColor(0xRRGGBB) handler Draw phase Render { … }"
tip: Declare a clear colour so the Render phase auto-clears + auto-presents for you.
order: 62

View file

@ -0,0 +1,12 @@
---
id: annot-color
name: @Color
category: annotations
kind: annotation
tokens: @Color
sig: @Color field: int = 0
tip: The field is a colour.
order: 68
---
<code>@Color</code> marks an <code>int</code> field as a colour so an editor shows a swatch and a picker; with <code>@Tint(SLOT)</code> beside it the colour is for that tint slot.

View file

@ -0,0 +1,12 @@
---
id: annot-derived
name: @Derived
category: annotations
kind: annotation
tokens: @Derived
sig: @Derived field: float = 0.0
tip: Worked out at boot: anything written in the data is overwritten.
order: 71
---
<code>@Derived</code> tells an editor a field is computed when the game starts, so a value typed into the data would be overwritten and is not offered for editing.

View file

@ -0,0 +1,12 @@
---
id: annot-deterministic
name: @deterministic
category: annotations
kind: annotation
tokens: @deterministic
sig: @deterministic function f() { }
tip: No floating point inside: it must replay the same everywhere.
order: 79
---
<code>@deterministic</code> on a function or a handler refuses floating point inside it, so it computes the same bits on every machine - what lockstep and replays need.

View file

@ -0,0 +1,12 @@
---
id: annot-frame
name: @frame
category: annotations
kind: annotation
tokens: @frame
sig: @frame field: fn() -> void
tip: A fn stored here runs every frame.
order: 76
---
<code>@frame</code> on a function-typed field says whatever function it holds runs every frame, so <code>ludic deps</code> counts what it can allocate among the frame's allocations.

View file

@ -0,0 +1,12 @@
---
id: annot-key
name: @Key
category: annotations
kind: annotation
tokens: @Key
sig: @Key field: int = 0
tip: The field is a key code.
order: 73
---
<code>@Key</code> marks an <code>int</code> field as a key code, so an editor offers a key to press rather than a number.

View file

@ -0,0 +1,18 @@
---
id: annot-max
name: @max
category: annotations
kind: annotation
tokens: @max
sig: @max(64) rows: []Row
tip: The most a list may hold; growing past it fails the run.
order: 77
---
<code>@max(n)</code> bounds a list field: it never holds more than <code>n</code>, and a push past it fails the run (exit 87) rather than growing a list that should not grow.
```ludic
property Log {
@max(64) lines: []int
}
```

View file

@ -0,0 +1,12 @@
---
id: annot-node
name: @Node
category: annotations
kind: annotation
tokens: @Node @Clip @Material
sig: @Node(model) / @Clip(model) / @Material(model) field: string = ""
tip: A node, an animation clip or a material inside the glTF another field names.
order: 69
---
<code>@Node(model)</code>, <code>@Clip(model)</code> and <code>@Material(model)</code> say a string field names a node, a clip or a material inside the glTF that field <code>model</code> of the same record names (an <code>@Asset("gltf")</code> field, or an <code>@Ref</code> to a registry whose record has exactly one). Naming anything else is an error.

View file

@ -0,0 +1,12 @@
---
id: annot-oneof
name: @OneOf
category: annotations
kind: annotation
tokens: @OneOf
sig: @OneOf(PREFIX_) / @OneOf(A, B) / @OneOf("word", ...)
tip: The field holds one of these constants or words.
order: 64
---
<code>@OneOf(GR_)</code> says a field holds one of the constants whose names start <code>GR_</code>; <code>@OneOf(GR_GOLD, GR_SILVER)</code> one of those (each must exist); on a <code>string</code> field, <code>@OneOf("box", "hull")</code> one of those words, and every registry row is checked against them.

View file

@ -0,0 +1,12 @@
---
id: annot-owns
name: @owns
category: annotations
kind: annotation
tokens: @owns @creates @releases
sig: @owns(Kind) field / @creates(Kind) function / @releases(Kind) function
tip: Resource handles: a field that owns one, a function that makes one, a function that lets one go.
order: 78
---
<code>@creates(PhysShape)</code> on a function says it returns a handle the caller must release, <code>@releases(PhysShape)</code> that it releases one, and <code>@owns(PhysShape)</code> on a field that its record owns the handle it holds. <code>ludic deps --resources</code> counts a created handle never released, and an owned one lost when its record is released.

View file

@ -0,0 +1,12 @@
---
id: annot-permap
name: @PerMap
category: annotations
kind: annotation
tokens: @PerMap @Chunked
sig: @PerMap registry Name of Row from "rows.lres" / @PerMap @Chunked(n) registry ...
tip: A table whose rows are read per map from that map's directory; @Chunked(n) reads it a chunk at a time.
order: 75
---
A <code>@PerMap</code> registry holds what is on a map rather than in the game: its rows are read when a map loads, from that map's directory, into a state the compiler writes with its verbs (<code>_load</code>, <code>_find</code>, ...). <code>@Chunked(n)</code> reads it in n-by-n-metre chunks from files named by <code>{cx}</code> and <code>{cz}</code>.

View file

@ -0,0 +1,12 @@
---
id: annot-range
name: @Range
category: annotations
kind: annotation
tokens: @Range
sig: @Range(lo, hi) field: float = 0.0
tip: The least and the most the value may be.
order: 65
---
<code>@Range(0, 20.5)</code> gives an editor the bounds of a number field, and <code>ludicc --check</code> holds every map row's value to them. Both arguments are numbers.

View file

@ -0,0 +1,19 @@
---
id: annot-ref
name: @Ref
category: annotations
kind: annotation
tokens: @Ref
sig: @Ref(Registry) field: int = 0
tip: The field is an entry of that registry: an index, or a key for a @PerMap one.
order: 63
---
<code>@Ref(Items)</code> on a field says its value is an entry of the registry <code>Items</code> - its index on an <code>int</code> field, its key on a <code>string</code> field of a <code>@PerMap</code> table - so an editor offers the entries. It changes nothing the program does; a registry the program does not declare is a warning and <code>"unresolved"</code> in the schema, anything else of that name is an error.
```ludic
# doc-check: skip — the registry is declared elsewhere
property Tool {
@Ref(Vendors) seller: int = 0
}
```

View file

@ -0,0 +1,12 @@
---
id: annot-text
name: @Text
category: annotations
kind: annotation
tokens: @Text @Multiline
sig: @Text @Multiline field: string = ""
tip: Read by the player, so translated; and prose, edited over several lines.
order: 72
---
<code>@Text</code> marks a string the player reads, so it is translated; <code>@Multiline</code> says it is prose, edited as several lines rather than one.

View file

@ -0,0 +1,12 @@
---
id: annot-tint
name: @Tint
category: annotations
kind: annotation
tokens: @Tint
sig: @Color @Tint(SLOT) field: int = 0
tip: A colour for that tint slot.
order: 70
---
<code>@Tint(TSLOT_HAIR)</code> names the tint slot a colour field paints - a constant, which must exist (or, when the program lacks it, is a warning and unresolved).

View file

@ -0,0 +1,12 @@
---
id: annot-unit
name: @Unit
category: annotations
kind: annotation
tokens: @Unit
sig: @Unit("m/s") field: float = 0.0
tip: The value's unit, in one canonical ASCII spelling.
order: 66
---
<code>@Unit</code> takes one of <code>m</code>, <code>m/s</code>, <code>m/s2</code>, <code>s</code>, <code>min</code>, <code>h</code>, <code>d</code>, <code>deg</code>, <code>rad</code>, <code>rad/s</code>, <code>kg</code>, <code>N</code>, <code>N.m</code>, <code>%</code>, <code>px</code>, so one word means one unit to an editor; another spelling is a warning naming the canonical one.

View file

@ -0,0 +1,17 @@
---
id: kw-dispatch
name: dispatch
category: control
kind: keyword
tokens: dispatch
sig: dispatch Action(field: value, ...)
tip: Queues an action for the reducers declared on it.
order: 13
---
<code>dispatch Move(dx: 1)</code> queues an action; at the end of the frame phase every <code>reducer</code> on <code>Move</code> applies it to its own state, in the order of the states' names. Input code and a screen's buttons dispatch; they never write another module's state.
```ludic
# doc-check: skip — the action is declared elsewhere
dispatch Move(dx: 1)
```

View file

@ -0,0 +1,12 @@
---
id: kw-system
name: system
category: ecs
kind: keyword
tokens: system
sig: disable system SystemFunction
tip: Leaves an engine system out at compile time.
order: 51
---
<code>disable system S</code> names a package's engine system (declared with <code>@EngineSystem</code>) and leaves it out of the program at compile time, for a game that drives that component itself.

View file

@ -0,0 +1,12 @@
---
id: kw-true
name: true
category: operators
kind: keyword
tokens: true false null
sig: true false null
tip: The boolean literals, and the absent record, slice or string.
order: 13
---
<code>true</code> and <code>false</code> are the two <code>bool</code> values; <code>null</code> is no record, no slice and no string - what an unset reference field holds and what a lookup that finds nothing returns.

View file

@ -0,0 +1,12 @@
---
id: kw-lasts
name: lasts
category: scenes
kind: keyword
tokens: lasts
sig: scene Name lasts N then Next { }
tip: A timed scene: after N seconds it moves on.
order: 52
---
<code>lasts N then Next</code> makes a scene timed - a banner, a splash - that moves to <code>Next</code> by itself once <code>N</code> seconds have passed.

View file

@ -0,0 +1,12 @@
---
id: kw-loads
name: loads
category: scenes
kind: keyword
tokens: loads
sig: scene Name loads then Next { }
tip: A loading scene: pumps the asset queue with a bar, then moves on.
order: 54
---
<code>loads then Next</code> makes a scene the loading screen: the engine pumps the asset queue, draws a progress bar and enters <code>Next</code> when everything queued is ready.

View file

@ -0,0 +1,12 @@
---
id: kw-shows
name: shows
category: scenes
kind: keyword
tokens: shows
sig: scene Name shows Menu { }
tip: The ui this scene opens, renders and closes by itself.
order: 51
---
<code>shows Menu</code> in a scene's header hands a <code>ui</code> to the engine: it is opened when the scene is entered, drawn every frame and closed when it is left, so the scene needs no handler for it.

View file

@ -0,0 +1,12 @@
---
id: kw-then
name: then
category: scenes
kind: keyword
tokens: then
sig: scene Name lasts N then Next / scene Name loads then Next
tip: The scene a timed or loading scene moves on to.
order: 53
---
<code>then</code> names where a scene goes when it is done: after the time of a <code>lasts</code> scene, or once a <code>loads</code> scene's assets are ready.

View file

@ -0,0 +1,16 @@
---
id: kw-action
name: action
category: structure
kind: keyword
tokens: action
sig: action Name { field: Type, ... }
tip: What the player asked for, dispatched and applied by each state's reducer.
order: 61
---
An <code>action</code> is a record that says what was asked for in the game's words (<code>Move</code>, <code>OpenPack</code>). Input code <code>dispatch</code>es it, and every <code>reducer</code> declared on it changes its own state. The queue drains at the end of every frame phase, each action's reducers in the order of their states' names.
```ludic
action Move { dx: int = 0, dy: int = 0 }
```

View file

@ -0,0 +1,19 @@
---
id: kw-alias
name: alias
category: structure
kind: keyword
tokens: alias
sig: namespace Name { alias method = function_name }
tip: A namespace method that is another function.
order: 69
---
Inside a <code>namespace</code> block, <code>alias m = f</code> makes <code>Name.m(...)</code> a call of <code>f</code>, checked against its parameters. It is how an engine namespace declared in Ludic forwards to the functions that implement it.
```ludic
# doc-check: skip — the aliased function lives elsewhere
namespace Trail {
alias length = trail_length
}
```

View file

@ -0,0 +1,12 @@
---
id: kw-as
name: as
category: structure
kind: keyword
tokens: as
sig: registry Name of Record as PREFIX
tip: The prefix of a registry's generated constants.
order: 65
---
<code>as P</code> after a registry's record makes the compiler write a constant for each entry, <code>P_KEY</code> in upper case, holding the entry's index - so code reads <code>IT_ROPE</code> rather than looking the key up.

View file

@ -0,0 +1,17 @@
---
id: kw-bind
name: bind
category: structure
kind: keyword
tokens: bind
sig: bind Port { member: function_name, ... }
tip: The program's answers to a port: one function per member.
order: 60
---
<code>bind</code> answers a <code>port</code>: each member names a function of the member's type. It is written once, where the program is put together, and it is the only code that knows both the asking module and the one that answers.
```ludic
# doc-check: skip — a module spans files
bind ClockWorld { rest_scale: party_rest_scale }
```

View file

@ -0,0 +1,21 @@
---
id: kw-component
name: component
category: structure
kind: keyword
tokens: component
sig: component Name[(states)] { prop p: T = v, state s: T = v, function ..., on e(...) { } }
tip: A UI component: its props, state, functions and events, beside Name.xml and Name.lss.
order: 70
---
A <code>component</code> is a piece of interface: the code file declares its <code>prop</code>s (handed in by its parent), its own <code>state</code>, the functions its template calls and the events it handles with <code>on</code>; <code>Name.xml</code> beside it is its template and <code>Name.lss</code> its styles. The states named in its header are supplied by the runtime and never seen by the template.
```ludic
# doc-check: skip — a component needs its template beside it
component Counter {
prop step: int = 1
state count: int = 0
on add() { count = count + step }
}
```

View file

@ -0,0 +1,17 @@
---
id: kw-def
name: def
category: structure
kind: keyword
tokens: def
sig: def Registry key { field: value, ... } / def Registry from "file.lres"
tip: Entries of a registry, written in code or read from a resource file.
order: 67
---
<code>def</code> adds entries to a registry: one written inline, or every entry of a resource file. An <code>open</code> registry takes <code>def</code>s from other modules, which is how a package's table gets a game's rows.
```ludic
# doc-check: skip — the registry is declared elsewhere
def Tools lantern { weight: 1.5 }
```

View file

@ -0,0 +1,17 @@
---
id: kw-export
name: export
category: structure
kind: keyword
tokens: export
sig: export function / property / state / registry ...
tip: Makes a declaration visible outside its module.
order: 54
---
<code>export</code> in front of a declaration makes it reachable from other modules; without it a module's names are its own. It works on every declaration - functions, records, states, events, actions, ports, registries, views and components - and <code>@export</code> is the same thing written as an attribute. Export deliberately: a name nobody else asks for stays private.
```ludic
# doc-check: skip — a module spans files
export function balance(b: Bank) -> int { return b.total }
```

View file

@ -0,0 +1,17 @@
---
id: kw-friend
name: friend
category: structure
kind: keyword
tokens: friend
sig: friend module name [of a, b]
tip: A module that sees other modules' private names - the lab, the tests.
order: 53
---
<code>friend module lab</code> declares a module that may name every private name of every module; <code>friend module lab of bank, sky</code> limits it to those. It is for test and staging code that must reach inside a system without the system exporting its internals.
```ludic
# doc-check: skip — a module spans files
friend module lab of bank, sky
```

View file

@ -0,0 +1,12 @@
---
id: kw-from
name: from
category: structure
kind: keyword
tokens: from
sig: registry ... from "file.lres" / def Registry from "file.lres"
tip: The resource file a registry's entries are read from.
order: 66
---
<code>from</code> names the <code>.lres</code> file the compiler reads a registry's entries from, relative to the declaring file (or, in a <code>@PerMap</code> registry, to each map's directory). The entries are checked against the record at build time, and an entry's place in the file is its index.

View file

@ -0,0 +1,19 @@
---
id: kw-internal
name: internal
category: structure
kind: keyword
tokens: internal
sig: namespace Name { internal function helper() { } }
tip: Inside a namespace: a function kept out of the Name.* surface.
order: 55
---
In a <code>namespace</code> block every function is part of the <code>Name.*</code> surface unless it says <code>internal</code>: then it is emitted as an ordinary helper the namespace's own methods can call, and <code>Name.helper</code> is not a method.
```ludic
namespace Trail {
internal function step(n: int) -> int { return n + 1 }
function next(n: int) -> int { return step(n) }
}
```

View file

@ -0,0 +1,19 @@
---
id: kw-module
name: module
category: structure
kind: keyword
tokens: module
sig: module name [in layer L] [uses a, b]
tip: Names the module a directory's files belong to; only what it exports is reachable from outside.
order: 51
---
<code>module</code> opens a directory's barrel (<code>index.ludic</code>) and says which module every file under it belongs to. A name a module does not <code>export</code> is private to it: another module that names it is refused at compile time, which is what makes a private name safe to change. The line may place the module in a layer (<code>in layer L</code>) and say what it may reach (<code>uses</code>).
```ludic
# doc-check: skip — a module spans files
# bank/index.ludic
module bank uses base
import "ledger.ludic"
```

View file

@ -0,0 +1,17 @@
---
id: kw-mut
name: mut
category: structure
kind: keyword
tokens: mut
sig: function f(st: mut State)
tip: A parameter the function may change - how a state is written.
order: 58
---
A state reaches a function only as a parameter: <code>h: HikerState</code> to read it, <code>h: mut HikerState</code> to change it, so a function's signature is everything it touches. The compiler refuses a write through a parameter that is not <code>mut</code>, and <code>ludic migrate state --tighten</code> takes <code>mut</code> off every one nothing down the chain writes.
```ludic
state Counter { n: int = 0 }
function bump(c: mut Counter) -> void { c.n = c.n + 1 }
```

View file

@ -0,0 +1,18 @@
---
id: kw-numbers
name: numbers
category: structure
kind: keyword
tokens: numbers
sig: numbers float
tip: This file's bare decimals are floats.
order: 56
---
<code>numbers float</code> at the top of a file makes a bare decimal such as <code>1.5</code> a <code>float</code> rather than a <code>fixed</code>. Such a file also refuses to promote a computed <code>int</code> silently: write <code>float(n)</code> where a count becomes a number.
```ludic
# doc-check: skip — a file-level line
numbers float
const GRAVITY: float = 9.81
```

View file

@ -0,0 +1,12 @@
---
id: kw-of
name: of
category: structure
kind: keyword
tokens: of
sig: registry Name of Record / friend module m of a, b
tip: Says what a registry holds, or whose private names a friend module sees.
order: 64
---
<code>of</code> names the record a <code>registry</code>'s entries are (<code>registry Tools of Tool</code>), and, on a <code>friend module</code> line, the modules whose private names it may see.

View file

@ -0,0 +1,12 @@
---
id: kw-open
name: open
category: structure
kind: keyword
tokens: open
sig: open registry Name of Record
tip: A registry other modules may add entries to with def.
order: 68
---
An <code>open registry</code> is one whose entries may come from other modules' <code>def</code>s, merged in a deterministic order; a closed one takes entries only from its own module. A package declares its table open so the game can fill it.

View file

@ -0,0 +1,19 @@
---
id: kw-port
name: port
category: structure
kind: keyword
tokens: port
sig: port Name { member: fn(T) -> R [= default], ... }
tip: The questions a module asks the world, bound once by the program.
order: 59
---
A <code>port</code> is what a module needs to ask the world, as named function members in primitive types. The program answers it once with <code>bind</code>; a member left unbound without a default is a compile error. Ports let a package ask a question without reaching into the module that knows the answer.
```ludic
# doc-check: skip — a module spans files
export port ClockWorld {
rest_scale: fn() -> float
}
```

View file

@ -0,0 +1,12 @@
---
id: kw-prop
name: prop
category: structure
kind: keyword
tokens: prop
sig: component Name { prop name: Type = default }
tip: A component's value handed in by its parent.
order: 71
---
<code>prop</code> declares a component member its parent sets from the template (<code>&lt;Counter step="2"/&gt;</code>); <code>state</code> declares one the component keeps for itself. Both are fields of the instance, listed with their types and defaults in <code>ludic schema</code>.

View file

@ -0,0 +1,20 @@
---
id: kw-reducer
name: reducer
category: structure
kind: keyword
tokens: reducer
sig: reducer State on Action(st: mut State, reads..., a: Action) { ... }
tip: Applies an action to one state; it may read others.
order: 62
---
A <code>reducer</code> writes exactly one state when its action is dispatched: the first parameter is that state, <code>mut</code>, the last is the action, and any states between are read-only. A change that must touch several states in a set order is a chain: a reducer dispatches the next action.
```ludic
state Pos { x: int = 0 }
action Move { dx: int = 0 }
reducer Pos on Move(p: mut Pos, a: Move) {
p.x = p.x + a.dx
}
```

View file

@ -0,0 +1,18 @@
---
id: kw-registry
name: registry
category: structure
kind: keyword
tokens: registry
sig: [open] registry Name of Record [as PREFIX] [from "file.lres"]
tip: A table of named entries of one record type, with a constant per entry.
order: 63
---
A <code>registry</code> is a table of named entries of one record: its entries come from <code>def</code> declarations or a resource file named by <code>from</code>, and <code>as P</code> generates a constant <code>P_KEY</code> per entry holding its index. Editors read it through <code>ludic schema</code>, and attributes such as <code>@AppendOnly</code> and <code>@PerMap</code> say how its entries may change and where they live.
```ludic
# doc-check: skip — the file it names is beside the example
property Tool { key: string = "", weight: float = 0.0 }
registry Tools of Tool as TL from "data/tools.lres"
```

View file

@ -0,0 +1,17 @@
---
id: kw-unsafe
name: unsafe
category: structure
kind: keyword
tokens: unsafe
sig: unsafe function f() { } / unsafe { ... }
tip: Raw memory is allowed inside: bytes(), free, Memory.*, indexing a pointer, calling C.
order: 57
---
Ludic's memory is safe unless code says <code>unsafe</code>: raw allocation, freeing, pointer indexing and foreign calls are compile errors elsewhere. An <code>unsafe function</code> or an <code>unsafe { ... }</code> block allows them inside, and only packages and the runtime are trusted to write it; a program's own files need <code>--unsafe</code>.
```ludic
# doc-check: skip — needs --unsafe
unsafe function raw(n: int) -> pointer { return bytes(n) }
```

View file

@ -0,0 +1,17 @@
---
id: kw-uses
name: uses
category: structure
kind: keyword
tokens: uses
sig: module name uses a, b, c
tip: The modules a module may reach; a reach not on the line is a compile error that names the fix.
order: 52
---
<code>uses</code> ends a <code>module</code> line with the modules its files may name. The compiler holds the module to that list and refuses a list that goes round: when adding a module would make a cycle, the question goes through a <code>port</code> the asker declares and the program binds instead.
```ludic
# doc-check: skip — a module spans files
module sky uses base, events, clock
```

View file

@ -0,0 +1,20 @@
---
id: kw-view
name: view
category: structure
kind: keyword
tokens: view
sig: view Name[(states)] { field = expr, function q(...), on e(...) { } }
tip: The bridge to a template: what it may read and what it may do.
order: 72
---
A <code>view</code> says what a template may read (its fields, each an expression) and what it may do (its queries and its <code>on</code> events), and nothing else crosses. The compiler writes <code>view_name()</code>, whose model is a value object of every field and whose call runs a query or an event by name.
```ludic
# doc-check: skip — the functions it names are elsewhere
view Yard {
spots: int = yard_spots()
on buy(hf: int) { yard_buy(hf) }
}
```

View file

@ -25,7 +25,25 @@
"annot-system",
"annot-enginesystem",
"annot-namespace",
"annot-clearcolor"
"annot-clearcolor",
"annot-alloc_ok",
"annot-appendonly",
"annot-asset",
"annot-color",
"annot-derived",
"annot-deterministic",
"annot-frame",
"annot-key",
"annot-max",
"annot-node",
"annot-oneof",
"annot-owns",
"annot-permap",
"annot-range",
"annot-ref",
"annot-text",
"annot-tint",
"annot-unit"
],
"builtins": [
"fn-print",
@ -86,7 +104,8 @@
"kw-machine",
"kw-state",
"kw-become",
"kw-try"
"kw-try",
"kw-dispatch"
],
"ease": [
"ease-in",
@ -119,7 +138,8 @@
"fn-world_register_prop",
"fn-world_attach_dyn",
"fn-world_detach_dyn",
"fn-world_query_next"
"fn-world_query_next",
"kw-system"
],
"events": [
"kw-event",
@ -211,7 +231,8 @@
"op-access",
"op-interp",
"op-literals",
"op-comment"
"op-comment",
"kw-true"
],
"phases": [
"phase-fixedupdate",
@ -240,7 +261,11 @@
"kw-on",
"kw-enter",
"kw-exit",
"kw-start"
"kw-start",
"kw-lasts",
"kw-loads",
"kw-shows",
"kw-then"
],
"screen": [
"screen-clear",
@ -276,7 +301,29 @@
"kw-extern",
"kw-ui",
"kw-enum",
"kw-namespace"
"kw-namespace",
"kw-action",
"kw-alias",
"kw-as",
"kw-bind",
"kw-component",
"kw-def",
"kw-export",
"kw-friend",
"kw-from",
"kw-internal",
"kw-module",
"kw-mut",
"kw-numbers",
"kw-of",
"kw-open",
"kw-port",
"kw-prop",
"kw-reducer",
"kw-registry",
"kw-unsafe",
"kw-uses",
"kw-view"
],
"system": [
"system-run",