diff --git a/src/runtime/parser.c b/src/runtime/parser.c index df7395d0..7d861b25 100644 --- a/src/runtime/parser.c +++ b/src/runtime/parser.c @@ -97,13 +97,13 @@ static bool parser__breakdown_top_of_stack(Parser *self, StackVersion version) { state = ts_language_next_state(self->language, state, child->symbol); } + ts_tree_retain(child); ts_stack_push(self->stack, slice.version, child, pending, state); } for (uint32_t j = 1; j < slice.trees.size; j++) { Tree *tree = slice.trees.contents[j]; ts_stack_push(self->stack, slice.version, tree, false, state); - ts_tree_release(&self->tree_pool, tree); } LOG("breakdown_top_of_stack tree:%s", SYM_NAME(parent->symbol)); @@ -638,7 +638,6 @@ static void parser__shift(Parser *self, StackVersion version, TSStateId state, self->stack, version, ts_tree_last_external_token(lookahead) ); } - ts_tree_release(&self->tree_pool, lookahead); } static bool parser__replace_children(Parser *self, Tree *tree, Tree **children, uint32_t count) { @@ -713,11 +712,9 @@ static StackPopResult parser__reduce(Parser *self, StackVersion version, TSSymbo // Push the parent node onto the stack, along with any extra tokens that // were previously on top of the stack. ts_stack_push(self->stack, slice.version, parent, false, next_state); - ts_tree_release(&self->tree_pool, parent); for (uint32_t j = parent->child_count; j < slice.trees.size; j++) { Tree *tree = slice.trees.contents[j]; ts_stack_push(self->stack, slice.version, tree, false, next_state); - ts_tree_release(&self->tree_pool, tree); } } @@ -756,6 +753,7 @@ static void parser__accept(Parser *self, StackVersion version, Tree *lookahead) { lookahead->extra = true; assert(lookahead->symbol == ts_builtin_sym_end); + ts_tree_retain(lookahead); ts_stack_push(self->stack, version, lookahead, false, 1); StackPopResult pop = ts_stack_pop_all(self->stack, version); @@ -769,8 +767,9 @@ static void parser__accept(Parser *self, StackVersion version, if (!child->extra) { root = ts_tree_make_copy(&self->tree_pool, child); root->child_count = 0; - for (uint32_t k = 0; k < child->child_count; k++) + for (uint32_t k = 0; k < child->child_count; k++) { ts_tree_retain(child->children[k]); + } array_splice(&trees, j, 1, child->child_count, child->children); ts_tree_set_children(root, trees.size, trees.contents, self->language); ts_tree_release(&self->tree_pool, child); @@ -920,7 +919,6 @@ static void parser__handle_error(Parser *self, StackVersion version, TSSymbol lo missing_tree, false, state_after_missing_symbol ); - ts_tree_release(&self->tree_pool, missing_tree); if (parser__do_all_potential_reductions( self, version_with_missing_tree, @@ -960,12 +958,10 @@ static void parser__halt_parse(Parser *self) { Tree *filler_node = ts_tree_make_error(&self->tree_pool, remaining_length, length_zero(), 0, self->language); filler_node->visible = false; ts_stack_push(self->stack, 0, filler_node, false, 0); - ts_tree_release(&self->tree_pool, filler_node); TreeArray children = array_new(); Tree *root_error = ts_tree_make_error_node(&self->tree_pool, &children, self->language); ts_stack_push(self->stack, 0, root_error, false, 0); - ts_tree_release(&self->tree_pool, root_error); Tree *eof = ts_tree_make_leaf(&self->tree_pool, ts_builtin_sym_end, length_zero(), length_zero(), self->language); parser__accept(self, 0, eof); @@ -1008,7 +1004,6 @@ static bool parser__recover_to_state(Parser *self, StackVersion version, unsigne Tree *error = ts_tree_make_error_node(&self->tree_pool, &slice.trees, self->language); error->extra = true; ts_stack_push(self->stack, slice.version, error, false, goal_state); - ts_tree_release(&self->tree_pool, error); } else { array_delete(&slice.trees); } @@ -1016,7 +1011,6 @@ static bool parser__recover_to_state(Parser *self, StackVersion version, unsigne for (unsigned j = 0; j < trailing_extras.size; j++) { Tree *tree = trailing_extras.contents[j]; ts_stack_push(self->stack, slice.version, tree, false, goal_state); - ts_tree_release(&self->tree_pool, tree); } previous_version = slice.version; @@ -1077,7 +1071,6 @@ static void parser__recover(Parser *self, StackVersion version, Tree *lookahead) TreeArray children = array_new(); Tree *parent = ts_tree_make_error_node(&self->tree_pool, &children, self->language); ts_stack_push(self->stack, version, parent, false, 1); - ts_tree_release(&self->tree_pool, parent); parser__accept(self, version, lookahead); return; } @@ -1166,7 +1159,6 @@ static void parser__advance(Parser *self, StackVersion version, ReusableNode *re } else if (!parser__breakdown_top_of_stack(self, version)) { if (state == ERROR_STATE) { ts_stack_push(self->stack, version, lookahead, false, ERROR_STATE); - ts_tree_release(&self->tree_pool, lookahead); return; } diff --git a/src/runtime/stack.c b/src/runtime/stack.c index 45d089f1..c7252e03 100644 --- a/src/runtime/stack.c +++ b/src/runtime/stack.c @@ -128,7 +128,6 @@ static StackNode *stack_node_new(StackNode *previous_node, Tree *tree, bool is_p if (tree) { node->depth = previous_node->depth; if (!tree->extra) node->depth++; - ts_tree_retain(tree); node->error_cost += tree->error_cost; node->position = length_add(node->position, ts_tree_total_size(tree)); node->dynamic_precedence += tree->dynamic_precedence; diff --git a/test/runtime/stack_test.cc b/test/runtime/stack_test.cc index bf565dcf..f0eb3546 100644 --- a/test/runtime/stack_test.cc +++ b/test/runtime/stack_test.cc @@ -100,6 +100,11 @@ describe("Stack", [&]() { AssertThat(record_alloc::outstanding_allocation_indices(), IsEmpty()); }); + auto push = [&](StackVersion version, Tree *tree, TSStateId state) { + ts_tree_retain(tree); + ts_stack_push(stack, version, tree, false, state); + }; + describe("push(version, tree, is_pending, state)", [&]() { it("adds entries to the given version of the stack", [&]() { AssertThat(ts_stack_version_count(stack), Equals(1)); @@ -107,17 +112,17 @@ describe("Stack", [&]() { AssertThat(ts_stack_top_position(stack, 0), Equals(length_zero())); // . <──0── A* - ts_stack_push(stack, 0, trees[0], false, stateA); + push(0, trees[0], stateA); AssertThat(ts_stack_top_state(stack, 0), Equals(stateA)); AssertThat(ts_stack_top_position(stack, 0), Equals(tree_len)); // . <──0── A <──1── B* - ts_stack_push(stack, 0, trees[1], false, stateB); + push(0, trees[1], stateB); AssertThat(ts_stack_top_state(stack, 0), Equals(stateB)); AssertThat(ts_stack_top_position(stack, 0), Equals(tree_len * 2)); // . <──0── A <──1── B <──2── C* - ts_stack_push(stack, 0, trees[2], false, stateC); + push(0, trees[2], stateC); AssertThat(ts_stack_top_state(stack, 0), Equals(stateC)); AssertThat(ts_stack_top_position(stack, 0), Equals(tree_len * 3)); @@ -135,7 +140,7 @@ describe("Stack", [&]() { // . <──0── A <─* // ↑ // └───* - ts_stack_push(stack, 0, trees[0], false, stateA); + push(0, trees[0], stateA); ts_stack_copy_version(stack, 0); }); @@ -143,10 +148,10 @@ describe("Stack", [&]() { // . <──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); + push(0, trees[1], stateB); + push(1, trees[2], stateC); + push(0, trees[3], stateD); + push(1, trees[4], stateD); // . <──0── A <──1── B <──3── D* // ↑ | @@ -166,8 +171,8 @@ describe("Stack", [&]() { // . <──0── A <──1── B* // ↑ // └───2─── C* - ts_stack_push(stack, 0, trees[1], false, stateB); - ts_stack_push(stack, 1, trees[2], false, stateC); + push(0, trees[1], stateB); + push(1, trees[2], stateC); AssertThat(ts_stack_merge(stack, 0, 1), IsFalse()); AssertThat(ts_stack_version_count(stack), Equals(2)); @@ -178,10 +183,10 @@ 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); + push(0, trees[1], stateB); + push(1, trees[2], stateC); + push(0, trees[3], stateD); + push(1, trees[4], stateD); AssertThat(ts_stack_merge(stack, 0, 1), IsFalse()); AssertThat(ts_stack_version_count(stack), Equals(2)); @@ -192,12 +197,12 @@ 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, 1, trees[4], false, stateD); - ts_stack_push(stack, 0, trees[5], false, stateE); - ts_stack_push(stack, 1, trees[5], false, stateE); + push(0, trees[1], stateB); + push(1, trees[2], stateC); + push(0, trees[3], stateD); + push(1, trees[4], stateD); + push(0, trees[5], stateE); + push(1, trees[5], stateE); // . <──0── A <──1── B <──3── D <──5── E* // ↑ | @@ -223,9 +228,9 @@ describe("Stack", [&]() { 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); + push(0, trees[1], stateB); + push(1, trees[2], stateA); + push(1, trees[1], stateB); // . <──0── A <──1── B* AssertThat(ts_stack_merge(stack, 0, 1), IsTrue()); @@ -242,9 +247,9 @@ describe("Stack", [&]() { describe("pop_count(version, count)", [&]() { before_each([&]() { // . <──0── A <──1── B <──2── C* - ts_stack_push(stack, 0, trees[0], false, stateA); - ts_stack_push(stack, 0, trees[1], false, stateB); - ts_stack_push(stack, 0, trees[2], false, stateC); + push(0, trees[0], stateA); + push(0, trees[1], stateB); + push(0, trees[2], stateC); }); it("creates a new version with the given number of entries removed", [&]() { @@ -284,14 +289,14 @@ describe("Stack", [&]() { // . <──0── A <──1── B <──2── C <──3── D <──10── I* // ↑ | // └───4─── E <──5── F <──6───┘ - ts_stack_push(stack, 0, trees[3], false, stateD); + push(0, trees[3], stateD); StackPopResult pop = ts_stack_pop_count(stack, 0, 3); free_slice_array(&pool,&pop.slices); - ts_stack_push(stack, 1, trees[4], false, stateE); - ts_stack_push(stack, 1, trees[5], false, stateF); - ts_stack_push(stack, 1, trees[6], false, stateD); + push(1, trees[4], stateE); + push(1, trees[5], stateF); + push(1, trees[6], stateD); ts_stack_merge(stack, 0, 1); - ts_stack_push(stack, 0, trees[10], false, stateI); + push(0, trees[10], stateI); AssertThat(ts_stack_version_count(stack), Equals(1)); AssertThat(get_stack_entries(stack, 0), Equals(vector({ @@ -407,10 +412,10 @@ describe("Stack", [&]() { // └───7─── G <──8── H <──9───┘ StackPopResult pop = ts_stack_pop_count(stack, 0, 4); free_slice_array(&pool,&pop.slices); - ts_stack_push(stack, 1, trees[7], false, stateG); - ts_stack_push(stack, 1, trees[8], false, stateH); - ts_stack_push(stack, 1, trees[9], false, stateD); - ts_stack_push(stack, 1, trees[10], false, stateI); + push(1, trees[7], stateG); + push(1, trees[8], stateH); + push(1, trees[9], stateD); + push(1, trees[10], stateI); ts_stack_merge(stack, 0, 1); AssertThat(ts_stack_version_count(stack), Equals(1)); @@ -463,11 +468,12 @@ describe("Stack", [&]() { describe("pop_pending(version)", [&]() { before_each([&]() { - ts_stack_push(stack, 0, trees[0], false, stateA); + push(0, trees[0], stateA); }); it("removes the top node from the stack if it was pushed in pending mode", [&]() { ts_stack_push(stack, 0, trees[1], true, stateB); + ts_tree_retain(trees[1]); StackPopResult pop = ts_stack_pop_pending(stack, 0); AssertThat(pop.slices.size, Equals(1)); @@ -482,12 +488,13 @@ describe("Stack", [&]() { it("skips entries whose trees are extra", [&]() { ts_stack_push(stack, 0, trees[1], true, stateB); + ts_tree_retain(trees[1]); trees[2]->extra = true; trees[3]->extra = true; - ts_stack_push(stack, 0, trees[2], false, stateB); - ts_stack_push(stack, 0, trees[3], false, stateB); + push(0, trees[2], stateB); + push(0, trees[3], stateB); StackPopResult pop = ts_stack_pop_pending(stack, 0); AssertThat(pop.slices.size, Equals(1)); @@ -503,7 +510,7 @@ describe("Stack", [&]() { }); it("does nothing if the top node was not pushed in pending mode", [&]() { - ts_stack_push(stack, 0, trees[1], false, stateB); + push(0, trees[1], stateB); StackPopResult pop = ts_stack_pop_pending(stack, 0); AssertThat(pop.slices.size, Equals(0)); @@ -544,8 +551,8 @@ describe("Stack", [&]() { ts_external_token_state_init(&trees[2]->external_token_state, "ABCD", 2); ts_stack_copy_version(stack, 0); - ts_stack_push(stack, 0, trees[0], false, 5); - ts_stack_push(stack, 1, trees[0], false, 5); + push(0, trees[0], 5); + push(1, trees[0], 5); ts_stack_set_last_external_token(stack, 0, trees[1]); ts_stack_set_last_external_token(stack, 1, trees[2]); @@ -558,8 +565,8 @@ describe("Stack", [&]() { ts_external_token_state_init(&trees[2]->external_token_state, "abcd", 2); ts_stack_copy_version(stack, 0); - ts_stack_push(stack, 0, trees[0], false, 5); - ts_stack_push(stack, 1, trees[0], false, 5); + push(0, trees[0], 5); + push(1, trees[0], 5); ts_stack_set_last_external_token(stack, 0, trees[1]); ts_stack_set_last_external_token(stack, 1, trees[2]); @@ -569,8 +576,8 @@ describe("Stack", [&]() { it("does not distinguish between an *empty* external token state and *no* external token state", [&]() { ts_stack_copy_version(stack, 0); - ts_stack_push(stack, 0, trees[0], false, 5); - ts_stack_push(stack, 1, trees[0], false, 5); + push(0, trees[0], 5); + push(1, trees[0], 5); ts_stack_set_last_external_token(stack, 0, trees[1]);