From 36d9c3be1410b14a41c47279bff3dc6d0ede3b5a Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Thu, 18 Jun 2015 16:34:52 -0700 Subject: [PATCH] Organize parse-stack spec --- spec/runtime/parse_stack_spec.cc | 344 ++++++++++++++++--------------- 1 file changed, 176 insertions(+), 168 deletions(-) diff --git a/spec/runtime/parse_stack_spec.cc b/spec/runtime/parse_stack_spec.cc index 226390ed..adb9105b 100644 --- a/spec/runtime/parse_stack_spec.cc +++ b/spec/runtime/parse_stack_spec.cc @@ -19,10 +19,6 @@ describe("ParseStack", [&]() { const size_t tree_count = 8; TSTree *trees[tree_count]; - bool merged; - ParseStackPopResultList pop; - int new_index; - before_each([&]() { stack = ts_parse_stack_new(); TSLength len = ts_length_make(2, 2); @@ -36,124 +32,43 @@ describe("ParseStack", [&]() { ts_tree_release(trees[i]); }); - it("starts with a single head with a null tree", [&]() { - AssertThat(ts_parse_stack_head_count(stack), Equals(1)); - AssertThat(ts_parse_stack_head(stack, 0), Equals(nullptr)); + describe("push(head_index, state, tree)", [&]() { + it("adds entries to the stack", [&]() { + AssertThat(ts_parse_stack_head_count(stack), Equals(1)); + AssertThat(ts_parse_stack_head(stack, 0), Equals(nullptr)); + + /* + * A0. + */ + ts_parse_stack_push(stack, 0, stateA, trees[0]); + const ParseStackEntry *entry1 = ts_parse_stack_head(stack, 0); + AssertThat(*entry1, Equals({trees[0], stateA})); + AssertThat(ts_parse_stack_entry_next_count(entry1), Equals(1)); + AssertThat(ts_parse_stack_entry_next(entry1, 0), Equals(nullptr)); + + /* + * A0__B1. + */ + ts_parse_stack_push(stack, 0, stateB, trees[1]); + const ParseStackEntry *entry2 = ts_parse_stack_head(stack, 0); + AssertThat(*entry2, Equals({trees[1], stateB})); + AssertThat(ts_parse_stack_entry_next_count(entry2), Equals(1)); + AssertThat(ts_parse_stack_entry_next(entry2, 0), Equals(entry1)); + + /* + * A0__B1__C2. + */ + ts_parse_stack_push(stack, 0, stateC, trees[2]); + const ParseStackEntry *entry3 = ts_parse_stack_head(stack, 0); + AssertThat(*entry3, Equals({trees[2], stateC})); + AssertThat(ts_parse_stack_entry_next_count(entry3), Equals(1)); + AssertThat(ts_parse_stack_entry_next(entry3, 0), Equals(entry2)); + }); }); - it("can push and pop (state, tree) pairs to and from the stack", [&]() { - /* - * A0. - */ - ts_parse_stack_push(stack, 0, stateA, trees[0]); - const ParseStackEntry *entry1 = ts_parse_stack_head(stack, 0); - AssertThat(*entry1, Equals({trees[0], stateA})); - AssertThat(ts_parse_stack_entry_next_count(entry1), Equals(1)); - AssertThat(ts_parse_stack_entry_next(entry1, 0), Equals(nullptr)); + describe("pop(head_index, count, should_count_extra)", [&]() { + ParseStackPopResultList pop; - /* - * A0__B1. - */ - ts_parse_stack_push(stack, 0, stateB, trees[1]); - const ParseStackEntry *entry2 = ts_parse_stack_head(stack, 0); - AssertThat(*entry2, Equals({trees[1], stateB})); - AssertThat(ts_parse_stack_entry_next_count(entry2), Equals(1)); - AssertThat(ts_parse_stack_entry_next(entry2, 0), Equals(entry1)); - - /* - * A0__B1__C2. - */ - ts_parse_stack_push(stack, 0, stateC, trees[2]); - const ParseStackEntry *entry3 = ts_parse_stack_head(stack, 0); - AssertThat(*entry3, Equals({trees[2], stateC})); - AssertThat(ts_parse_stack_entry_next_count(entry3), Equals(1)); - AssertThat(ts_parse_stack_entry_next(entry3, 0), Equals(entry2)); - - /* - * A0. - */ - pop = ts_parse_stack_pop(stack, 0, 2, false); - AssertThat(pop.size, Equals(1)); - AssertThat(pop.contents[0].tree_count, Equals(2)); - AssertThat(pop.contents[0].trees[0], Equals(trees[1])); - AssertThat(pop.contents[0].trees[1], Equals(trees[2])); - AssertThat(ts_parse_stack_head(stack, 0), Equals(entry1)); - - /* - * . - */ - pop = ts_parse_stack_pop(stack, 0, 1, false); - AssertThat(pop.size, Equals(1)); - AssertThat(pop.contents[0].tree_count, Equals(1)); - AssertThat(pop.contents[0].trees[0], Equals(trees[0])); - AssertThat(ts_parse_stack_head(stack, 0), Equals(nullptr)); - }); - - it("does not count 'extra' trees toward the count given to pop()", [&]() { - ts_parse_stack_push(stack, 0, stateA, trees[0]); - ts_parse_stack_push(stack, 0, stateB, trees[1]); - ts_parse_stack_push(stack, 0, stateC, trees[2]); - ts_tree_set_extra(trees[1]); - - pop = ts_parse_stack_pop(stack, 0, 2, false); - AssertThat(pop.size, Equals(1)); - AssertThat(pop.contents[0].tree_count, Equals(3)); - AssertThat(pop.contents[0].trees[0], Equals(trees[0])); - AssertThat(pop.contents[0].trees[1], Equals(trees[1])); - AssertThat(pop.contents[0].trees[2], Equals(trees[2])); - AssertThat(ts_parse_stack_head(stack, 0), Equals(nullptr)); - }); - - it("can split a head and manipulate the two resulting heads independently", [&]() { - /* - * A0__B1__C2. - */ - ts_parse_stack_push(stack, 0, stateA, trees[0]); - ts_parse_stack_push(stack, 0, stateB, trees[1]); - ts_parse_stack_push(stack, 0, stateC, trees[2]); - - new_index = ts_parse_stack_split(stack, 0); - AssertThat(ts_parse_stack_head_count(stack), Equals(2)); - AssertThat(new_index, Equals(1)); - - /* - * A0__B1__C2__D3. - * \. - */ - ts_parse_stack_push(stack, 0, stateD, trees[3]); - ts_parse_stack_pop(stack, 1, 1, false); - - AssertThat(ts_parse_stack_head_count(stack), Equals(2)); - AssertThat(*ts_parse_stack_head(stack, 0), Equals({trees[3], stateD})); - AssertThat(*ts_parse_stack_head(stack, 1), Equals({trees[1], stateB})); - - /* - * A0__B1__C2__D3. - * \__E4__F3. - */ - ts_parse_stack_push(stack, 1, stateE, trees[4]); - ts_parse_stack_push(stack, 1, stateF, trees[3]); - - AssertThat(ts_parse_stack_head_count(stack), Equals(2)); - AssertThat(*ts_parse_stack_head(stack, 0), Equals({trees[3], stateD})); - AssertThat(*ts_parse_stack_head(stack, 1), Equals({trees[3], stateF})); - }); - - it("pops the entire stack when given a negative count", [&]() { - ts_parse_stack_push(stack, 0, stateA, trees[0]); - ts_parse_stack_push(stack, 0, stateB, trees[1]); - ts_parse_stack_push(stack, 0, stateC, trees[2]); - - pop = ts_parse_stack_pop(stack, 0, -1, false); - - AssertThat(pop.size, Equals(1)); - AssertThat(pop.contents[0].tree_count, Equals(3)); - AssertThat(pop.contents[0].trees[0], Equals(trees[0])); - AssertThat(pop.contents[0].trees[1], Equals(trees[1])); - AssertThat(pop.contents[0].trees[2], Equals(trees[2])); - }); - - describe("when same state is pushed onto two heads", [&]() { before_each([&]() { /* * A0__B1__C2. @@ -161,76 +76,169 @@ describe("ParseStack", [&]() { ts_parse_stack_push(stack, 0, stateA, trees[0]); ts_parse_stack_push(stack, 0, stateB, trees[1]); ts_parse_stack_push(stack, 0, stateC, trees[2]); + }); + + it("removes the given number of nodes from the stack", [&]() { + /* + * A0. + */ + pop = ts_parse_stack_pop(stack, 0, 2, false); + AssertThat(pop.size, Equals(1)); + AssertThat(pop.contents[0].tree_count, Equals(2)); + AssertThat(pop.contents[0].trees[0], Equals(trees[1])); + AssertThat(pop.contents[0].trees[1], Equals(trees[2])); + AssertThat(*ts_parse_stack_head(stack, 0), Equals({trees[0], stateA})); + + /* + * . + */ + pop = ts_parse_stack_pop(stack, 0, 1, false); + AssertThat(pop.size, Equals(1)); + AssertThat(pop.contents[0].tree_count, Equals(1)); + AssertThat(pop.contents[0].trees[0], Equals(trees[0])); + AssertThat(ts_parse_stack_head(stack, 0), Equals(nullptr)); + }); + + it("does not count 'extra' trees toward the count", [&]() { + ts_tree_set_extra(trees[1]); + + pop = ts_parse_stack_pop(stack, 0, 2, false); + AssertThat(pop.size, Equals(1)); + AssertThat(pop.contents[0].tree_count, Equals(3)); + AssertThat(pop.contents[0].trees[0], Equals(trees[0])); + AssertThat(pop.contents[0].trees[1], Equals(trees[1])); + AssertThat(pop.contents[0].trees[2], Equals(trees[2])); + AssertThat(ts_parse_stack_head(stack, 0), Equals(nullptr)); + }); + + it("pops the entire stack when given a negative count", [&]() { + pop = ts_parse_stack_pop(stack, 0, -1, false); + + AssertThat(pop.size, Equals(1)); + AssertThat(pop.contents[0].tree_count, Equals(3)); + AssertThat(pop.contents[0].trees[0], Equals(trees[0])); + AssertThat(pop.contents[0].trees[1], Equals(trees[1])); + AssertThat(pop.contents[0].trees[2], Equals(trees[2])); + }); + }); + + describe("split(head_index)", [&]() { + it("creates a new independent head with the same entries", [&]() { + /* + * A0__B1__C2. + */ + ts_parse_stack_push(stack, 0, stateA, trees[0]); + ts_parse_stack_push(stack, 0, stateB, trees[1]); + ts_parse_stack_push(stack, 0, stateC, trees[2]); + + int new_index = ts_parse_stack_split(stack, 0); + AssertThat(ts_parse_stack_head_count(stack), Equals(2)); + AssertThat(new_index, Equals(1)); /* * A0__B1__C2__D3. - * \__E4__F5. + * \. */ - ts_parse_stack_split(stack, 0); ts_parse_stack_push(stack, 0, stateD, trees[3]); ts_parse_stack_pop(stack, 1, 1, false); - ts_parse_stack_push(stack, 1, stateE, trees[4]); - ts_parse_stack_push(stack, 1, stateF, trees[5]); AssertThat(ts_parse_stack_head_count(stack), Equals(2)); AssertThat(*ts_parse_stack_head(stack, 0), Equals({trees[3], stateD})); - AssertThat(*ts_parse_stack_head(stack, 1), Equals({trees[5], stateF})); + AssertThat(*ts_parse_stack_head(stack, 1), Equals({trees[1], stateB})); + + /* + * A0__B1__C2__D3. + * \__E4__F3. + */ + ts_parse_stack_push(stack, 1, stateE, trees[4]); + ts_parse_stack_push(stack, 1, stateF, trees[3]); + + AssertThat(ts_parse_stack_head_count(stack), Equals(2)); + AssertThat(*ts_parse_stack_head(stack, 0), Equals({trees[3], stateD})); + AssertThat(*ts_parse_stack_head(stack, 1), Equals({trees[3], stateF})); }); - describe("when the trees are identical", [&]() { - it("merges the heads, and removes nodes along both heads on subsequent pop operations", [&]() { - /* - * A0__B1__C2__D3__G6. - * \__E4__F5__/ - */ - merged = ts_parse_stack_push(stack, 0, stateG, trees[6]); - AssertThat(merged, IsFalse()); - merged = ts_parse_stack_push(stack, 1, stateG, trees[6]); - AssertThat(merged, IsTrue()); - - AssertThat(ts_parse_stack_head_count(stack), Equals(1)); - const ParseStackEntry *entry1 = ts_parse_stack_head(stack, 0); - AssertThat(*entry1, Equals({trees[6], stateG})); - AssertThat(ts_parse_stack_entry_next_count(entry1), Equals(2)); - AssertThat(*ts_parse_stack_entry_next(entry1, 0), Equals({trees[3], stateD})); - AssertThat(*ts_parse_stack_entry_next(entry1, 1), Equals({trees[5], stateF})); + describe("when same state is pushed onto two heads", [&]() { + bool merged; + before_each([&]() { /* * A0__B1__C2. - * \__E4. */ - pop = ts_parse_stack_pop(stack, 0, 2, false); + ts_parse_stack_push(stack, 0, stateA, trees[0]); + ts_parse_stack_push(stack, 0, stateB, trees[1]); + ts_parse_stack_push(stack, 0, stateC, trees[2]); - AssertThat(pop.size, Equals(2)); - AssertThat(pop.contents[0].tree_count, Equals(2)); - AssertThat(pop.contents[0].trees[0], Equals(trees[3])); - AssertThat(pop.contents[0].trees[1], Equals(trees[6])); - AssertThat(pop.contents[1].tree_count, Equals(2)); - AssertThat(pop.contents[1].trees[0], Equals(trees[5])); - AssertThat(pop.contents[1].trees[1], Equals(trees[6])); + /* + * A0__B1__C2__D3. + * \__E4__F5. + */ + ts_parse_stack_split(stack, 0); + ts_parse_stack_push(stack, 0, stateD, trees[3]); + ts_parse_stack_pop(stack, 1, 1, false); + ts_parse_stack_push(stack, 1, stateE, trees[4]); + ts_parse_stack_push(stack, 1, stateF, trees[5]); AssertThat(ts_parse_stack_head_count(stack), Equals(2)); - AssertThat(*ts_parse_stack_head(stack, 0), Equals({trees[2], stateC})); - AssertThat(*ts_parse_stack_head(stack, 1), Equals({trees[4], stateE})); + AssertThat(*ts_parse_stack_head(stack, 0), Equals({trees[3], stateD})); + AssertThat(*ts_parse_stack_head(stack, 1), Equals({trees[5], stateF})); }); - }); - describe("when the trees are different", [&]() { - it("merges the heads by creating an ambiguity node", [&]() { - /* - * A0__B1__C2__D3__G(6|7) - * \__E4__F5____/ - */ - merged = ts_parse_stack_push(stack, 0, stateG, trees[6]); - AssertThat(merged, IsFalse()); - merged = ts_parse_stack_push(stack, 1, stateG, trees[7]); - AssertThat(merged, IsTrue()); + describe("when the trees are identical", [&]() { + it("merges the heads, and removes nodes along both heads on subsequent pop operations", [&]() { + /* + * A0__B1__C2__D3__G6. + * \__E4__F5__/ + */ + merged = ts_parse_stack_push(stack, 0, stateG, trees[6]); + AssertThat(merged, IsFalse()); + merged = ts_parse_stack_push(stack, 1, stateG, trees[6]); + AssertThat(merged, IsTrue()); - AssertThat(ts_parse_stack_head_count(stack), Equals(1)); - AssertThat(*ts_parse_stack_head(stack, 0), Equals({ - ts_tree_make_ambiguity(2, tree_array({ trees[6], trees[7] })), - stateG - })); + AssertThat(ts_parse_stack_head_count(stack), Equals(1)); + const ParseStackEntry *entry1 = ts_parse_stack_head(stack, 0); + AssertThat(*entry1, Equals({trees[6], stateG})); + AssertThat(ts_parse_stack_entry_next_count(entry1), Equals(2)); + AssertThat(*ts_parse_stack_entry_next(entry1, 0), Equals({trees[3], stateD})); + AssertThat(*ts_parse_stack_entry_next(entry1, 1), Equals({trees[5], stateF})); + + /* + * A0__B1__C2. + * \__E4. + */ + ParseStackPopResultList pop = ts_parse_stack_pop(stack, 0, 2, false); + + AssertThat(pop.size, Equals(2)); + AssertThat(pop.contents[0].tree_count, Equals(2)); + AssertThat(pop.contents[0].trees[0], Equals(trees[3])); + AssertThat(pop.contents[0].trees[1], Equals(trees[6])); + AssertThat(pop.contents[1].tree_count, Equals(2)); + AssertThat(pop.contents[1].trees[0], Equals(trees[5])); + AssertThat(pop.contents[1].trees[1], Equals(trees[6])); + + AssertThat(ts_parse_stack_head_count(stack), Equals(2)); + AssertThat(*ts_parse_stack_head(stack, 0), Equals({trees[2], stateC})); + AssertThat(*ts_parse_stack_head(stack, 1), Equals({trees[4], stateE})); + }); + }); + + describe("when the trees are different", [&]() { + it("merges the heads by creating an ambiguity node", [&]() { + /* + * A0__B1__C2__D3__G(6|7) + * \__E4__F5____/ + */ + merged = ts_parse_stack_push(stack, 0, stateG, trees[6]); + AssertThat(merged, IsFalse()); + merged = ts_parse_stack_push(stack, 1, stateG, trees[7]); + AssertThat(merged, IsTrue()); + + AssertThat(ts_parse_stack_head_count(stack), Equals(1)); + AssertThat(*ts_parse_stack_head(stack, 0), Equals({ + ts_tree_make_ambiguity(2, tree_array({ trees[6], trees[7] })), + stateG + })); + }); }); }); });