API Reference

The public interface is the C API declared in yaml_c_wrapper.h, together with the expression evaluator in pals_expression.h. Everything below is generated from the header doc comments by Doxygen and embedded with Breathe.

The C API is organized by task: parse and expand a lattice, then navigate, inspect, edit, and serialize the resulting trees, with dedicated sections for node correspondence, name matching, and parameter lookup.

Ownership

Every handle, string, and list the API returns is owned by the caller. Trees are freed with delete_tree(); the char* returned by the read and emit functions with yaml_free_string(); and each aggregate result with its matching free_* function. See Memory management.

Core types

The opaque handles and sentinel values shared across the API.

typedef void *YAMLTreeHandle

Opaque handle to a parsed YAML tree.

typedef size_t YAMLNodeId

Identifies a node within a tree.

YAML_NULL_ID

Sentinel node id meaning “not found” or “invalid” (ryml’s (size_t)-1).

YAML_END

Pass as the index argument to the add_* functions to append instead of inserting.

Spelled YAML_END rather than END because this is a public header: an unprefixed END would clobber any enumerator, variable or macro of that name in every translation unit that includes us.

Parsing & expansion

Read PALS/YAML from disk or memory and expand a lattice into its four representations (original, combined, expanded, leftover).

struct lattices parse_and_expand_PALS(const char *filename, const char *root_lattice)

Builds and returns all four representations of a lattice file.

The returned struct also carries problems: an owning list of human-readable messages for every issue met while building the full_expanded tree (undefined lattice, dangling element/line references, undefined inherit/repeat/Fork targets, and expressions that could not be evaluated). It is empty when expansion was clean. The caller owns it and must release it with free_lattice_problems(). The library does not print — the caller decides whether to report.

Parameters:
  • filename – Path to the top-level YAML lattice file.

  • root_lattice – Name of the lattice to expand. If NULL or empty:

    • expands the lattice named by the last “use” statement, or

    • expands the last lattice defined in the file if no “use” is present.

Returns:

A lattices struct containing five handles:

  • original: raw tree mapping each file (including includes) to its unparsed contents.

  • combined: tree with all “include” directives resolved and spliced inline.

  • full_expanded: the selected lattice fully expanded — scalars substituted, repeats unrolled, inherits merged, and forks resolved — and nothing else. Rooted at a map holding the single name: {kind: Lattice, ...} entry, stripped of the PALS/facility scaffolding it was defined under. Its branches entries are branches, not the BeamLines they were built from, and so carry no kind; a BeamLine referenced inside a line: is a sub-line whose contents are spliced directly into the enclosing line, so no nested BeamLine survives. Elements of a multipass line carry a multipass_index giving their pass number — how many times a particle will have travelled through that physical element by that point. Every dependent parameter has been computed: each element carries its element_index — its position, counting from one, in the branch line that holds it — its ReferenceP, FloorP and s_position, the derived members of every parameter family it uses (Kn1L alongside Kn1, voltage alongside gradient, …), the non-zero defaults of the groups it carries, and each branch is capped with a branch_end Placeholder holding its final reference and floor.

  • expanded: the same lattice with all of that removed. Which parameters it keeps is decided by what the author wrote: one is held when it was present before bookkeeping ran or was written by a post-expand_lattice set, and everything else the bookkeeper computed is pruned, along with any group left empty and the branch_end elements. The values it holds are the finished ones — this is full_expanded with nodes removed, not an earlier snapshot, so a parameter present in both trees carries the same value in both, with every set and ABSOLUTE controller applied. Use it to see what was asked for rather than what it implies, or to write a lattice back out without the derived values.

  • leftover: the rest of the document, keeping its PALS/facility scaffolding: element and beamline definitions, use statements, constants, and any Lattice that was not the one expanded. Definitions substituted into the lattice are copies, so they appear in both trees. All five handles must be freed individually with delete_tree().

void free_lattice_problems(struct string_list problems)

Frees the string array owned by the problems list of a lattices value.

Passing a list with a NULL items pointer (e.g. when there were no problems) is safe and has no effect.

Parameters:

problems – The lattices::problems list to free (passed by value).

YAMLTreeHandle parse_file(const char *filename)

Parses a YAML file from disk into an opaque tree handle.

The file is read into an internal buffer and parsed in-place; the buffer is owned by the returned handle and freed by delete_tree().

Parameters:

filename – Path to the YAML file to parse.

Returns:

A tree handle on success, NULL if the file cannot be opened or if parsing fails.

YAMLTreeHandle parse_string(const char *yaml_str)

Parses a YAML string into an opaque tree handle.

The string is copied into an internal buffer and parsed in-place; the buffer is owned by the returned handle and freed by delete_tree().

Parameters:

yaml_str – Null-terminated YAML string to parse.

Returns:

A tree handle on success, NULL if parsing fails.

const char *yaml_last_parse_error(void)

Returns the most recent parse error message on the calling thread.

Whenever parse_file(), parse_string() (and hence parse_and_expand_PALS()) returns NULL because a document is malformed or a file cannot be read, this holds a human-readable description of why — for a YAML syntax error, prefixed with the offending “line L, column C:” — so the caller can report exactly what went wrong instead of a bare failure. It is cleared at the start of each parse and is empty when the last parse on this thread succeeded.

Returns:

A null-terminated string owned by the library, valid until the next parse call on this thread. Never NULL (empty when there is no error).

struct string_list

A flat, owning list of C strings.

Used to return the human-readable problems encountered while building the full_expanded tree (undefined lattice, dangling element/line references, undefined inherit/repeat/Fork targets, expressions that could not be evaluated, …). Free with free_lattice_problems().

Public Members

char **items

The strings (owning).

size_t count

Number of strings in items.

struct lattices

The five trees parse_and_expand_PALS() produces, plus the problems found on the way.

Plain C: the handles are opaque pointers, so this is usable from any language that can read the rest of this header.

Public Members

YAMLTreeHandle original

Raw tree mapping each file the document is built from — the top-level file and every file it reaches by “include” or “load” — to its unparsed contents, keyed by path.

YAMLTreeHandle combined

Tree with all “include” directives spliced inline and all “load”ed files merged in.

YAMLTreeHandle expanded

full_expanded minus every parameter the bookkeeper computed.

Values are the finished ones: a parameter in both trees holds the same value in both.

YAMLTreeHandle full_expanded

The expanded root lattice, and nothing else: a map holding the single name: {kind: Lattice, ...} entry, without the PALS/facility scaffolding it was defined under.

Every dependent parameter is computed and present.

YAMLTreeHandle leftover

Everything the expanded trees do not carry — the whole PALS/facility document minus the root lattice, so element/beamline definitions, use statements, constants and any non-root Lattice.

struct string_list problems

Problems found while building full_expanded; free with free_lattice_problems().

Node correspondence

Map a single logical node across the four trees produced by parse_and_expand_PALS().

struct correspondence_map build_correspondence_map(YAMLTreeHandle original, YAMLTreeHandle combined, YAMLTreeHandle full_expanded, YAMLTreeHandle leftover)

Builds the node correspondence between the derivation-chain trees of a lattices value.

Returns a flat list containing one node_link per node of the full_expanded tree and one per node of the leftover tree. Each link gives the corresponding combined and original node ids (or YAML_NULL_ID where none exists). Grouping the links by shared combined / original ids recovers, for any node in any of those trees, the set of nodes it corresponds to in the others.

The expanded tree takes no part: it is a pruned copy of full_expanded rather than a step in the derivation chain, and its nodes are located by path.

The handles must come from the same parse_and_expand_PALS() call — the provenance recorded during that call is what makes the mapping exact. The original handle is accepted for API symmetry; the mapping is derived from the provenance stored in combined, full_expanded and leftover.

Parameters:
  • original – Handle to the original tree.

  • combined – Handle to the combined tree.

  • full_expanded – Handle to the full_expanded tree.

  • leftover – Handle to the leftover tree. May be NULL, in which case only the full_expanded tree is walked.

Returns:

A correspondence_map. The caller must free it with free_correspondence_map(). links is NULL and count is 0 if combined is NULL, or if both full_expanded and leftover are NULL.

void free_correspondence_map(struct correspondence_map map)

Frees the link array owned by a correspondence_map.

Passing a map with a NULL links pointer is safe and has no effect.

Parameters:

map – The map to free (passed by value).

Links a node across the representations produced by parse_and_expand_PALS().

The trees are built as a derivation chain (original -> combined -> full_expanded and leftover), and provenance is recorded at every copy, so each link records which node in each tree a single logical entity maps to.

The mapping is functional per link: one full_expanded (or leftover) node maps to at most one combined node, which maps to at most one original node. Because expansion can duplicate nodes (scalar substitution, repeat, inherit, forks), a single combined/original node may appear in several links — one per copy. A field is YAML_NULL_ID when no corresponding node exists (e.g. the destination_pointer scalars synthesised during expansion have no original source).

Expansion splits the document, so a link carries either a full_expanded id or a leftover id, never both; the two are tied together through the combined id they share. A definition that was substituted into the lattice therefore yields links on both sides: one for the copy in full_expanded, one for the definition still standing in leftover.

The expanded tree is not mapped: it is a pruned copy of full_expanded, so a node in it is found by the path it sits at, not by a recorded link.

Public Members

YAMLNodeId original

Node in the original tree, or YAML_NULL_ID.

YAMLNodeId combined

Node in the combined tree, or YAML_NULL_ID.

YAMLNodeId full_expanded

Node in the full_expanded tree, or YAML_NULL_ID.

YAMLNodeId leftover

Node in the leftover tree, or YAML_NULL_ID.

struct correspondence_map

A flat list of node_links.

One link is emitted per node of the full_expanded tree and one per node of the leftover tree. Free with free_correspondence_map().

Public Members

struct node_link *links

The links (owning).

size_t count

Number of links in links.

Name matching

Resolve a PALS name-matching string to the nodes it selects.

struct name_matches match_names(YAMLTreeHandle tree, const char *match_string)

Finds every named construct matched by a PALS name-matching string.

The string follows the “Name Matching” / “Element Name Matching” syntax:

[{lattice}>>>][{branch}>>][{kind}::]{name}[>{group}.{sub}. … .{param}]

{lattice}, {branch}, and {name} are PCRE2 patterns matched against the whole name (anchored at both ends); {kind} is matched exactly; the parameter path after the single > is matched exactly, key by key. An omitted or empty pattern component matches any name at that level. {branch} matches an element if any enclosing BeamLine/Branch name matches, so elements in sub-lines are included.

The node returned for each match is whatever the string resolves to: the element node (no parameter path), the parameter-group or parameter node (with a path), or, for a bare name — no lattice/branch/kind qualifier and no parameter path — additionally each matching constant and variable defined directly under the PALS or facility node (both the full kind: constant/kind: variable and the compact constants:/variables: forms).

Not yet implemented from Element Name Matching: #N instance selection, {e1}:{e2} ranges, , unions, and & intersections.

Because beamlines and elements are only fully realised after expansion, this is normally run on the full_expanded tree of a parse_and_expand_PALS() result, but it works on any tree. Results are de-duplicated and returned in document order.

Parameters:
  • tree – Handle to the tree to search.

  • match_string – Null-terminated name-matching string.

Returns:

A name_matches listing the matched node ids. nodes is NULL and count is 0 when there are no matches or on a malformed pattern. The caller must free it with free_name_matches().

void free_name_matches(struct name_matches matches)

Frees the node array owned by a name_matches.

Passing a value with a NULL nodes pointer is safe and has no effect.

Parameters:

matches – The value to free (passed by value).

struct name_matches

A flat list of node ids identifying every named construct that matched a query string.

Each id is a node within the single tree that was passed to match_names(). Free with free_name_matches().

Public Members

YAMLNodeId *nodes

The matched node ids (owning).

size_t count

Number of ids in nodes.

Parameter values

Look up the stored value of a single element parameter, constant, or variable.

enum param_value_kind

The three outcomes of get_parameter_value().

PARAM_VALUE_NUMBER also covers the “parameter identified but not set” case, which returns the parameter’s default value (0 for every parameter, for now — real per-parameter defaults come later).

Values:

enumerator PARAM_VALUE_MISSING

The match string did not identify a parameter.

enumerator PARAM_VALUE_NUMBER

Numeric value, in param_value::number.

enumerator PARAM_VALUE_STRING

String value, in param_value::string.

struct param_value get_parameter_value(YAMLTreeHandle tree, const char *match_string)

Looks up the value of a single lattice parameter named by a PALS name-matching string.

match_string uses the same syntax as match_names(). It names either an element parameter (with a >{group}.{sub}. ... .{param} path) or, as a bare name (no lattice/branch/kind qualifier and no path), a constant or variable — the same constructs match_names() resolves. Run an element-parameter query on the full_expanded tree of a parse_and_expand_PALS() result, where constants and variables referenced by a value have already been substituted; constants and variables themselves live in the facility scaffolding, so look them up in any view that keeps it — original, combined, or leftover — but not the expanded trees, which drop it (exactly as with match_names()).

The value is returned as stored; it is NOT evaluated. A plain numeric literal comes back as a number (PARAM_VALUE_NUMBER); anything else — an expression such as “0.3 * 5”, a species name like “#3He”, or any other text — comes back verbatim as a string (PARAM_VALUE_STRING). Evaluation is the job of lattice expansion (the expanded trees already hold numbers) or evaluate_pals_expression, not of this accessor.

Resolution, and the resulting kind:

  • Element parameter, set: its stored value — a number, or a string for an expression or other non-numeric text.

  • Element parameter, not set: the default value is returned (PARAM_VALUE_NUMBER with number 0, for now).

  • Constant or variable (bare name): its stored value, the same way.

  • Nothing is identified: PARAM_VALUE_MISSING. That covers no matching element, no matching constant/variable, a bare element name (an element has no single scalar value), a path that stops on a whole parameter group, and several matches that carry conflicting values. (Matches that agree — the same element reused, or several that all take the default — collapse to the one shared value.)

Parameters:
  • tree – Handle to the tree to search.

  • match_string – Null-terminated name-matching string.

Returns:

A param_value. If kind is PARAM_VALUE_STRING the caller must free string with yaml_free_string().

struct param_value get_lattice_parameter_value(YAMLTreeHandle full_expanded, YAMLTreeHandle leftover, const char *match_string)

Looks up a parameter value across the two trees of an expanded lattice that carry live values: the full_expanded lattice (element parameters, already evaluated) and the leftover facility scaffolding (constants, variables, and any element/beamline definitions not spliced into the lattice).

This is the whole-lattice form of get_parameter_value(): the caller passes the two relevant handles from a parse_and_expand_PALS() result instead of picking a tree by hand. full_expanded is consulted first; only if it does not identify the parameter is leftover tried. The original and combined trees are deliberately not consulted — they hold raw, pre-expansion text, so a value read from them would be unevaluated and, for reused definitions, duplicated. Pass full_expanded rather than expanded: a dependent parameter is a legitimate thing to ask for, and only the former carries one.

Either handle may be NULL (treated as “no match” for that tree). The value’s kind, string ownership, and the number/string/missing rules are exactly those of get_parameter_value().

Parameters:
  • full_expanded – Handle to the full_expanded tree (element parameters).

  • leftover – Handle to the leftover tree (constants/variables).

  • match_string – Null-terminated name-matching string.

Returns:

A param_value. If kind is PARAM_VALUE_STRING the caller must free string with yaml_free_string().

struct param_value

The result of get_parameter_value().

When kind is PARAM_VALUE_STRING, string is a heap-allocated null-terminated copy the caller must release with yaml_free_string(); it is NULL for the other two kinds, which need no freeing.

Public Members

int kind

One of enum param_value_kind.

double number

Valid when kind == PARAM_VALUE_NUMBER.

char *string

Valid when kind == PARAM_VALUE_STRING; NULL otherwise.

Building & editing

Create trees and add, set, copy, or remove nodes.

YAMLTreeHandle create_empty_tree()

Creates an empty tree with a MAP root node.

Useful as a destination for deep_copy_node() / deep_copy_children(), or for building a tree programmatically via add_map(), add_sequence(), and add_scalar().

Returns:

A tree handle representing an empty MAP. Must be freed with delete_tree().

void remove_node(YAMLTreeHandle tree, YAMLNodeId parent, YAMLNodeId child)

Removes a child node and all its descendants from the tree.

After removal the child’s node ID is invalid and must not be used again. The parent parameter is accepted for API symmetry but is not used internally — the parent is inferred from the tree structure.

Parameters:
  • tree – Handle to the tree containing the node.

  • parent – Node ID of the parent (unused, may be YAML_NULL_ID).

  • child – Node ID to remove. If YAML_NULL_ID, this call is a no-op.

YAMLNodeId add_scalar(YAMLTreeHandle tree, YAMLNodeId parent, const char *key, const char *value, size_t index)

Adds a scalar key-value child to a MAP, or a plain scalar to a sequence.

Parameters:
  • tree – Handle to the tree.

  • parent – Node ID of the parent MAP or sequence.

  • key – Key string for MAP parents. Pass NULL for sequence elements.

  • value – Null-terminated scalar value string.

  • index – Insertion position among existing children. Pass YAML_END to append.

Returns:

Node ID of the newly created child, or YAML_NULL_ID on failure.

YAMLNodeId add_map(YAMLTreeHandle tree, YAMLNodeId parent, const char *key, size_t index)

Adds a new empty MAP child to an existing MAP or sequence.

Parameters:
  • tree – Handle to the tree.

  • parent – Node ID of the parent MAP or sequence.

  • key – Key string when parent is a MAP. Pass NULL for sequence elements.

  • index – Insertion position among existing children. Pass YAML_END to append.

Returns:

Node ID of the newly created MAP child, or YAML_NULL_ID on failure.

YAMLNodeId add_sequence(YAMLTreeHandle tree, YAMLNodeId parent, const char *key, size_t index)

Adds a new empty sequence child to an existing MAP or sequence.

Parameters:
  • tree – Handle to the tree.

  • parent – Node ID of the parent MAP or sequence.

  • key – Key string when parent is a MAP. Pass NULL for sequence elements.

  • index – Insertion position among existing children. Pass YAML_END to append.

Returns:

Node ID of the newly created sequence child, or YAML_NULL_ID on failure.

void set_scalar(YAMLTreeHandle tree, YAMLNodeId node, const char *value)

Sets or replaces the scalar value of an existing node.

The value string is copied into the tree’s internal arena.

Parameters:
  • tree – Handle to the tree.

  • node – Node ID to update. If YAML_NULL_ID, this call is a no-op.

  • value – Null-terminated value string to set.

void set_node_key(YAMLTreeHandle tree, YAMLNodeId node, const char *key)

Sets or replaces the key of an existing node.

The key string is copied into the tree’s internal arena.

Parameters:
  • tree – Handle to the tree.

  • node – Node ID to update. If YAML_NULL_ID, this call is a no-op.

  • key – Null-terminated key string to set.

void deep_copy_node(YAMLTreeHandle dst_tree, YAMLNodeId dst_node, YAMLTreeHandle src_tree, YAMLNodeId src_node)

Deep-copies the contents of a source node into a destination node, overwriting whatever was previously there.

Works across different trees.

Keys, values, type flags, and all descendants are copied. Strings are duplicated into the destination tree’s arena so the source tree may be freed independently afterwards.

Parameters:
  • dst_tree – Handle to the destination tree.

  • dst_node – Node ID in dst_tree to copy into.

  • src_tree – Handle to the source tree (may be the same as dst_tree).

  • src_node – Node ID in src_tree to copy from. If either handle is NULL or either node is YAML_NULL_ID, this call is a no-op.

void deep_copy_children(YAMLTreeHandle dst_tree, YAMLNodeId dst_node, YAMLTreeHandle src_tree, YAMLNodeId src_node, size_t index)

Deep-copies the children of a source node into a destination node, inserting them at the given position.

Works across different trees.

Only the children are copied — the source node itself is not. Existing children of dst_node are preserved. Strings are duplicated into the destination tree’s arena.

Parameters:
  • dst_tree – Handle to the destination tree.

  • dst_node – Node ID in dst_tree to copy children into.

  • src_tree – Handle to the source tree (may be the same as dst_tree).

  • src_node – Node ID in src_tree whose children are copied.

  • index – Insertion position among dst_node’s existing children. Pass YAML_END to append after all existing children, or 0 to prepend before all existing children. If either handle is NULL or either node is YAML_NULL_ID, this call is a no-op.

Serialization

Emit a node or whole tree back to YAML text or a file.

char *node_to_string(YAMLTreeHandle tree, YAMLNodeId node)

Emits a node and its descendants as a YAML string.

Parameters:
  • tree – Handle to the tree.

  • node – Node ID to emit. If YAML_NULL_ID or out of range, returns NULL.

Returns:

Heap-allocated null-terminated YAML string. The caller must free it with yaml_free_string().

char *tree_to_string(YAMLTreeHandle tree)

Emits a tree as a YAML string.

Same as node_to_string but defaulted to the root.

Parameters:

tree – Handle to the tree.

Returns:

Heap-allocated null-terminated YAML string. The caller must free it with yaml_free_string().

bool write_file(YAMLTreeHandle tree, const char *filename)

Writes the entire tree to a file as YAML.

Parameters:
  • tree – Handle to the tree to serialize.

  • filename – Path to the output file. Created or truncated if it already exists.

Returns:

true on success, false if the file could not be opened or if an error occurs during writing.

Memory management

Release the handles and strings the API returns. (The subsystem-specific free_* functions live with their data above: free_lattice_problems(), free_correspondence_map(), and free_name_matches().)

void delete_tree(YAMLTreeHandle tree)

Frees all memory associated with a tree handle.

Parameters:

tree – Handle previously returned by parse_file(), parse_string(), create_empty_tree(), or parse_and_expand_PALS(). Passing NULL is safe and has no effect.

void yaml_free_string(char *str)

Frees a string returned by get_node_key(), as_string(), node_to_string() or tree_to_string().

These are every char*-returning function in this header.

Passing NULL is safe and has no effect.

Parameters:

str – Pointer to the string to free.

Expression evaluation

The recursive-descent evaluator behind the PALS expression grammar. The C entry point evaluate_pals_expression() (declared in yaml_c_wrapper.h) evaluates a standalone string; the pals:: interface in pals_expression.h is the C++ evaluator it and lattice expansion are built on.

using SymbolLookup = std::function<bool(const std::string &name, double &out)>

Looks up a user-defined constant/variable by name.

Returns true and sets out if the name is known. Built-in PALS constants (pi, c_light, …) are resolved inside the evaluator and need not be provided here.

using SpeciesLookup = std::function<bool(const std::string &name, std::string &out)>

Looks up a user-defined species-name symbol by name.

A constant/variable whose value is a species string, e.g. species: "#3He". Returns true and sets out to the species name if the name is known. Lets the particle-data functions accept a symbol, e.g. mass_of(species), not only a quoted literal mass_of("#3He"). An empty std::function means no such symbols.

double evaluate_pals_expression(const char *expr, bool *ok)

Evaluates a single PALS mathematical expression to a double.

Supports the full PALS expression grammar: arithmetic (+ - * / ^), unary signs, parentheses, the built-in constants (pi, c_light, r_electron, …), the math functions (sqrt, log, sin, floor, modulo, …), and the particle-data functions mass_of / charge_of / anomalous_moment_of (backed by AtomicAndPhysicalConstantsCLib), whose species-name argument must be quoted, e.g. mass_of(“#3He”). A leading expr(...) wrapper is accepted and unwrapped.

This entry point evaluates a standalone string: user-defined constants and variables are NOT in scope (use parse_and_expand_PALS() for whole-lattice evaluation, which resolves them). Expressions containing random() / random_gauss() are treated as non-evaluable here.

Parameters:
  • expr – Null-terminated expression string.

  • ok – Optional out-param. Set to true on success, false on a parse error, unknown identifier/species, deferred random(), or a non-finite result. May be NULL.

Returns:

The evaluated value on success, or 0.0 on failure.

EvalOutcome eval_expression(const std::string &text, const SymbolLookup &lookup, const SpeciesLookup &species = {})

Evaluates text as a PALS mathematical expression.

A leading expr(...) wrapper, if present, must be stripped by the caller. lookup resolves user symbols; an empty std::function is fine when none are available. species resolves a bare identifier passed to a particle-data function to a species name; an empty std::function restricts those functions to quoted literals.

bool builtin_constant(const std::string &name, double &out)

Resolves a built-in PALS constant by name.

If name is a built-in PALS constant, sets out to its value and returns true; otherwise returns false.

struct EvalOutcome

Outcome of evaluating a PALS expression.

  • ok=true -> value holds the finite numeric result.

  • deferred=true -> the expression contains random()/random_gauss(), which must stay unevaluated to keep the expanded tree reproducible. value is unspecified.

  • ok=false, deferred=false -> not a (valid) evaluable expression: parse error, unknown identifier, unknown species, or a non-finite result. The caller should leave the original text untouched, and error says which of those it was.

Public Members

bool ok = false

True when value holds a finite result.

bool deferred = false

True when evaluation was deferred (random()).

double value = 0.0

The result; valid only when ok is true.

std::string error

Why evaluation failed, naming the offending symbol &#8212;

”unknown constant or

variable ‘C_LIGHT’; did you mean ‘c_light’?”.

A lower-case sentence fragment, meant to be appended to a caller’s own message. Empty when ok or deferred.