Fragments and stacking (spec/02): the fragment-type behavior, and the operations over fragments of a type.
A fragment is a document of a type, or any part of one: a map with the type's keys,
not necessarily all of them and not validated. A document type that stacks implements
this behavior, declaring what visualize read from its chart schema: how each key
combines (key/2), which elements a layer replaces in place (identity/2), the kinds
its fragments can be (kinds/0, wrapper/1) and where each kind lands in a whole
document (place/3). The machinery holds no type's vocabulary, so every type combines
the same way:
compose/3, the union, reports a name two fragments declare differently (§3.1);stack/2, the cascade, takes the higher layer's word (§3.2);explain/2says which layer set every value of a stack (§6.3);kind/2,refs/2andrelocate/3read a fragment's kind and ids (§6.1, §6.2);encode_value/2anddecode_value/3write and read variables, ids and use sites in the type's forms (§9).
A struct is a leaf of every walk (visualize D-92): a %Macaw.Layers.Var{} stands for
a value rather than being one. Only refs/2 and relocate/3 read a struct's parts, a
%Macaw.Layers.Use{}'s, by name.
Ported from visualize's Visualize.Chart.Compose, Stack and Fragment.
Summary
Types
An id a store issued: {kind, n}.
A node kind of a document type.
A layer of a stack: a fragment, or a {name, fragment} pair.
How a key combines (spec/02 §2).
A key's spec: its rule, the node kind of a node-valued key, and the node kind of a list's or a name map's elements.
Callbacks
That value with its holes substituted, written back in the type's syntax.
A whole document as inline sites, one kind each.
The variables a value of the type's own syntax holds (a text's holes).
The identity of an element of a :concat list of kind elements, or nil.
Every id left at a reference site of a flattened document resolved through fetch.
How a key of a node of kind combines, or nil for a key the type does not know.
Every kind a fragment of the type can be, and so every kind an id can carry.
The type's own merge of a key whose rule is {:type, name}.
Where a composite site of kind lands in a whole document (spec/02 §8.2).
The node kind of a whole document of the type.
The kind a singular wrapper key names (style: → :style), or nil.
Functions
The left fold of compose/3; compose(type, []) is {:ok, %{}}.
b over a by every key's rule (spec/02 §3.1): {:ok, fragment}, or {:error, faults}
with every :conflict at its path, ordered by path.
The value of one of this file's tags, its payload already read (spec/02 §9), for a
type's decode_value/2 to call: {:ok, value}, or :default for a tag or payload it
does not read, which the reader refuses at its path. An id's kind is matched against the
type's kinds by its string, so no atom is made from a document.
The map form of this file's terms (spec/02 §9), for a type's encode_value/1 to call:
a variable as {"$var": name}, an id as {"$id": [kind, n]}, a use site as
{"$use": {…}}, its parts in the type's own map form; :default for any other term.
One entry per leaf path of stack/2 of layers (spec/02 §6.3), ordered by path:
%{path, value, layer, overrode}, layer the layer's name or its zero-based position.
It recomputes the stack by the cascade's own walk, so it cannot drift from it.
The kind of a fragment, derived (spec/02 §6.1): walking down while exactly one key is
set, the last kind reached. A singular wrapper is the kind it names, a name map or list
holding one entry the entry's kind, a composite :composite. nil for a fragment that
branches at the top, which is no kind of fragment, and for one that reaches no kind
below the root.
Every id a fragment refers to, once each, sorted (spec/02 §6.2): a {kind, n} of the
type's kinds/0 with n a positive integer, wherever it stands, a use site's ref,
origin, local and vars included. Sorted, since the order a map is walked is the
runtime's.
The fragment with every id rewritten through table, %{old => new}, and the ids the
table did not carry, sorted (spec/02 §6.2). A use site's ids are rewritten in place, the
site still a %Use{}; an id not in the table is left, to resolve as a mask.
The cascade of higher over lower (spec/02 §3.2): for every key the higher layer
wins. It cannot fail, so it answers the fragment itself.
Types
@type id() :: {kind(), pos_integer()}
An id a store issued: {kind, n}.
@type kind() :: atom()
A node kind of a document type.
A layer of a stack: a fragment, or a {name, fragment} pair.
@type rule() :: :concat | :union | :deep | :override | {:type, atom()}
How a key combines (spec/02 §2).
A key's spec: its rule, the node kind of a node-valued key, and the node kind of a list's or a name map's elements.
Callbacks
That value with its holes substituted, written back in the type's syntax.
@callback decompose(map()) :: [Macaw.Layers.Use.t()]
A whole document as inline sites, one kind each.
@callback holes(kind(), term(), term()) :: [Macaw.Layers.Var.t()]
The variables a value of the type's own syntax holds (a text's holes).
The identity of an element of a :concat list of kind elements, or nil.
Every id left at a reference site of a flattened document resolved through fetch.
How a key of a node of kind combines, or nil for a key the type does not know.
@callback kinds() :: [kind()]
Every kind a fragment of the type can be, and so every kind an id can carry.
The type's own merge of a key whose rule is {:type, name}.
Where a composite site of kind lands in a whole document (spec/02 §8.2).
@callback root() :: kind()
The node kind of a whole document of the type.
The kind a singular wrapper key names (style: → :style), or nil.
Functions
@spec compose(module(), [map()]) :: {:ok, map()} | {:error, [Macaw.Layers.Fault.t(), ...]}
The left fold of compose/3; compose(type, []) is {:ok, %{}}.
@spec compose(module(), map(), map()) :: {:ok, map()} | {:error, [Macaw.Layers.Fault.t(), ...]}
b over a by every key's rule (spec/02 §3.1): {:ok, fragment}, or {:error, faults}
with every :conflict at its path, ordered by path.
The value of one of this file's tags, its payload already read (spec/02 §9), for a
type's decode_value/2 to call: {:ok, value}, or :default for a tag or payload it
does not read, which the reader refuses at its path. An id's kind is matched against the
type's kinds by its string, so no atom is made from a document.
The map form of this file's terms (spec/02 §9), for a type's encode_value/1 to call:
a variable as {"$var": name}, an id as {"$id": [kind, n]}, a use site as
{"$use": {…}}, its parts in the type's own map form; :default for any other term.
One entry per leaf path of stack/2 of layers (spec/02 §6.3), ordered by path:
%{path, value, layer, overrode}, layer the layer's name or its zero-based position.
It recomputes the stack by the cascade's own walk, so it cannot drift from it.
The kind of a fragment, derived (spec/02 §6.1): walking down while exactly one key is
set, the last kind reached. A singular wrapper is the kind it names, a name map or list
holding one entry the entry's kind, a composite :composite. nil for a fragment that
branches at the top, which is no kind of fragment, and for one that reaches no kind
below the root.
Every id a fragment refers to, once each, sorted (spec/02 §6.2): a {kind, n} of the
type's kinds/0 with n a positive integer, wherever it stands, a use site's ref,
origin, local and vars included. Sorted, since the order a map is walked is the
runtime's.
The fragment with every id rewritten through table, %{old => new}, and the ids the
table did not carry, sorted (spec/02 §6.2). A use site's ids are rewritten in place, the
site still a %Use{}; an id not in the table is left, to resolve as a mask.
The left fold of stack/3, the later layer the higher: stack(type, []) is %{} and
stack(type, [a]) is a. A layer may be a {name, fragment} pair, whose name is
ignored here and reported by explain/2.
The cascade of higher over lower (spec/02 §3.2): for every key the higher layer
wins. It cannot fail, so it answers the fragment itself.