Allocate and free trees using an object pool
This commit is contained in:
parent
53152658ce
commit
addeb6c4c1
11 changed files with 287 additions and 230 deletions
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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){
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue