Doc Module
Document resolution: the resolved `Item` tree a front-end's `Node` tree becomes. Layout lives in properties (the style cascade); paint lives in bodies (`Op` data, interpreted at render time — the document text produces no closures of its own beyond one interpreter wrapper per element). Geometry rides the framework's own nouns (`CellPoint`, `CellSize`, `CellRect`, `Align`, `Track`).
Types
| Type | Description |
|
One resolvable element of the document tree: the paint body, the merged style, and the container's declared tracks and area template. Carries a paint closure, so it never takes structural equality. |
|
|
One element declared by the game: a name, an optional intrinsic size, and a body of operations. Variations are separate declarations (six corridor directions are six declarations from one F# builder); there are no parameters. |
|
|
One resolved item of the document tree. `Name` selects the style rules; `Element` paints the body; `Cols`, `Rows` and `Areas` are the container's declared tracks and area template. Carries a paint closure, so it never takes structural equality. |
|
|
A per-cell kernel, referenced from a document by name through `generate`. Gen2 generates 2D cells. |
|
|
A paint statement as data. The interpreter runs it at render time. Closed by design — the library owns statement semantics, and every statement means the same thing in every game. Consumers extend through elements and words, not through new cases. Geometry is box-local: `FillRect` covers a local rect, `Set` places a local point (or, with `at` absent, places one cell by the two aligns — the `set c` anchor form), `Border` outlines a local rect (absent rect: the whole box), `Generate` runs a kernel over a local rect (absent area: the whole box). |
|
|
How a container places its children: stacked children (default), flow tracks, or seeded scatter. |
|
|
Merged layout properties. Absent means inherit. Two halves: where and how big the element itself is inside its parent (Size, At, Col, Row, Span, Area, PlaceH, PlaceV), and how it places its own children (Pack, Gap, Pad, Seed). Layout only — paint stays in bodies. |
|
|
The game's whole say: cell words, kernels, and its element library. Constructed once, read per build — hence the frozen dictionaries, the fastest read-side dictionary in the BCL. |
Functions and values
| Function or value |
Description
|
|
Resolves one area template — `areas="road woods; road lake"` — into its rows of names. Rows split on `;`, names on spaces and tabs. A row with no name is an authoring slip, not an empty row: it would shift every row below it in the template.
|
|
The positioned half of an error message; XML nodes carry Position -1 (that front-end tracks no positions), so the message names the element only.
|
|
Reads one align word — `start`, `center`, `end`, `stretch` — into its `Align`; anything else is `ValueNone`.
|
Full Usage:
collectStyles (src, roots)
Parameters:
string
roots : ImmutableArray<Node>
Returns: Result<Dictionary<string, Style>, string>
|
Collects `style name ...` rules — the name by word argument (KDL) or by the `name` property (XML). Later rules win per property; a bad property fails the build with its position. Like the template collector, a declaration is a leaf: rules do not nest. The `name` property names the rule; it is a key, not a style, so it is dropped before the properties are applied. A KDL rule states its name as a word argument and never carries the property.
|
Full Usage:
collectTemplates (surface, src, roots)
Parameters:
Surface<'T>
src : string
roots : ImmutableArray<Node>
Returns: Result<Dictionary<string, ElementDecl<'T>>, string>
Type parameters: 'T |
Collects `element name { ... }` templates from the whole tree. The definition's `w=`/`h=` state its extent; other properties are errors. The body resolves like any statement list.
|
Full Usage:
csOf v
Parameters:
(int * int) voption
Returns: int
Modifiers: inline |
The column span of a `colspan`/`rowspan` pair, or 1 when absent — a half-stated span merges field-wise, and one track is the default.
|
|
Reads and validates the map node's dimensions: `w=`/`h=` properties (the XML channel), positional args (the KDL channel), or one of each. A named dimension claims its slot, so `map 36 h=20` reads 36 across and 20 down instead of failing on a mixed document. A doubled dimension, leftover args, and zero or negative dimensions fail with a position.
|
|
The solver's defaults: no size, no placement, no pack, no gap. Every cascade starts here, so an absent property means "inherit".
|
Full Usage:
expandNodes (src, nodes)
Parameters:
string
nodes : ImmutableArray<Node>
Returns: Result<Node[], string>
|
`repeat n` duplicates its children, nested repeats included. The count is read by name (`count=`) or positionally. Two caps hold, a per-`repeat` count cap and a 100000-node cap on the expansion's total output — nested repeats multiply, so `repeat 100000 { repeat 100000 { x } }` fails on the running total instead of looping until memory stops. Returns an array; every consumer iterates.
|
|
Locates the document's map container. Its dimensions ride positional args (`map 36 20`) or the `w=`/`h=` properties (`map w="36" h="20"`).
|
Full Usage:
interpret (surface, box, op)
Parameters:
Surface<'T>
box : GridSection2D<'T>
op : Op<'T>
Type parameters: 'T |
Runs one statement's paint into `box`.
|
Full Usage:
isListProp name
Parameters:
string
Returns: bool
|
The three list properties a container states for its own children. They are the container's own channel: they never cascade, and a `style` rule that states one fails.
|
Full Usage:
isOpKind kind
Parameters:
string
Returns: bool
|
Whether the node kind is a paint statement (`fill`, `fillRect`, `set`, `border`, `rect`, `generate`). Everything else in a body is a child container or a declaration node.
|
|
|
|
Scratch-grid run, then a scan for the covered area — the general measurement for bodies the op pass cannot see (game-declared elements with custom paint). `available` bounds the scratch grid, so greedy bodies report the available size, not an unbounded one. The resolver's op-derived extents cover the document path; this runs only for `Element<'T>` values a game builds by hand.
|
|
Derives an element's extent from its body's own geometry: each statement contributes its furthest cell, and any box-relative statement (a whole-box fill, border, or generate) marks the body greedy — its size is whatever the container assigns. A `set` that places a spanning word contributes the whole instance, so an element reserves the cells its instance covers. Pure arithmetic over the `Op` data: no grid, no allocation. This is the measurement the emitter path uses; a `ValueNone` result means "greedy, stretch".
|
|
|
|
|
|
The one closure per element: the body as data, interpreted at render time. The text produces nothing else that runs. The extent states a declared size; when none is declared, `measureOps` derives it from the body's own geometry (no allocation), so the emitter never needs the scratch-grid measure.
|
|
Node kinds the vocabulary owns. A template or a surface element under one of these names would be unreachable, or would take over a container the resolver builds itself. `plot` and `grid` are not here: a template or a surface element of that name gives the built-in container its own body. Frozen: public but unmodifiable.
|
Full Usage:
resolve surface src roots
Parameters:
Surface<'T>
src : string
roots : ImmutableArray<Node>
Returns: Result<Item<'T>[], string>
Type parameters: 'T |
Templates expand, words resolve, style merges. Errors carry line and column when the front-end tracks positions (`Markup.where` turns each node's offset into them; XML nodes carry no positions, so their errors name the element). Cascade: solver defaults, then document `style` rules in order, then inline properties. `map` is the root container (its `w=`/`h=` dimensions are validated here); `element` nodes define templates (name as first argument or `name` property); `repeat n` duplicates its children; the `cols`, `rows` and `areas` properties of a container declare its tracks and named areas, and a `style` rule cannot state one. Declared `cols`/`rows` imply `pack=flow`. `plot` is the built-in anonymous container: empty body, exact box. `layer` is the map's layer container: one name and nothing else, resolved under the literal name `layer` and reported under its own (`Item.Layer`). Every root is the map or a declaration: a stray root node would be dropped without a word, so it fails the build.
|
Full Usage:
resolveContainer (surface, src, templates, styles, name, n)
Parameters:
Surface<'T>
src : string
templates : Dictionary<string, ElementDecl<'T>>
styles : Dictionary<string, Style>
name : string
n : Node
Returns: Result<Item<'T>, string>
Type parameters: 'T |
Resolves one container node into an `Item`: expands repeats, cascades the style (rule sheet, then inline props), splits the children into paint statements (this element's body), track and area directives, and child containers. Declarations (`element`, `style`) are leaves here — their collectors ran first. A `layer` child is legal only under the map root; it resolves under the literal name `layer` and the item is stamped with the layer's own name.
|
|
|
Full Usage:
rsOf v
Parameters:
(int * int) voption
Returns: int
Modifiers: inline |
The row span of a `colspan`/`rowspan` pair, or 1 when absent.
|
|
|
|
Resolves one track list — `cols="1 fixed 3 auto"` — into tracks. A bare number is a weight, `fixed n` is a fixed size, `auto` sizes to the children. `Track.Percent` has no token: it carries a fraction of the container, and no document needs one yet.
|
|
Game-declared element bodies never pass through statement resolution, so their kernel references and their area words get checked here: a typo, or a spanning word that an area statement cannot place, must fail the build rather than vanish at render.
|
The `W` of a size, or 0 when absent — a half-stated `w=`/`h=` pair merges field-wise, so the missing axis reads 0 ("stretch this axis").
|
|
|
|
|
|
The `X` of a point, or 0 when absent — a half-stated `x=`/`y=` pair merges field-wise, so the missing axis reads 0.
|
|
Mibo