diff --git a/src/runtime/document.c b/src/runtime/document.c index 94dd99dc..998b74bd 100644 --- a/src/runtime/document.c +++ b/src/runtime/document.c @@ -8,23 +8,17 @@ TSDocument *ts_document_new() { TSDocument *self = ts_calloc(1, sizeof(TSDocument)); - if (!self) - goto error; - - if (!parser_init(&self->parser)) - goto error; - + parser_init(&self->parser); + array_init(&self->tree_path1); + array_init(&self->tree_path2); return self; - -error: - if (self) - ts_free(self); - return NULL; } void ts_document_free(TSDocument *self) { + if (self->tree) ts_tree_release(&self->parser.tree_pool, self->tree); + if (self->tree_path1.contents) array_delete(&self->tree_path1); + if (self->tree_path2.contents) array_delete(&self->tree_path2); parser_destroy(&self->parser); - if (self->tree) ts_tree_release(self->tree); ts_document_set_input(self, (TSInput){ NULL, NULL, @@ -43,7 +37,7 @@ void ts_document_set_language(TSDocument *self, const TSLanguage *language) { ts_document_invalidate(self); parser_set_language(&self->parser, language); if (self->tree) { - ts_tree_release(self->tree); + ts_tree_release(&self->parser.tree_pool, self->tree); self->tree = NULL; } } @@ -140,12 +134,12 @@ void ts_document_parse_with_options(TSDocument *self, TSParseOptions options) { if (options.changed_ranges && options.changed_range_count) { *options.changed_range_count = ts_tree_get_changed_ranges( - old_tree, tree, &self->parser.tree_path1, &self->parser.tree_path2, + old_tree, tree, &self->tree_path1, &self->tree_path2, self->parser.language, options.changed_ranges ); } - ts_tree_release(old_tree); + ts_tree_release(&self->parser.tree_pool, old_tree); } self->tree = tree; diff --git a/src/runtime/document.h b/src/runtime/document.h index e2015f9b..0be05f14 100644 --- a/src/runtime/document.h +++ b/src/runtime/document.h @@ -3,12 +3,15 @@ #include "runtime/parser.h" #include "runtime/tree.h" +#include "runtime/get_changed_ranges.h" #include struct TSDocument { Parser parser; TSInput input; Tree *tree; + TreePath tree_path1; + TreePath tree_path2; size_t parse_count; bool valid; bool owns_input; diff --git a/src/runtime/get_changed_ranges.h b/src/runtime/get_changed_ranges.h index b6b5132a..360cdbd4 100644 --- a/src/runtime/get_changed_ranges.h +++ b/src/runtime/get_changed_ranges.h @@ -3,6 +3,15 @@ #include "runtime/tree.h" +typedef struct { + Tree *tree; + Length position; + uint32_t child_index; + uint32_t structural_child_index; +} TreePathEntry; + +typedef Array(TreePathEntry) TreePath; + unsigned ts_tree_get_changed_ranges( Tree *old_tree, Tree *new_tree, TreePath *path1, TreePath *path2, const TSLanguage *language, TSRange **ranges diff --git a/src/runtime/parser.c b/src/runtime/parser.c index b89eca39..ddd3e3b9 100644 --- a/src/runtime/parser.c +++ b/src/runtime/parser.c @@ -103,7 +103,7 @@ static bool parser__breakdown_top_of_stack(Parser *self, StackVersion version) { 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(tree); + ts_tree_release(&self->tree_pool, tree); } LOG("breakdown_top_of_stack tree:%s", SYM_NAME(parent->symbol)); @@ -111,7 +111,7 @@ static bool parser__breakdown_top_of_stack(Parser *self, StackVersion version) { ts_stack_decrease_push_count(self->stack, slice.version, parent->child_count + 1); - ts_tree_release(parent); + ts_tree_release(&self->tree_pool, parent); array_delete(&slice.trees); } } while (pending); @@ -130,7 +130,7 @@ static void parser__breakdown_lookahead(Parser *self, Tree **lookahead, } if (did_break_down) { - ts_tree_release(*lookahead); + ts_tree_release(&self->tree_pool, *lookahead); ts_tree_retain(*lookahead = reusable_node->tree); } } @@ -411,7 +411,7 @@ static Tree *parser__lex(Parser *self, StackVersion version, TSStateId parse_sta if (skipped_error) { Length padding = length_sub(error_start_position, start_position); Length size = length_sub(error_end_position, error_start_position); - result = ts_tree_make_error(size, padding, first_error_character, self->language); + result = ts_tree_make_error(&self->tree_pool, size, padding, first_error_character, self->language); } else { TSSymbol symbol = self->lexer.data.result_symbol; if (found_external_token) { @@ -424,7 +424,7 @@ static Tree *parser__lex(Parser *self, StackVersion version, TSStateId parse_sta Length padding = length_sub(self->lexer.token_start_position, start_position); Length size = length_sub(self->lexer.token_end_position, self->lexer.token_start_position); - result = ts_tree_make_leaf(symbol, padding, size, self->language); + result = ts_tree_make_leaf(&self->tree_pool, symbol, padding, size, self->language); if (found_external_token) { result->has_external_tokens = true; @@ -463,8 +463,8 @@ static void parser__set_cached_token(Parser *self, size_t byte_index, Tree *last TokenCache *cache = &self->token_cache; if (token) ts_tree_retain(token); if (last_external_token) ts_tree_retain(last_external_token); - if (cache->token) ts_tree_release(cache->token); - if (cache->last_external_token) ts_tree_release(cache->last_external_token); + if (cache->token) ts_tree_release(&self->tree_pool, cache->token); + if (cache->last_external_token) ts_tree_release(&self->tree_pool, cache->last_external_token); cache->token = token; cache->byte_index = byte_index; cache->last_external_token = last_external_token; @@ -611,7 +611,7 @@ static void parser__shift(Parser *self, StackVersion version, TSStateId state, Tree *lookahead, bool extra) { if (extra != lookahead->extra) { if (ts_stack_version_count(self->stack) > 1) { - lookahead = ts_tree_make_copy(lookahead); + lookahead = ts_tree_make_copy(&self->tree_pool, lookahead); } else { ts_tree_retain(lookahead); } @@ -627,7 +627,7 @@ static void parser__shift(Parser *self, StackVersion version, TSStateId state, self->stack, version, ts_tree_last_external_token(lookahead) ); } - ts_tree_release(lookahead); + ts_tree_release(&self->tree_pool, lookahead); } static bool parser__replace_children(Parser *self, Tree *tree, Tree **children, uint32_t count) { @@ -660,7 +660,7 @@ static StackPopResult parser__reduce(Parser *self, StackVersion version, TSSymbo child_count--; } - Tree *parent = ts_tree_make_node( + Tree *parent = ts_tree_make_node(&self->tree_pool, symbol, child_count, slice.trees.contents, alias_sequence_id, self->language ); @@ -679,10 +679,10 @@ static StackPopResult parser__reduce(Parser *self, StackVersion version, TSSymbo } if (parser__replace_children(self, parent, next_slice.trees.contents, child_count)) { - ts_tree_array_delete(&slice.trees); + ts_tree_array_delete(&self->tree_pool, &slice.trees); slice = next_slice; } else { - ts_tree_array_delete(&next_slice.trees); + ts_tree_array_delete(&self->tree_pool, &next_slice.trees); } } @@ -702,11 +702,11 @@ 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(parent); + 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(tree); + ts_tree_release(&self->tree_pool, tree); } } @@ -754,13 +754,13 @@ static void parser__accept(Parser *self, StackVersion version, for (uint32_t j = trees.size - 1; j + 1 > 0; j--) { Tree *child = trees.contents[j]; if (!child->extra) { - root = ts_tree_make_copy(child); + root = ts_tree_make_copy(&self->tree_pool, child); root->child_count = 0; 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(child); + ts_tree_release(&self->tree_pool, child); break; } } @@ -769,10 +769,10 @@ static void parser__accept(Parser *self, StackVersion version, if (self->finished_tree) { if (parser__select_tree(self, self->finished_tree, root)) { - ts_tree_release(self->finished_tree); + ts_tree_release(&self->tree_pool, self->finished_tree); self->finished_tree = root; } else { - ts_tree_release(root); + ts_tree_release(&self->tree_pool, root); } } else { self->finished_tree = root; @@ -885,19 +885,19 @@ static void parser__halt_parse(Parser *self) { ts_stack_top_position(self->stack, 0) ); - Tree *filler_node = ts_tree_make_error(remaining_length, length_zero(), 0, self->language); + 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(filler_node); + ts_tree_release(&self->tree_pool, filler_node); TreeArray children = array_new(); - Tree *root_error = ts_tree_make_error_node(&children, self->language); + 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(root_error); + ts_tree_release(&self->tree_pool, root_error); - Tree *eof = ts_tree_make_leaf(ts_builtin_sym_end, length_zero(), length_zero(), self->language); + Tree *eof = ts_tree_make_leaf(&self->tree_pool, ts_builtin_sym_end, length_zero(), length_zero(), self->language); parser__accept(self, 0, eof); - ts_tree_release(eof); + ts_tree_release(&self->tree_pool, eof); } static void parser__recover(Parser *self, StackVersion version, Tree *lookahead) { @@ -924,12 +924,12 @@ static void parser__recover(Parser *self, StackVersion version, Tree *lookahead) for (unsigned j = 0; j < pop.slices.size; j++) { StackSlice slice = pop.slices.contents[j]; if (slice.version == previous_version) { - ts_tree_array_delete(&slice.trees); + ts_tree_array_delete(&self->tree_pool, &slice.trees); continue; } if (ts_stack_top_state(self->stack, slice.version) != entry.state) { - ts_tree_array_delete(&slice.trees); + ts_tree_array_delete(&self->tree_pool, &slice.trees); ts_stack_halt(self->stack, slice.version); continue; } @@ -945,10 +945,10 @@ static void parser__recover(Parser *self, StackVersion version, Tree *lookahead) TreeArray trailing_extras = ts_tree_array_remove_trailing_extras(&slice.trees); if (slice.trees.size > 0) { - Tree *error = ts_tree_make_error_node(&slice.trees, self->language); + 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, entry.state); - ts_tree_release(error); + ts_tree_release(&self->tree_pool, error); } else { array_delete(&slice.trees); } @@ -957,7 +957,7 @@ static void parser__recover(Parser *self, StackVersion version, Tree *lookahead) for (unsigned k = 0; k < trailing_extras.size; k++) { Tree *tree = trailing_extras.contents[k]; ts_stack_push(self->stack, slice.version, tree, false, entry.state); - ts_tree_release(tree); + ts_tree_release(&self->tree_pool, tree); } array_delete(&trailing_extras); @@ -990,9 +990,9 @@ static void parser__recover(Parser *self, StackVersion version, Tree *lookahead) if (lookahead->symbol == ts_builtin_sym_end) { LOG("recover_eof"); TreeArray children = array_new(); - Tree *parent = ts_tree_make_error_node(&children, self->language); + 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(parent); + ts_tree_release(&self->tree_pool, parent); parser__accept(self, version, lookahead); return; } @@ -1037,7 +1037,7 @@ static void parser__advance(Parser *self, StackVersion version, ReusableNode *re parser__shift(self, version, next_state, lookahead, action.params.extra); if (lookahead == reusable_node->tree) reusable_node_pop(reusable_node); - ts_tree_release(lookahead); + ts_tree_release(&self->tree_pool, lookahead); return; } @@ -1056,7 +1056,7 @@ static void parser__advance(Parser *self, StackVersion version, ReusableNode *re case TSParseActionTypeAccept: { LOG("accept"); parser__accept(self, version, lookahead); - ts_tree_release(lookahead); + ts_tree_release(&self->tree_pool, lookahead); return; } @@ -1066,7 +1066,7 @@ static void parser__advance(Parser *self, StackVersion version, ReusableNode *re } parser__recover(self, version, lookahead); if (lookahead == reusable_node->tree) reusable_node_pop(reusable_node); - ts_tree_release(lookahead); + ts_tree_release(&self->tree_pool, lookahead); return; } } @@ -1078,16 +1078,16 @@ 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(lookahead); + ts_tree_release(&self->tree_pool, lookahead); return; } parser__handle_error(self, version, lookahead->first_leaf.symbol); if (ts_stack_is_halted(self->stack, version)) { - ts_tree_release(lookahead); + ts_tree_release(&self->tree_pool, lookahead); return; } else if (lookahead->size.bytes == 0) { - ts_tree_release(lookahead); + ts_tree_release(&self->tree_pool, lookahead); state = ts_stack_top_state(self->stack, version); lookahead = parser__get_lookahead(self, version, &state, reusable_node, &table_entry); } @@ -1101,10 +1101,9 @@ static void parser__advance(Parser *self, StackVersion version, ReusableNode *re bool parser_init(Parser *self) { ts_lexer_init(&self->lexer); array_init(&self->reduce_actions); - array_init(&self->tree_path1); - array_init(&self->tree_path2); array_grow(&self->reduce_actions, 4); - self->stack = ts_stack_new(); + ts_tree_pool_init(&self->tree_pool); + self->stack = ts_stack_new(&self->tree_pool); self->finished_tree = NULL; parser__set_cached_token(self, 0, NULL, NULL); return true; @@ -1127,10 +1126,7 @@ void parser_destroy(Parser *self) { ts_stack_delete(self->stack); if (self->reduce_actions.contents) array_delete(&self->reduce_actions); - if (self->tree_path1.contents) - array_delete(&self->tree_path1); - if (self->tree_path2.contents) - array_delete(&self->tree_path2); + ts_tree_pool_delete(&self->tree_pool); parser_set_language(self, NULL); } @@ -1182,6 +1178,6 @@ Tree *parser_parse(Parser *self, TSInput input, Tree *old_tree, bool halt_on_err LOG_TREE(); ts_stack_clear(self->stack); parser__set_cached_token(self, 0, NULL, NULL); - ts_tree_assign_parents(self->finished_tree, &self->tree_path1, self->language); + ts_tree_assign_parents(self->finished_tree, &self->tree_pool, self->language); return self->finished_tree; } diff --git a/src/runtime/parser.h b/src/runtime/parser.h index 533cdf3a..a3b88eab 100644 --- a/src/runtime/parser.h +++ b/src/runtime/parser.h @@ -10,6 +10,7 @@ extern "C" { #include "runtime/lexer.h" #include "runtime/reusable_node.h" #include "runtime/reduce_action.h" +#include "runtime/tree.h" typedef struct { Tree *token; @@ -20,14 +21,13 @@ typedef struct { typedef struct { Lexer lexer; Stack *stack; + TreePool tree_pool; const TSLanguage *language; ReduceActionSet reduce_actions; Tree *finished_tree; Tree scratch_tree; TokenCache token_cache; ReusableNode reusable_node; - TreePath tree_path1; - TreePath tree_path2; void *external_scanner_payload; bool in_ambiguity; bool print_debugging_graphs; diff --git a/src/runtime/stack.c b/src/runtime/stack.c index a5fdc94c..8e85b363 100644 --- a/src/runtime/stack.c +++ b/src/runtime/stack.c @@ -63,6 +63,7 @@ struct Stack { Array(Iterator) iterators; StackNodeArray node_pool; StackNode *base_node; + TreePool *tree_pool; }; typedef StackIterateAction (*StackIterateInternalCallback)(void *, const Iterator *); @@ -75,7 +76,7 @@ static void stack_node_retain(StackNode *self) { assert(self->ref_count != 0); } -static void stack_node_release(StackNode *self, StackNodeArray *pool) { +static void stack_node_release(StackNode *self, StackNodeArray *pool, TreePool *tree_pool) { recur: assert(self->ref_count != 0); self->ref_count--; @@ -84,10 +85,10 @@ recur: StackNode *first_predecessor = NULL; if (self->link_count > 0) { for (unsigned i = self->link_count - 1; i > 0; i--) { - if (self->links[i].tree) ts_tree_release(self->links[i].tree); - stack_node_release(self->links[i].node, pool); + if (self->links[i].tree) ts_tree_release(tree_pool, self->links[i].tree); + stack_node_release(self->links[i].node, pool, tree_pool); } - if (self->links[0].tree) ts_tree_release(self->links[0].tree); + if (self->links[0].tree) ts_tree_release(tree_pool, self->links[0].tree); first_predecessor = self->links[0].node; } @@ -187,16 +188,16 @@ static void stack_node_add_link(StackNode *self, StackLink link) { } } -static void stack_head_delete(StackHead *self, StackNodeArray *pool) { +static void stack_head_delete(StackHead *self, StackNodeArray *pool, TreePool *tree_pool) { if (self->node) { if (self->last_external_token) { - ts_tree_release(self->last_external_token); + ts_tree_release(tree_pool, self->last_external_token); } if (self->summary) { array_delete(self->summary); ts_free(self->summary); } - stack_node_release(self->node, pool); + stack_node_release(self->node, pool, tree_pool); } } @@ -271,7 +272,7 @@ inline StackPopResult stack__iter(Stack *self, StackVersion version, if (should_stop) { if (!should_pop) - ts_tree_array_delete(&iterator->trees); + ts_tree_array_delete(self->tree_pool, &iterator->trees); array_erase(&self->iterators, i); i--, size--; continue; @@ -316,7 +317,7 @@ inline StackPopResult stack__iter(Stack *self, StackVersion version, return (StackPopResult){self->slices}; } -Stack *ts_stack_new() { +Stack *ts_stack_new(TreePool *tree_pool) { Stack *self = ts_calloc(1, sizeof(Stack)); array_init(&self->heads); @@ -328,6 +329,7 @@ Stack *ts_stack_new() { array_grow(&self->iterators, 4); array_grow(&self->node_pool, MAX_NODE_POOL_SIZE); + self->tree_pool = tree_pool; self->base_node = stack_node_new(NULL, NULL, false, 1, &self->node_pool); ts_stack_clear(self); @@ -339,9 +341,9 @@ void ts_stack_delete(Stack *self) { array_delete(&self->slices); if (self->iterators.contents) array_delete(&self->iterators); - stack_node_release(self->base_node, &self->node_pool); + stack_node_release(self->base_node, &self->node_pool, self->tree_pool); for (uint32_t i = 0; i < self->heads.size; i++) { - stack_head_delete(&self->heads.contents[i], &self->node_pool); + stack_head_delete(&self->heads.contents[i], &self->node_pool, self->tree_pool); } array_clear(&self->heads); if (self->node_pool.contents) { @@ -380,7 +382,7 @@ Tree *ts_stack_last_external_token(const Stack *self, StackVersion version) { void ts_stack_set_last_external_token(Stack *self, StackVersion version, Tree *token) { StackHead *head = array_get(&self->heads, version); if (token) ts_tree_retain(token); - if (head->last_external_token) ts_tree_release(head->last_external_token); + if (head->last_external_token) ts_tree_release(self->tree_pool, head->last_external_token); head->last_external_token = token; } @@ -397,7 +399,7 @@ void ts_stack_push(Stack *self, StackVersion version, Tree *tree, bool pending, } else if (!tree->extra) { head->push_count++; } - stack_node_release(head->node, &self->node_pool); + stack_node_release(head->node, &self->node_pool, self->tree_pool); head->node = new_node; } @@ -525,14 +527,14 @@ int ts_stack_dynamic_precedence(Stack *self, StackVersion version) { } void ts_stack_remove_version(Stack *self, StackVersion version) { - stack_head_delete(array_get(&self->heads, version), &self->node_pool); + stack_head_delete(array_get(&self->heads, version), &self->node_pool, self->tree_pool); array_erase(&self->heads, version); } void ts_stack_renumber_version(Stack *self, StackVersion v1, StackVersion v2) { assert(v2 < v1); assert((uint32_t)v1 < self->heads.size); - stack_head_delete(&self->heads.contents[v2], &self->node_pool); + stack_head_delete(&self->heads.contents[v2], &self->node_pool, self->tree_pool); self->heads.contents[v2] = self->heads.contents[v1]; array_erase(&self->heads, v1); } @@ -593,7 +595,7 @@ bool ts_stack_is_halted(Stack *self, StackVersion version) { void ts_stack_clear(Stack *self) { stack_node_retain(self->base_node); for (uint32_t i = 0; i < self->heads.size; i++) { - stack_head_delete(&self->heads.contents[i], &self->node_pool); + stack_head_delete(&self->heads.contents[i], &self->node_pool, self->tree_pool); } array_clear(&self->heads); array_push(&self->heads, ((StackHead){ diff --git a/src/runtime/stack.h b/src/runtime/stack.h index 0cb3a800..df902b8c 100644 --- a/src/runtime/stack.h +++ b/src/runtime/stack.h @@ -48,7 +48,7 @@ typedef StackIterateAction (*StackIterateCallback)(void *, TSStateId state, /* * Create a parse stack. */ -Stack *ts_stack_new(); +Stack *ts_stack_new(TreePool *); /* * Release any resources reserved by a parse stack. diff --git a/src/runtime/tree.c b/src/runtime/tree.c index 9e16a81b..255029dc 100644 --- a/src/runtime/tree.c +++ b/src/runtime/tree.c @@ -12,6 +12,8 @@ TSStateId TS_TREE_STATE_NONE = USHRT_MAX; +// ExternalTokenState + void ts_external_token_state_init(TSExternalTokenState *self, const char *content, unsigned length) { self->length = length; if (length > sizeof(self->short_data)) { @@ -42,30 +44,7 @@ bool ts_external_token_state_eq(const TSExternalTokenState *a, const TSExternalT memcmp(ts_external_token_state_data(a), ts_external_token_state_data(b), a->length) == 0); } -Tree *ts_tree_make_leaf(TSSymbol symbol, Length padding, Length size, const TSLanguage *language) { - TSSymbolMetadata metadata = ts_language_symbol_metadata(language, symbol); - Tree *result = ts_malloc(sizeof(Tree)); - *result = (Tree){ - .ref_count = 1, - .symbol = symbol, - .size = size, - .child_count = 0, - .children = NULL, - .visible_child_count = 0, - .named_child_count = 0, - .alias_sequence_id = 0, - .padding = padding, - .visible = metadata.visible, - .named = metadata.named, - .has_changes = false, - .first_leaf = { - .symbol = symbol, - .lex_mode = {0, 0}, - }, - .has_external_tokens = false, - }; - return result; -} +// TreeArray bool ts_tree_array_copy(TreeArray self, TreeArray *dest) { Tree **contents = NULL; @@ -82,9 +61,9 @@ bool ts_tree_array_copy(TreeArray self, TreeArray *dest) { return true; } -void ts_tree_array_delete(TreeArray *self) { +void ts_tree_array_delete(TreePool *pool, TreeArray *self) { for (uint32_t i = 0; i < self->size; i++) { - ts_tree_release(self->contents[i]); + ts_tree_release(pool, self->contents[i]); } array_delete(self); } @@ -146,27 +125,89 @@ void ts_tree_array_reverse(TreeArray *self) { } } -Tree *ts_tree_make_error(Length size, Length padding, int32_t lookahead_char, +// TreePool + +static const uint32_t MAX_TREE_POOL_SIZE = 1024; + +void ts_tree_pool_init(TreePool *self) { + array_init(&self->free_trees); + array_init(&self->tree_stack); +} + +void ts_tree_pool_delete(TreePool *self) { + if (self->free_trees.contents) { + for (unsigned i = 0; i < self->free_trees.size; i++) { + ts_free(self->free_trees.contents[i]); + } + array_delete(&self->free_trees); + } + if (self->tree_stack.contents) array_delete(&self->tree_stack); +} + +Tree *ts_tree_pool_allocate(TreePool *self) { + if (self->free_trees.size > 0) { + return array_pop(&self->free_trees); + } else { + return ts_malloc(sizeof(Tree)); + } +} + +void ts_tree_pool_free(TreePool *self, Tree *tree) { + if (self->free_trees.size < MAX_TREE_POOL_SIZE) { + array_push(&self->free_trees, tree); + } else { + ts_free(tree); + } +} + +// Tree + +Tree *ts_tree_make_leaf(TreePool *pool, TSSymbol symbol, Length padding, Length size, const TSLanguage *language) { + TSSymbolMetadata metadata = ts_language_symbol_metadata(language, symbol); + Tree *result = ts_tree_pool_allocate(pool); + *result = (Tree){ + .ref_count = 1, + .symbol = symbol, + .size = size, + .child_count = 0, + .children = NULL, + .visible_child_count = 0, + .named_child_count = 0, + .alias_sequence_id = 0, + .padding = padding, + .visible = metadata.visible, + .named = metadata.named, + .has_changes = false, + .first_leaf = { + .symbol = symbol, + .lex_mode = {0, 0}, + }, + .has_external_tokens = false, + }; + return result; +} + +Tree *ts_tree_make_error(TreePool *pool, Length size, Length padding, int32_t lookahead_char, const TSLanguage *language) { - Tree *result = ts_tree_make_leaf(ts_builtin_sym_error, padding, size, language); + Tree *result = ts_tree_make_leaf(pool, ts_builtin_sym_error, padding, size, language); result->fragile_left = true; result->fragile_right = true; result->lookahead_char = lookahead_char; return result; } -Tree *ts_tree_make_copy(Tree *self) { - Tree *result = ts_malloc(sizeof(Tree)); +Tree *ts_tree_make_copy(TreePool *pool, Tree *self) { + Tree *result = ts_tree_pool_allocate(pool); *result = *self; result->ref_count = 1; return result; } -void ts_tree_assign_parents(Tree *self, TreePath *path, const TSLanguage *language) { - array_clear(path); - array_push(path, ((TreePathEntry){self, length_zero(), 0, 0})); - while (path->size > 0) { - Tree *tree = array_pop(path).tree; +void ts_tree_assign_parents(Tree *self, TreePool *pool, const TSLanguage *language) { + array_clear(&pool->tree_stack); + array_push(&pool->tree_stack, self); + while (pool->tree_stack.size > 0) { + Tree *tree = array_pop(&pool->tree_stack); Length offset = length_zero(); const TSSymbol *alias_sequence = ts_language_alias_sequence(language, tree->alias_sequence_id); uint32_t non_extra_index = 0; @@ -184,7 +225,7 @@ void ts_tree_assign_parents(Tree *self, TreePath *path, const TSLanguage *langua child->context.alias_symbol = 0; child->context.alias_is_named = false; } - array_push(path, ((TreePathEntry){child, length_zero(), 0, 0})); + array_push(&pool->tree_stack, child); } offset = length_add(offset, ts_tree_total_size(child)); if (!child->extra) non_extra_index++; @@ -192,7 +233,6 @@ void ts_tree_assign_parents(Tree *self, TreePath *path, const TSLanguage *langua } } - void ts_tree_set_children(Tree *self, uint32_t child_count, Tree **children, const TSLanguage *language) { if (self->child_count > 0) ts_free(self->children); @@ -264,15 +304,15 @@ void ts_tree_set_children(Tree *self, uint32_t child_count, Tree **children, } } -Tree *ts_tree_make_node(TSSymbol symbol, uint32_t child_count, Tree **children, +Tree *ts_tree_make_node(TreePool *pool, TSSymbol symbol, uint32_t child_count, Tree **children, unsigned alias_sequence_id, const TSLanguage *language) { - Tree *result = ts_tree_make_leaf(symbol, length_zero(), length_zero(), language); + Tree *result = ts_tree_make_leaf(pool, symbol, length_zero(), length_zero(), language); result->alias_sequence_id = alias_sequence_id; ts_tree_set_children(result, child_count, children, language); return result; } -Tree *ts_tree_make_error_node(TreeArray *children, const TSLanguage *language) { +Tree *ts_tree_make_error_node(TreePool *pool, TreeArray *children, const TSLanguage *language) { for (uint32_t i = 0; i < children->size; i++) { Tree *child = children->contents[i]; if (child->symbol == ts_builtin_sym_error && child->child_count > 0) { @@ -280,12 +320,12 @@ Tree *ts_tree_make_error_node(TreeArray *children, const TSLanguage *language) { i += child->child_count - 1; for (uint32_t j = 0; j < child->child_count; j++) ts_tree_retain(child->children[j]); - ts_tree_release(child); + ts_tree_release(pool, child); } } Tree *result = - ts_tree_make_node(ts_builtin_sym_error, children->size, children->contents, 0, language); + ts_tree_make_node(pool, ts_builtin_sym_error, children->size, children->contents, 0, language); result->fragile_left = true; result->fragile_right = true; @@ -298,26 +338,24 @@ void ts_tree_retain(Tree *self) { assert(self->ref_count != 0); } -void ts_tree_release(Tree *self) { -recur: - assert(self->ref_count > 0); - self->ref_count--; - - if (self->ref_count == 0) { - if (self->child_count > 0) { - for (uint32_t i = 0; i < self->child_count - 1; i++) { - ts_tree_release(self->children[i]); +void ts_tree_release(TreePool *pool, Tree *self) { + array_clear(&pool->tree_stack); + array_push(&pool->tree_stack, self); + while (pool->tree_stack.size > 0) { + Tree *tree = array_pop(&pool->tree_stack); + assert(tree->ref_count > 0); + tree->ref_count--; + if (tree->ref_count == 0) { + if (tree->child_count > 0) { + for (uint32_t i = 0; i < tree->child_count; i++) { + array_push(&pool->tree_stack, tree->children[i]); + } + ts_free(tree->children); + } else if (tree->has_external_tokens) { + ts_external_token_state_delete(&tree->external_token_state); } - Tree *last_child = self->children[self->child_count - 1]; - ts_free(self->children); - ts_free(self); - self = last_child; - goto recur; - } else if (self->has_external_tokens) { - ts_external_token_state_delete(&self->external_token_state); + ts_tree_pool_free(pool, tree); } - - ts_free(self); } } diff --git a/src/runtime/tree.h b/src/runtime/tree.h index 243239a8..e273fcd8 100644 --- a/src/runtime/tree.h +++ b/src/runtime/tree.h @@ -22,9 +22,6 @@ typedef struct { unsigned length; } TSExternalTokenState; -void ts_external_token_state_init(TSExternalTokenState *, const char *, unsigned); -const char *ts_external_token_state_data(const TSExternalTokenState *); - typedef struct Tree { struct { struct Tree *parent; @@ -70,38 +67,41 @@ typedef struct Tree { bool has_external_tokens : 1; } Tree; -typedef struct { - Tree *tree; - Length position; - uint32_t child_index; - uint32_t structural_child_index; -} TreePathEntry; - typedef Array(Tree *) TreeArray; -typedef Array(TreePathEntry) TreePath; +typedef struct { + TreeArray free_trees; + TreeArray tree_stack; +} TreePool; + +void ts_external_token_state_init(TSExternalTokenState *, const char *, unsigned); +const char *ts_external_token_state_data(const TSExternalTokenState *); bool ts_tree_array_copy(TreeArray, TreeArray *); -void ts_tree_array_delete(TreeArray *); +void ts_tree_array_delete(TreePool *, TreeArray *); uint32_t ts_tree_array_essential_count(const TreeArray *); TreeArray ts_tree_array_remove_last_n(TreeArray *, uint32_t); TreeArray ts_tree_array_remove_trailing_extras(TreeArray *); void ts_tree_array_reverse(TreeArray *); -Tree *ts_tree_make_leaf(TSSymbol, Length, Length, const TSLanguage *); -Tree *ts_tree_make_node(TSSymbol, uint32_t, Tree **, unsigned, const TSLanguage *); -Tree *ts_tree_make_copy(Tree *child); -Tree *ts_tree_make_error_node(TreeArray *, const TSLanguage *); -Tree *ts_tree_make_error(Length, Length, int32_t, const TSLanguage *); +void ts_tree_pool_init(TreePool *); +void ts_tree_pool_delete(TreePool *); +Tree *ts_tree_pool_allocate(TreePool *); +void ts_tree_pool_free(TreePool *, Tree *); + +Tree *ts_tree_make_leaf(TreePool *, TSSymbol, Length, Length, const TSLanguage *); +Tree *ts_tree_make_node(TreePool *, TSSymbol, uint32_t, Tree **, unsigned, const TSLanguage *); +Tree *ts_tree_make_copy(TreePool *, Tree *child); +Tree *ts_tree_make_error_node(TreePool *, TreeArray *, const TSLanguage *); +Tree *ts_tree_make_error(TreePool *, Length, Length, int32_t, const TSLanguage *); void ts_tree_retain(Tree *tree); -void ts_tree_release(Tree *tree); +void ts_tree_release(TreePool *, Tree *tree); bool ts_tree_eq(const Tree *tree1, const Tree *tree2); int ts_tree_compare(const Tree *tree1, const Tree *tree2); - uint32_t ts_tree_start_column(const Tree *self); uint32_t ts_tree_end_column(const Tree *self); void ts_tree_set_children(Tree *, uint32_t, Tree **, const TSLanguage *); -void ts_tree_assign_parents(Tree *, TreePath *, const TSLanguage *); +void ts_tree_assign_parents(Tree *, TreePool *, const TSLanguage *); void ts_tree_edit(Tree *, const TSInputEdit *edit); char *ts_tree_string(const Tree *, const TSLanguage *, bool include_all); void ts_tree_print_dot_graph(const Tree *, const TSLanguage *, FILE *); @@ -116,11 +116,6 @@ static inline Length ts_tree_total_size(const Tree *self) { return length_add(self->padding, self->size); } -static inline bool ts_tree_is_fragile(const Tree *tree) { - return tree->fragile_left || tree->fragile_right || - ts_tree_total_bytes(tree) == 0; -} - #ifdef __cplusplus } #endif diff --git a/test/runtime/stack_test.cc b/test/runtime/stack_test.cc index b40972dc..921033e4 100644 --- a/test/runtime/stack_test.cc +++ b/test/runtime/stack_test.cc @@ -23,7 +23,7 @@ Length operator*(const Length &length, uint32_t factor) { return {length.bytes * factor, {0, length.extent.column * factor}}; } -void free_slice_array(StackSliceArray *slices) { +void free_slice_array(TreePool *pool, StackSliceArray *slices) { for (size_t i = 0; i < slices->size; i++) { StackSlice slice = slices->contents[i]; @@ -38,7 +38,7 @@ void free_slice_array(StackSliceArray *slices) { if (!matches_prior_trees) { for (size_t j = 0; j < slice.trees.size; j++) - ts_tree_release(slice.trees.contents[j]); + ts_tree_release(pool, slice.trees.contents[j]); array_delete(&slice.trees); } } @@ -72,25 +72,29 @@ describe("Stack", [&]() { const size_t tree_count = 11; Tree *trees[tree_count]; Length tree_len = {3, {0, 3}}; + TreePool pool; before_each([&]() { record_alloc::start(); - stack = ts_stack_new(); + ts_tree_pool_init(&pool); + stack = ts_stack_new(&pool); TSLanguage dummy_language; TSSymbolMetadata symbol_metadata[50] = {}; dummy_language.symbol_metadata = symbol_metadata; for (size_t i = 0; i < tree_count; i++) { - trees[i] = ts_tree_make_leaf(i, length_zero(), tree_len, &dummy_language); + trees[i] = ts_tree_make_leaf(&pool, i, length_zero(), tree_len, &dummy_language); } }); after_each([&]() { ts_stack_delete(stack); - for (size_t i = 0; i < tree_count; i++) - ts_tree_release(trees[i]); + for (size_t i = 0; i < tree_count; i++) { + ts_tree_release(&pool, trees[i]); + } + ts_tree_pool_delete(&pool); record_alloc::stop(); AssertThat(record_alloc::outstanding_allocation_indices(), IsEmpty()); @@ -223,7 +227,7 @@ describe("Stack", [&]() { AssertThat(slice.trees, Equals(vector({ trees[1], trees[2] }))); AssertThat(ts_stack_top_state(stack, 1), Equals(stateA)); - free_slice_array(&pop.slices); + free_slice_array(&pool,&pop.slices); }); it("does not count 'extra' trees toward the given count", [&]() { @@ -239,7 +243,7 @@ describe("Stack", [&]() { AssertThat(slice.trees, Equals(vector({ trees[0], trees[1], trees[2] }))); AssertThat(ts_stack_top_state(stack, 1), Equals(1)); - free_slice_array(&pop.slices); + free_slice_array(&pool,&pop.slices); }); describe("when the version has been merged", [&]() { @@ -249,7 +253,7 @@ describe("Stack", [&]() { // └───4─── E <──5── F <──6───┘ ts_stack_push(stack, 0, trees[3], false, stateD); StackPopResult pop = ts_stack_pop_count(stack, 0, 3); - free_slice_array(&pop.slices); + 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); @@ -309,7 +313,7 @@ describe("Stack", [&]() { {1, 2}, }))); - free_slice_array(&pop.slices); + free_slice_array(&pool,&pop.slices); }); }); @@ -331,7 +335,7 @@ describe("Stack", [&]() { AssertThat(ts_stack_top_state(stack, 0), Equals(stateI)); AssertThat(ts_stack_top_state(stack, 1), Equals(stateD)); - free_slice_array(&pop.slices); + free_slice_array(&pool,&pop.slices); }); }); @@ -357,7 +361,7 @@ describe("Stack", [&]() { AssertThat(ts_stack_top_state(stack, 0), Equals(stateI)); AssertThat(ts_stack_top_state(stack, 1), Equals(stateA)); - free_slice_array(&pop.slices); + free_slice_array(&pool,&pop.slices); }); }); @@ -369,7 +373,7 @@ describe("Stack", [&]() { // | | // └───7─── G <──8── H <──9───┘ StackPopResult pop = ts_stack_pop_count(stack, 0, 4); - free_slice_array(&pop.slices); + 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); @@ -418,7 +422,7 @@ describe("Stack", [&]() { AssertThat(ts_stack_top_state(stack, 2), Equals(stateF)); AssertThat(ts_stack_top_state(stack, 3), Equals(stateH)); - free_slice_array(&pop.slices); + free_slice_array(&pool,&pop.slices); }); }); }); @@ -440,7 +444,7 @@ describe("Stack", [&]() { {1, 1}, }))); - free_slice_array(&pop.slices); + free_slice_array(&pool,&pop.slices); }); it("skips entries whose trees are extra", [&]() { @@ -462,7 +466,7 @@ describe("Stack", [&]() { {1, 1}, }))); - free_slice_array(&pop.slices); + free_slice_array(&pool,&pop.slices); }); it("does nothing if the top node was not pushed in pending mode", [&]() { @@ -477,7 +481,7 @@ describe("Stack", [&]() { {1, 2}, }))); - free_slice_array(&pop.slices); + free_slice_array(&pool,&pop.slices); }); }); diff --git a/test/runtime/tree_test.cc b/test/runtime/tree_test.cc index a3191ac3..96f485f7 100644 --- a/test/runtime/tree_test.cc +++ b/test/runtime/tree_test.cc @@ -40,17 +40,30 @@ describe("Tree", []() { TSLanguage language; language.symbol_metadata = metadata_list; + TreePool pool; + + before_each([&]() { + ts_tree_pool_init(&pool); + }); + + after_each([&]() { + ts_tree_pool_delete(&pool); + }); + describe("make_leaf", [&]() { it("does not mark the tree as fragile", [&]() { - Tree *tree = ts_tree_make_leaf(symbol1, {2, {0, 1}}, {5, {0, 4}}, &language); + Tree *tree = ts_tree_make_leaf(&pool, symbol1, {2, {0, 1}}, {5, {0, 4}}, &language); AssertThat(tree->fragile_left, IsFalse()); AssertThat(tree->fragile_right, IsFalse()); + + ts_tree_release(&pool, tree); }); }); describe("make_error", [&]() { it("marks the tree as fragile", [&]() { Tree *error_tree = ts_tree_make_error( + &pool, length_zero(), length_zero(), 'z', @@ -60,7 +73,7 @@ describe("Tree", []() { AssertThat(error_tree->fragile_left, IsTrue()); AssertThat(error_tree->fragile_right, IsTrue()); - ts_tree_release(error_tree); + ts_tree_release(&pool, error_tree); }); }); @@ -68,21 +81,21 @@ describe("Tree", []() { Tree *tree1, *tree2, *parent1; before_each([&]() { - tree1 = ts_tree_make_leaf(symbol1, {2, {0, 1}}, {5, {0, 4}}, &language); - tree2 = ts_tree_make_leaf(symbol2, {1, {0, 1}}, {3, {0, 3}}, &language); + tree1 = ts_tree_make_leaf(&pool, symbol1, {2, {0, 1}}, {5, {0, 4}}, &language); + tree2 = ts_tree_make_leaf(&pool, symbol2, {1, {0, 1}}, {3, {0, 3}}, &language); ts_tree_retain(tree1); ts_tree_retain(tree2); - parent1 = ts_tree_make_node(symbol3, 2, tree_array({ + parent1 = ts_tree_make_node(&pool, symbol3, 2, tree_array({ tree1, tree2, }), 0, &language); }); after_each([&]() { - ts_tree_release(tree1); - ts_tree_release(tree2); - ts_tree_release(parent1); + ts_tree_release(&pool, tree1); + ts_tree_release(&pool, tree2); + ts_tree_release(&pool, parent1); }); it("computes its size and padding based on its child nodes", [&]() { @@ -101,14 +114,14 @@ describe("Tree", []() { ts_tree_retain(tree1); ts_tree_retain(tree2); - parent = ts_tree_make_node(symbol3, 2, tree_array({ + parent = ts_tree_make_node(&pool, symbol3, 2, tree_array({ tree1, tree2, }), 0, &language); }); after_each([&]() { - ts_tree_release(parent); + ts_tree_release(&pool, parent); }); it("records that it is fragile on the left side", [&]() { @@ -125,14 +138,14 @@ describe("Tree", []() { ts_tree_retain(tree1); ts_tree_retain(tree2); - parent = ts_tree_make_node(symbol3, 2, tree_array({ + parent = ts_tree_make_node(&pool, symbol3, 2, tree_array({ tree1, tree2, }), 0, &language); }); after_each([&]() { - ts_tree_release(parent); + ts_tree_release(&pool, parent); }); it("records that it is fragile on the right side", [&]() { @@ -149,14 +162,14 @@ describe("Tree", []() { ts_tree_retain(tree1); ts_tree_retain(tree2); - parent = ts_tree_make_node(symbol3, 2, tree_array({ + parent = ts_tree_make_node(&pool, symbol3, 2, tree_array({ tree1, tree2, }), 0, &language); }); after_each([&]() { - ts_tree_release(parent); + ts_tree_release(&pool, parent); }); it("records that it is not fragile", [&]() { @@ -170,10 +183,10 @@ describe("Tree", []() { Tree *tree = nullptr; before_each([&]() { - tree = ts_tree_make_node(symbol1, 3, tree_array({ - ts_tree_make_leaf(symbol2, {2, {0, 2}}, {3, {0, 3}}, &language), - ts_tree_make_leaf(symbol3, {2, {0, 2}}, {3, {0, 3}}, &language), - ts_tree_make_leaf(symbol4, {2, {0, 2}}, {3, {0, 3}}, &language), + tree = ts_tree_make_node(&pool, symbol1, 3, tree_array({ + ts_tree_make_leaf(&pool, symbol2, {2, {0, 2}}, {3, {0, 3}}, &language), + ts_tree_make_leaf(&pool, symbol3, {2, {0, 2}}, {3, {0, 3}}, &language), + ts_tree_make_leaf(&pool, symbol4, {2, {0, 2}}, {3, {0, 3}}, &language), }), 0, &language); AssertThat(tree->padding, Equals({2, {0, 2}})); @@ -181,7 +194,7 @@ describe("Tree", []() { }); after_each([&]() { - ts_tree_release(tree); + ts_tree_release(&pool, tree); }); describe("edits within a tree's padding", [&]() { @@ -337,25 +350,25 @@ describe("Tree", []() { Tree *leaf; before_each([&]() { - leaf = ts_tree_make_leaf(symbol1, {2, {0, 1}}, {5, {0, 4}}, &language); + leaf = ts_tree_make_leaf(&pool, symbol1, {2, {0, 1}}, {5, {0, 4}}, &language); }); after_each([&]() { - ts_tree_release(leaf); + ts_tree_release(&pool, leaf); }); it("returns true for identical trees", [&]() { - Tree *leaf_copy = ts_tree_make_leaf(symbol1, {2, {1, 1}}, {5, {1, 4}}, &language); + Tree *leaf_copy = ts_tree_make_leaf(&pool, symbol1, {2, {1, 1}}, {5, {1, 4}}, &language); AssertThat(ts_tree_eq(leaf, leaf_copy), IsTrue()); - Tree *parent = ts_tree_make_node(symbol2, 2, tree_array({ + Tree *parent = ts_tree_make_node(&pool, symbol2, 2, tree_array({ leaf, leaf_copy, }), 0, &language); ts_tree_retain(leaf); ts_tree_retain(leaf_copy); - Tree *parent_copy = ts_tree_make_node(symbol2, 2, tree_array({ + Tree *parent_copy = ts_tree_make_node(&pool, symbol2, 2, tree_array({ leaf, leaf_copy, }), 0, &language); @@ -364,13 +377,14 @@ describe("Tree", []() { AssertThat(ts_tree_eq(parent, parent_copy), IsTrue()); - ts_tree_release(leaf_copy); - ts_tree_release(parent); - ts_tree_release(parent_copy); + ts_tree_release(&pool, leaf_copy); + ts_tree_release(&pool, parent); + ts_tree_release(&pool, parent_copy); }); it("returns false for trees with different symbols", [&]() { Tree *different_leaf = ts_tree_make_leaf( + &pool, leaf->symbol + 1, leaf->padding, leaf->size, @@ -378,37 +392,37 @@ describe("Tree", []() { ); AssertThat(ts_tree_eq(leaf, different_leaf), IsFalse()); - ts_tree_release(different_leaf); + ts_tree_release(&pool, different_leaf); }); it("returns false for trees with different options", [&]() { - Tree *different_leaf = ts_tree_make_leaf(leaf->symbol, leaf->padding, leaf->size, &language); + Tree *different_leaf = ts_tree_make_leaf(&pool, leaf->symbol, leaf->padding, leaf->size, &language); different_leaf->visible = !leaf->visible; AssertThat(ts_tree_eq(leaf, different_leaf), IsFalse()); - ts_tree_release(different_leaf); + ts_tree_release(&pool, different_leaf); }); it("returns false for trees with different paddings or sizes", [&]() { - Tree *different_leaf = ts_tree_make_leaf(leaf->symbol, {}, leaf->size, &language); + Tree *different_leaf = ts_tree_make_leaf(&pool, leaf->symbol, {}, leaf->size, &language); AssertThat(ts_tree_eq(leaf, different_leaf), IsFalse()); - ts_tree_release(different_leaf); + ts_tree_release(&pool, different_leaf); - different_leaf = ts_tree_make_leaf(symbol1, leaf->padding, {}, &language); + different_leaf = ts_tree_make_leaf(&pool, symbol1, leaf->padding, {}, &language); AssertThat(ts_tree_eq(leaf, different_leaf), IsFalse()); - ts_tree_release(different_leaf); + ts_tree_release(&pool, different_leaf); }); it("returns false for trees with different children", [&]() { - Tree *leaf2 = ts_tree_make_leaf(symbol2, {1, {0, 1}}, {3, {0, 3}}, &language); + Tree *leaf2 = ts_tree_make_leaf(&pool, symbol2, {1, {0, 1}}, {3, {0, 3}}, &language); - Tree *parent = ts_tree_make_node(symbol2, 2, tree_array({ + Tree *parent = ts_tree_make_node(&pool, symbol2, 2, tree_array({ leaf, leaf2, }), 0, &language); ts_tree_retain(leaf); ts_tree_retain(leaf2); - Tree *different_parent = ts_tree_make_node(symbol2, 2, tree_array({ + Tree *different_parent = ts_tree_make_node(&pool, symbol2, 2, tree_array({ leaf2, leaf, }), 0, &language); @@ -418,9 +432,9 @@ describe("Tree", []() { AssertThat(ts_tree_eq(different_parent, parent), IsFalse()); AssertThat(ts_tree_eq(parent, different_parent), IsFalse()); - ts_tree_release(leaf2); - ts_tree_release(parent); - ts_tree_release(different_parent); + ts_tree_release(&pool, leaf2); + ts_tree_release(&pool, parent); + ts_tree_release(&pool, different_parent); }); }); @@ -436,22 +450,24 @@ describe("Tree", []() { it("returns the last serialized external token state in the given tree", [&]() { Tree *tree1, *tree2, *tree3, *tree4, *tree5, *tree6, *tree7, *tree8, *tree9; - tree1 = ts_tree_make_node(symbol1, 2, tree_array({ - (tree2 = ts_tree_make_node(symbol2, 3, tree_array({ - (tree3 = make_external(ts_tree_make_leaf(symbol3, padding, size, &language))), - (tree4 = ts_tree_make_leaf(symbol4, padding, size, &language)), - (tree5 = ts_tree_make_leaf(symbol5, padding, size, &language)), + tree1 = ts_tree_make_node(&pool, symbol1, 2, tree_array({ + (tree2 = ts_tree_make_node(&pool, symbol2, 3, tree_array({ + (tree3 = make_external(ts_tree_make_leaf(&pool, symbol3, padding, size, &language))), + (tree4 = ts_tree_make_leaf(&pool, symbol4, padding, size, &language)), + (tree5 = ts_tree_make_leaf(&pool, symbol5, padding, size, &language)), }), 0, &language)), - (tree6 = ts_tree_make_node(symbol6, 2, tree_array({ - (tree7 = ts_tree_make_node(symbol7, 1, tree_array({ - (tree8 = ts_tree_make_leaf(symbol8, padding, size, &language)), + (tree6 = ts_tree_make_node(&pool, symbol6, 2, tree_array({ + (tree7 = ts_tree_make_node(&pool, symbol7, 1, tree_array({ + (tree8 = ts_tree_make_leaf(&pool, symbol8, padding, size, &language)), }), 0, &language)), - (tree9 = ts_tree_make_leaf(symbol9, padding, size, &language)), + (tree9 = ts_tree_make_leaf(&pool, symbol9, padding, size, &language)), }), 0, &language)), }), 0, &language); auto token = ts_tree_last_external_token(tree1); AssertThat(token, Equals(tree3)); + + ts_tree_release(&pool, tree1); }); }); });