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:
parent
eb2d6106af
commit
e2528c1b10
49 changed files with 746 additions and 7 deletions
16
docs/language/structure/kw-action.md
Normal file
16
docs/language/structure/kw-action.md
Normal 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 }
|
||||
```
|
||||
19
docs/language/structure/kw-alias.md
Normal file
19
docs/language/structure/kw-alias.md
Normal 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
|
||||
}
|
||||
```
|
||||
12
docs/language/structure/kw-as.md
Normal file
12
docs/language/structure/kw-as.md
Normal 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.
|
||||
17
docs/language/structure/kw-bind.md
Normal file
17
docs/language/structure/kw-bind.md
Normal 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 }
|
||||
```
|
||||
21
docs/language/structure/kw-component.md
Normal file
21
docs/language/structure/kw-component.md
Normal 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 }
|
||||
}
|
||||
```
|
||||
17
docs/language/structure/kw-def.md
Normal file
17
docs/language/structure/kw-def.md
Normal 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 }
|
||||
```
|
||||
17
docs/language/structure/kw-export.md
Normal file
17
docs/language/structure/kw-export.md
Normal 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 }
|
||||
```
|
||||
17
docs/language/structure/kw-friend.md
Normal file
17
docs/language/structure/kw-friend.md
Normal 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
|
||||
```
|
||||
12
docs/language/structure/kw-from.md
Normal file
12
docs/language/structure/kw-from.md
Normal 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.
|
||||
19
docs/language/structure/kw-internal.md
Normal file
19
docs/language/structure/kw-internal.md
Normal 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) }
|
||||
}
|
||||
```
|
||||
19
docs/language/structure/kw-module.md
Normal file
19
docs/language/structure/kw-module.md
Normal 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"
|
||||
```
|
||||
17
docs/language/structure/kw-mut.md
Normal file
17
docs/language/structure/kw-mut.md
Normal 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 }
|
||||
```
|
||||
18
docs/language/structure/kw-numbers.md
Normal file
18
docs/language/structure/kw-numbers.md
Normal 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
|
||||
```
|
||||
12
docs/language/structure/kw-of.md
Normal file
12
docs/language/structure/kw-of.md
Normal 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.
|
||||
12
docs/language/structure/kw-open.md
Normal file
12
docs/language/structure/kw-open.md
Normal 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.
|
||||
19
docs/language/structure/kw-port.md
Normal file
19
docs/language/structure/kw-port.md
Normal 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
|
||||
}
|
||||
```
|
||||
12
docs/language/structure/kw-prop.md
Normal file
12
docs/language/structure/kw-prop.md
Normal 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><Counter step="2"/></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>.
|
||||
20
docs/language/structure/kw-reducer.md
Normal file
20
docs/language/structure/kw-reducer.md
Normal 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
|
||||
}
|
||||
```
|
||||
18
docs/language/structure/kw-registry.md
Normal file
18
docs/language/structure/kw-registry.md
Normal 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"
|
||||
```
|
||||
17
docs/language/structure/kw-unsafe.md
Normal file
17
docs/language/structure/kw-unsafe.md
Normal 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) }
|
||||
```
|
||||
17
docs/language/structure/kw-uses.md
Normal file
17
docs/language/structure/kw-uses.md
Normal 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
|
||||
```
|
||||
20
docs/language/structure/kw-view.md
Normal file
20
docs/language/structure/kw-view.md
Normal 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) }
|
||||
}
|
||||
```
|
||||
Loading…
Add table
Add a link
Reference in a new issue