Allocate and free trees using an object pool

This commit is contained in:
Max Brunsfeld 2017-10-05 17:32:21 -07:00
parent 53152658ce
commit addeb6c4c1
11 changed files with 287 additions and 230 deletions

View file

@ -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;

View file

@ -3,12 +3,15 @@
#include "runtime/parser.h"
#include "runtime/tree.h"
#include "runtime/get_changed_ranges.h"
#include <stdbool.h>
struct TSDocument {
Parser parser;
TSInput input;
Tree *tree;
TreePath tree_path1;
TreePath tree_path2;
size_t parse_count;
bool valid;
bool owns_input;

View file

@ -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

View file

@ -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;
}

View file

@ -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;

View file

@ -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){

View file

@ -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.

View file

@ -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);
}
}

View file

@ -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

View file

@ -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<Tree *>({ 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<Tree *>({ 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);
});
});

View file

@ -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<Length>({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);
});
});
});