From 82c7e170b3bc75a94c45be5dd1cda4af10f7002a Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Thu, 1 Mar 2018 22:41:53 -0800 Subject: [PATCH] Fix case where loop was created in the parse stack Fixes #133 --- src/runtime/stack.c | 2 ++ test/runtime/stack_test.cc | 43 +++++++++++++++++++++++++++++++++----- 2 files changed, 40 insertions(+), 5 deletions(-) diff --git a/src/runtime/stack.c b/src/runtime/stack.c index 8e85b363..45d089f1 100644 --- a/src/runtime/stack.c +++ b/src/runtime/stack.c @@ -167,6 +167,8 @@ static bool stack__tree_is_equivalent(const Tree *left, const Tree *right) { } static void stack_node_add_link(StackNode *self, StackLink link) { + if (link.node == self) return; + for (int i = 0; i < self->link_count; i++) { StackLink existing_link = self->links[i]; if (stack__tree_is_equivalent(existing_link.tree, link.tree)) { diff --git a/test/runtime/stack_test.cc b/test/runtime/stack_test.cc index 921033e4..bf565dcf 100644 --- a/test/runtime/stack_test.cc +++ b/test/runtime/stack_test.cc @@ -132,19 +132,19 @@ describe("Stack", [&]() { describe("merge()", [&]() { before_each([&]() { - // . <──0── A <──1── B* + // . <──0── A <─* // ↑ - // └───2─── C* + // └───* ts_stack_push(stack, 0, trees[0], false, stateA); ts_stack_copy_version(stack, 0); - ts_stack_push(stack, 0, trees[1], false, stateB); - ts_stack_push(stack, 1, trees[2], false, stateC); }); it("combines versions that have the same top states and positions", [&]() { // . <──0── A <──1── B <──3── D* // ↑ // └───2─── C <──4── D* + ts_stack_push(stack, 0, trees[1], false, stateB); + ts_stack_push(stack, 1, trees[2], false, stateC); ts_stack_push(stack, 0, trees[3], false, stateD); ts_stack_push(stack, 1, trees[4], false, stateD); @@ -163,6 +163,12 @@ describe("Stack", [&]() { }); it("does not combine versions that have different states", [&]() { + // . <──0── A <──1── B* + // ↑ + // └───2─── C* + ts_stack_push(stack, 0, trees[1], false, stateB); + ts_stack_push(stack, 1, trees[2], false, stateC); + AssertThat(ts_stack_merge(stack, 0, 1), IsFalse()); AssertThat(ts_stack_version_count(stack), Equals(2)); }); @@ -172,6 +178,8 @@ describe("Stack", [&]() { // ↑ // └───2─── C <──4── D* trees[3]->size = tree_len * 3; + ts_stack_push(stack, 0, trees[1], false, stateB); + ts_stack_push(stack, 1, trees[2], false, stateC); ts_stack_push(stack, 0, trees[3], false, stateD); ts_stack_push(stack, 1, trees[4], false, stateD); @@ -184,9 +192,11 @@ describe("Stack", [&]() { // . <──0── A <──1── B <──3── D <──5── E* // ↑ // └───2─── C <──4── D <──5── E* + ts_stack_push(stack, 0, trees[1], false, stateB); + ts_stack_push(stack, 1, trees[2], false, stateC); ts_stack_push(stack, 0, trees[3], false, stateD); - ts_stack_push(stack, 0, trees[5], false, stateE); ts_stack_push(stack, 1, trees[4], false, stateD); + ts_stack_push(stack, 0, trees[5], false, stateE); ts_stack_push(stack, 1, trees[5], false, stateE); // . <──0── A <──1── B <──3── D <──5── E* @@ -204,6 +214,29 @@ describe("Stack", [&]() { }))); }); }); + + describe("when one of the versions contains an extra (e.g. ERROR) tree of size zero", [&]() { + it("does not create a loop in the stack", [&]() { + // . <──0── A <────1──── B* + // ↑ + // └2─ A <──1── B* + trees[2]->extra = true; + trees[2]->size = tree_len * 0; + + ts_stack_push(stack, 0, trees[1], false, stateB); + ts_stack_push(stack, 1, trees[2], false, stateA); + ts_stack_push(stack, 1, trees[1], false, stateB); + + // . <──0── A <──1── B* + AssertThat(ts_stack_merge(stack, 0, 1), IsTrue()); + AssertThat(ts_stack_version_count(stack), Equals(1)); + AssertThat(get_stack_entries(stack, 0), Equals(vector({ + {stateB, 0}, + {stateA, 1}, + {1, 2}, + }))); + }); + }); }); describe("pop_count(version, count)", [&]() {