Modules
Parses Yarn Spinner dialogue into a Yarnspinnex.Script (plain data, safe to cache) and runs
it one event at a time: step/3 returns the next line, command, or option group along with an
updated Yarnspinnex.Cursor, and choose/4 answers an option group. Nothing blocks.
Why a script could not be compiled: a parse failure, or a validation failure such as a jump to
a missing node. line (1-based, in the source string) and node locate the problem when known.
A position in a running dialogue: the current node, the path into it, the variables the
dialogue owns (keyed by bare name, so $gold in a script is "gold" here), and the fingerprint
of the node it is in. Plain data with no reference to the script itself and none of the
host's context, so it can be persisted (:erlang.term_to_binary/1), copied, and resumed later.
Built-in Yarn Spinner expression functions. Game-specific functions belong in a
Yarnspinnex.HostFunctions module passed to Yarnspinnex.compile_string/2.
Behaviour for the game-specific functions a script may call, beyond Yarnspinnex.Functions.
Advances a Yarnspinnex.Cursor through a Yarnspinnex.Script one event at a time. Statements
with nothing to show the host (<<set>>, <<declare>>, <<if>>, <<jump>>) are absorbed
inside step/3, so every result is a line, a command, an option group, or the end.
One line of dialogue as returned by Yarnspinnex.step/3: the speaker, the text with its
interpolations applied, and the #tags written after it. id is the value of the #line:
tag when present - Yarn's localization key for the line.
Renders a compiled script as Mermaid flowchart source: node_graph/1 draws one box per node
with an edge per <<jump>>, and flowchart/2 draws every line, choice, and branch inside
each node with edges following control flow between them.
A single parsed Yarn node: its title, the source line its header starts on, its headers, and its statement body.
Operator semantics for Yarnspinnex.Interpreter: binop/3 for every binary operator except
and/or (those short-circuit in the interpreter), negate/1 for unary minus, get_field/2
for . access, and to_text/1 for how values render inside dialogue text.
One choice in a -> option group, as returned by Yarnspinnex.step/3. index is what
Yarnspinnex.choose/4 takes; enabled? reflects the option's trailing <<if>> and is false
for choices that should be shown but cannot be picked. tags and id come from the #tags
written after the option, as on a Yarnspinnex.Line.
Splits a Yarn source string into nodes (title: ... header, --- body
separator, === terminator) and parses each node's body.
Parses the lines inside one Yarn node (between --- and ===) into a tree of statements
consumed by Yarnspinnex.Interpreter. Every statement and option ends with the source line it
came from; consecutive -> options are folded into one {:options, ...} statement.
Parses a Yarn expression (as found inside {...} interpolation, <<if ...>>, <<set ... = ...>>, and command arguments) into a small, plain
data AST that Yarnspinnex.Interpreter evaluates against the cursor's
variables. Tokenizing is delegated to Yarnspinnex.Parser.Lexer; this
module only builds the AST from the resulting tokens.
Tokenizes a Yarn expression source string. Pure source-to-tokens - no
knowledge of expression grammar or the AST; that lives in
Yarnspinnex.Parser.Expression.
A host-built view of game state that dialogue is allowed to read. fields holds the readable
values; source keeps a reference to whatever it was projected from, for the host's own use.
Dialogue reads fields and can never reach source.
Raised by Yarnspinnex.step/3 and Yarnspinnex.choose/4 when a statement cannot run: a type
error in an expression, a host function that failed, a cursor that does not fit the script, or
a script that loops without ever producing an event. node and line locate the statement;
path and index are the cursor position for cases with no statement to point at.
A parsed Yarn script ready to run: nodes indexed by title, which one Yarnspinnex.start/2
should enter, the Yarnspinnex.HostFunctions module its calls resolve against, and a
fingerprint per node that cursors carry so a stale one is caught. Plain data - safe to cache
(in ETS, a map, wherever) across dialogue turns.
Name lookup shared by the interpreter and Yarnspinnex.Ops: $player finds "player" or
:player in a map or Yarnspinnex.Projection, string key first. A keyword list is accepted at
the top level only, as context (lookup!/1) or vars (normalize/1); nested values are maps.