Working on PALSParserCpp¶
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:
PALSParserCpp.h— the public C API: the opaque handle types and every exported function. This is the only header consumers include.PALSParserCpp.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/adjunct): 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 libPALSParserCpp; 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"
The test binary can also be run directly, from any directory:
build/tests/tests "[check]"
Where a test’s lattice comes from¶
The tests do not create lattice files. A lattice a test needs only in order to
expand it is held in a string and passed to expand_PALS_string, which builds
the same four trees parse_and_expand_PALS does without going through the disk:
struct lattices lat = expand_PALS_string(doc, nullptr);
The tests that are about files on disk — what a relative load or include
resolves against, what parse_file does with a real path, what a parse error
says a malformed file is called — read the fixtures committed under
tests/lattices/, one directory per multi-file case. lattice_file("name")
names one; it resolves against the test sources’ own location, so the current
directory never matters. The two tests that exercise write_file write under the
system temp directory, through out_path.
Nothing about the tests depends on where they are started from. (The examples are
a different story: example_rw and print_lattices reach their lattices through
../lattice_files/, so they still have to be run from build/.)
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/PALSParserCpp/.
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/PALSParserCpp.h and src/pals_expression.h, so API
documentation is edited in the headers themselves.