Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 21 additions & 15 deletions src/pals_expand.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -242,12 +242,12 @@ static size_t find_in_line(const ryml::Tree& t, size_t line,
// creates nothing.
// 3. Names the new branch (after `to_line` for SELF, else after `new_branch`).
// 4. Checks the destination is a kind that may be forked to.
// 5. Creates a destination_pointer in the element pointing at
// "destination_element" in the destination branch, and resolves
// ForkP.new_branch to the name of the branch that was made (or `null` when
// none was). The pointer is a node id, for use while expansion runs;
// link_fork_connections later turns it into the `ForkP.forked_to` name that
// the expanded lattice states the connection by.
// 5. Creates a ForkP.destination_pointer pointing at "destination_element" in
// the destination branch, and resolves ForkP.new_branch to the name of the
// branch that was made (or `null` when none was). The pointer is a node id,
// for use while expansion runs; link_fork_connections later turns it into
// the `ForkP.forked_to` name that the expanded lattice states the
// connection by.
static void handle_fork(ryml::Tree& t, size_t fork_node, size_t branches,
std::map<std::string, size_t>& emap,
std::map<size_t, size_t>& prov, ProblemList& problems,
Expand Down Expand Up @@ -400,10 +400,12 @@ static void handle_fork(ryml::Tree& t, size_t fork_node, size_t branches,
}
}

// Add destination_pointer: <node id of target as string>
// Add ForkP.destination_pointer: <node id of target as string>. It sits in
// the group beside the `to_line`/`destination_element` it resolves and the
// `forked_to` it will become, not loose on the element.
ensure_capacity(t, 2);
std::string id_str = std::to_string(target);
size_t fp_child = t.append_child(fork_node);
size_t fp_child = t.append_child(forkp);
t.ref(fp_child) |= ryml::KEY | ryml::VAL;
t.set_key(fp_child, t.to_arena(ryml::to_csubstr("destination_pointer")));
t.set_val(fp_child, t.to_arena(ryml::to_csubstr(id_str)));
Expand Down Expand Up @@ -2188,7 +2190,10 @@ static void run_element_bookkeeper(ryml::Tree& t, size_t lat_node,
forkp != ryml::NONE
? child_val_str(t, forkp, "propagate_reference")
: "";
std::string ptr = child_val_str(t, def, "destination_pointer");
std::string ptr =
forkp != ryml::NONE
? child_val_str(t, forkp, "destination_pointer")
: "";
std::string nb =
forkp != ryml::NONE
? child_val_str(t, forkp, "new_branch")
Expand Down Expand Up @@ -2296,10 +2301,12 @@ static void link_fork_connections(ryml::Tree& t, size_t lat_node) {
if (ele == ryml::NONE || !t.has_key(ele)) continue;
if (child_val_str(t, ele, "kind") != "Fork") continue;

// A Fork that failed to resolve has no destination_pointer, and
// the reason was reported when it was handled; there is nothing to
// link to.
std::string ptr = child_val_str(t, ele, "destination_pointer");
// A Fork that failed to resolve has no ForkP.destination_pointer,
// and the reason was reported when it was handled; there is nothing
// to link to.
size_t forkp = t.find_child(ele, ryml::to_csubstr("ForkP"));
if (forkp == ryml::NONE) continue;
std::string ptr = child_val_str(t, forkp, "destination_pointer");
if (ptr.empty()) continue;
size_t dest;
try {
Expand All @@ -2312,9 +2319,8 @@ static void link_fork_connections(ryml::Tree& t, size_t lat_node) {
// Name the destination on the Fork. A destination that is not in
// `qnames` is not an element of any branch line, which handle_fork
// does not produce a pointer to.
size_t forkp = t.find_child(ele, ryml::to_csubstr("ForkP"));
auto dest_name = qnames.find(dest);
if (forkp != ryml::NONE && dest_name != qnames.end())
if (dest_name != qnames.end())
set_plain_child(t, forkp, "forked_to",
dest_name->second.c_str());

Expand Down
21 changes: 13 additions & 8 deletions tests/test_expansion.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -452,14 +452,16 @@ TEST_CASE("a Fork needs only to_line; destination_element and new_branch default
REQUIRE(std::string(lat.problems.items[i]).find("f1") ==
std::string::npos);

// The fork resolved to a target, so the element carries a destination_pointer and
// the defaulted branch (named after to_line) exists.
YAMLNodeId fp = find_by_key(lat.expanded, "destination_pointer");
REQUIRE(fp != YAML_NULL_ID);
// The fork resolved to a target, so its ForkP carries a
// destination_pointer and the defaulted branch (named after to_line)
// exists. The pointer is a parameter of the group, not a key loose on the
// element.
YAMLNodeId forkp = find_by_key(lat.expanded, "ForkP");
REQUIRE(get_child_by_key(lat.expanded, forkp, "destination_pointer") !=
YAML_NULL_ID);

// Expansion resolves ForkP.new_branch to the name of the branch it made,
// which for the default is the to_line name.
YAMLNodeId forkp = find_by_key(lat.expanded, "ForkP");
REQUIRE(val_eq(lat.expanded,
get_child_by_key(lat.expanded, forkp, "new_branch"),
"dump_line"));
Expand Down Expand Up @@ -974,13 +976,16 @@ TEST_CASE("a Fork inside a forked-to branch resolves exactly once",
YAMLNodeId branches = get_child_by_key(lat.expanded, lat1, "branches");
REQUIRE(get_size(lat.expanded, branches) == 4);

// f2, the Fork in the branch that f1 built, ran once: one destination_pointer.
// f2, the Fork in the branch that f1 built, ran once: its ForkP holds one
// destination_pointer. A second run would append a second one to the same
// group, since handle_fork reuses the ForkP it finds.
YAMLNodeId f2 = first_element_of_branch(lat.expanded, 2);
REQUIRE(key_eq(lat.expanded, f2, "f2"));
YAMLNodeId forkp = get_child_by_key(lat.expanded, f2, "ForkP");
int pointers = 0;
for (size_t i = 0; i < get_size(lat.expanded, f2); ++i) {
for (size_t i = 0; i < get_size(lat.expanded, forkp); ++i) {
char* k = get_node_key(lat.expanded,
get_child_by_index(lat.expanded, f2, i));
get_child_by_index(lat.expanded, forkp, i));
if (k && std::string(k) == "destination_pointer") pointers++;
yaml_free_string(k);
}
Expand Down
Loading