Skip to content

Handle load commands alongside includes in the combined tree#75

Merged
DavidSagan merged 1 commit into
mainfrom
load-commands
Jul 23, 2026
Merged

Handle load commands alongside includes in the combined tree#75
DavidSagan merged 1 commit into
mainfrom
load-commands

Conversation

@DavidSagan

Copy link
Copy Markdown
Member

Implements the load command defined by pals#260.

A load is a list under the PALS node naming files whose contents are merged, whole file by whole file, into one document. Where an include splices a file in verbatim at the point it is written, a load merges subnode by subnode under the PALS root — which is what lets a layout file and one of several settings files be composed by a small joiner file that names both. Both directives are resolved into the combined tree.

Implementation

All in the original -> combined step of src/pals_expand.cpp:

  • make_original walks load lists as well as include keys, so every file the document reaches by either route, at any depth, lands in the master tree keyed by its path. A path already registered is skipped, which both keeps one copy of a file reached twice and stops a reference cycle.
  • resolve_loads resolves one file's load list in place. Each named file is staged, spliced for its own includes and resolved for its own load, so it is a single complete file before it takes part in the merge and nesting works bottom up to any depth. The joiner's own contents are staged the same way, which is what lets SELF sit anywhere in the order; absent, they merge last. The load node itself does not survive into combined.
  • merge_pals_into combines the subnodes by type: list subnodes concatenate in load order, Dict subnodes take the union with an agreeing duplicate discarded and a disagreeing one reported, and version collects the distinct version strings. Only version is keyed to a subnode name, so notes, authors, facility and extension_labels fall out of the type rules.

A cycle, an unreadable file, or a loaded file with no PALS node is reported as a problem, and the rest of the document still combines.

Path resolution

pals#260 also states that a path in an include is relative to the file containing it, so that rule is implemented for both directives (one lexical-folding helper, resolve_path). Paths are folded before use as master-tree keys, so one file gets one key whatever route reached it. The includes already under lattice_files/ resolve to the same place under the old and new rules, so no existing test changes.

Tests

tests/test_load.cpp, 14 cases: subnode-by-subnode merge, SELF placement and its default, nested loads, includes-before-merge, relative paths (including a loaded file in a subdirectory reaching back up), version merging both ways, Dict union and Dict conflict, missing file, cycle, diamond load, and an end-to-end check that a loaded settings file's set drives an element the layout file defined.

217/217 tests pass.

Also

lattice_files/load_{layout,settings,joiner}.pals.yaml demonstrate the layout/settings split — ./print_lattices load_joiner.pals.yaml shows all three trees. README, docs/src/index.md, docs/src/guide/usage.md and the struct lattices field comments updated.

🤖 Generated with Claude Code

pals PR #260 defines a `load` command: a list under the `PALS` node naming
files whose contents are merged, whole file by whole file, to give one
document. Where an `include` splices a file in verbatim at the point it is
written, a `load` merges subnode by subnode under the `PALS` root, which is
what lets a layout file and one of several settings files be composed by a
small joiner file that names both.

Both directives are now resolved into the `combined` tree:

- make_original walks `load` lists as well as `include` keys, so every file
  the document reaches by either route, at any depth, lands in the master
  tree keyed by its path. A path already registered is skipped, which both
  keeps one copy of a file reached twice and stops a reference cycle.
- resolve_loads resolves one file's `load` list in place. Each named file is
  staged, spliced for its own includes and resolved for its own `load`, so
  it is a single complete file before it takes part in the merge and nesting
  works bottom up to any depth. The joiner's own contents are staged the
  same way, which is what lets `SELF` sit anywhere in the order; absent, they
  merge last. The `load` node does not survive into `combined`.
- merge_pals_into combines the subnodes by type: list subnodes concatenate
  in load order, Dict subnodes take the union with an agreeing duplicate
  discarded and a disagreeing one reported, and `version` collects the
  distinct version strings. Only `version` is keyed to a subnode name, so
  `notes`, `authors`, `facility` and `extension_labels` fall out of the
  type rules.

A cycle, an unreadable file, or a loaded file with no `PALS` node is
reported as a problem and the rest of the document still combines.

PR #260 also states that a path in an `include` is relative to the file
containing it, so that rule is implemented for both directives. Paths are
folded before use as master tree keys, so one file gets one key whatever
route reached it. The includes already under lattice_files/ resolve to the
same place under the old and new rules, so no existing test changes.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@DavidSagan
DavidSagan merged commit 6d0850c into main Jul 23, 2026
3 checks passed
@DavidSagan
DavidSagan deleted the load-commands branch July 23, 2026 17:13
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant