Working on pals-cpp¶
Notes for working on the library itself: where the code lives, how trees are held in memory, how to run the tests, and how to build this documentation.
Source layout¶
The library sources live in src/, split by concern:
yaml_c_wrapper.h— the public C API: the opaque handle types and every exported function. This is the only header consumers include.yaml_c_wrapper.cpp— the generic YAML tree wrapper over rapidyaml (parse, traverse, query, modify, emit). Knows nothing about PALS.yaml_tree.h— internal declarations shared between the wrapper and the PALS code: the tree representation behindYAMLTreeHandle(ParsedData) plus the low-level tree helpers (ensure_capacity,deep_copy_recursive).pals_expand.cpp— the lattice expansion pipeline that builds the five-tree representation (original/combined/expanded/full_expanded/leftover): include splicing,loadmerging, structural expansion (repeats, inherits, forks), expression, controller andsetevaluation, and the element bookkeeper that walks each branch filling in reference parameters, floor placement, s-positions and dependent parameters.pals_check.{h,cpp}— spelling checks against the fixed PALS vocabulary (element kinds and parameter group names). AFlorPgroup parses as valid YAML and would otherwise go unrecognised in silence, so it is reported here, with a “did you mean” suggestion where a near match exists.pals_floor.{h,cpp}— floor (global) coordinate geometry. A placement is a position plus an orientation, carried as a unit quaternion rather than the standard’s W matrix;floor_propagateadvances one along the reference curve, andstraight_LS/bend_LS/patch_LSbuild the (L, S) pair for the three geometries PALS defines.pals_match.cpp— PALS name matching and parameter lookup (the PCRE2-basedmatch_names/get_parameter_valuefamily).pals_util.{h,cpp}— small helpers shared across the PALS split (child_val_str,split_dots,resolve_param_path,strip_expr_wrapper).pals_expression.{h,cpp}— the standalone PALS expression grammar and evaluator (arithmetic, functions, built-in constants, particle-data lookups).
Everything builds into libyaml_c_wrapper; see CMakeLists.txt.
Memory model¶
YAMLTreeHandle wraps a ryml::Tree into a C object so that trees can be
handed across the shared library boundary to other languages. A ryml::Tree is
stored in memory as a plain array of nodes, and a ryml::NodeRef is a thin
wrapper around an index into that array — which is what YAMLNodeId is.
Trees are obtained by parsing a C++ std::string, and the parsed values are
pointers into that string rather than copies. The string must therefore stay
alive as long as the tree is in use, which is why ParsedData owns both
together.
Most of the relevant ryml code for reference is in
build/_deps/rapidyaml-src/src/c4/yml/tree.hpp.
Running the tests¶
The tests are Catch2 cases under
tests/, registered with CTest. Rebuild before running them — the tests link
against the freshly built library:
cmake --build build
ctest --test-dir build --output-on-failure
To run a single test case, match it by name:
ctest --test-dir build -R "Test Name"
Building the documentation¶
The site is built with Sphinx (MyST Markdown + the Furo theme), with the C/C++ API pulled in from Doxygen via Breathe. The published site is at https://pals-project.github.io/pals-cpp/.
To build and preview it locally (requires doxygen and python3):
docs/build_local.sh
This runs docs/build.py — Doxygen (API → XML), then Sphinx →
docs/build/html — and serves the result at http://localhost:8000/. Pass
--no-serve to build without starting a server, or --port N to serve
elsewhere.
Narrative pages live in docs/src/; the API reference is generated from the
doc comments in src/yaml_c_wrapper.h and src/pals_expression.h, so API
documentation is edited in the headers themselves.