From fe5350617546e26403a6e6b8f8da5068b22959a2 Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Fri, 11 May 2018 15:06:13 -0700 Subject: [PATCH] Declare subtrees as const wherever possible Co-Authored-By: Rick Winfrey --- include/tree_sitter/runtime.h | 2 +- src/runtime/get_changed_ranges.c | 22 +++--- src/runtime/get_changed_ranges.h | 3 +- src/runtime/node.c | 2 +- src/runtime/parser.c | 108 +++++++++++++------------- src/runtime/reusable_node.h | 8 +- src/runtime/stack.c | 17 ++-- src/runtime/stack.h | 6 +- src/runtime/subtree.c | 129 +++++++++++++++++-------------- src/runtime/subtree.h | 20 ++--- src/runtime/tree.c | 2 +- src/runtime/tree_cursor.c | 8 +- src/runtime/tree_cursor.h | 2 +- test/helpers/tree_helpers.cc | 6 +- test/helpers/tree_helpers.h | 4 +- test/runtime/stack_test.cc | 60 +++++++------- test/runtime/subtree_test.cc | 67 +++++++++------- 17 files changed, 244 insertions(+), 222 deletions(-) diff --git a/include/tree_sitter/runtime.h b/include/tree_sitter/runtime.h index acd2c3b3..8f379718 100644 --- a/include/tree_sitter/runtime.h +++ b/include/tree_sitter/runtime.h @@ -85,7 +85,7 @@ TSTree *ts_parser_parse(TSParser *, const TSTree *, TSInput); TSTree *ts_parser_parse_string(TSParser *, const TSTree *, const char *, uint32_t); TSTree *ts_tree_copy(const TSTree *); -void ts_tree_delete(const TSTree *); +void ts_tree_delete(TSTree *); TSNode ts_tree_root_node(const TSTree *); void ts_tree_edit(TSTree *, const TSInputEdit *); TSRange *ts_tree_get_changed_ranges(const TSTree *, const TSTree *, uint32_t *); diff --git a/src/runtime/get_changed_ranges.c b/src/runtime/get_changed_ranges.c index 032fdaab..2b015d27 100644 --- a/src/runtime/get_changed_ranges.c +++ b/src/runtime/get_changed_ranges.c @@ -31,7 +31,7 @@ typedef struct { bool in_padding; } Iterator; -static Iterator iterator_new(TSTreeCursor *cursor, Subtree *tree, const TSLanguage *language) { +static Iterator iterator_new(TSTreeCursor *cursor, const Subtree *tree, const TSLanguage *language) { array_clear(&cursor->stack); array_push(&cursor->stack, ((TreeCursorEntry){ .subtree = tree, @@ -74,14 +74,14 @@ static bool iterator_tree_is_visible(const Iterator *self) { TreeCursorEntry entry = *array_back(&self->cursor.stack); if (entry.subtree->visible) return true; if (self->cursor.stack.size > 1) { - Subtree *parent = self->cursor.stack.contents[self->cursor.stack.size - 2].subtree; + const Subtree *parent = self->cursor.stack.contents[self->cursor.stack.size - 2].subtree; const TSSymbol *alias_sequence = ts_language_alias_sequence(self->language, parent->alias_sequence_id); return alias_sequence && alias_sequence[entry.structural_child_index] != 0; } return false; } -static void iterator_get_visible_state(const Iterator *self, Subtree **tree, +static void iterator_get_visible_state(const Iterator *self, const Subtree **tree, TSSymbol *alias_symbol, uint32_t *start_byte) { uint32_t i = self->cursor.stack.size - 1; @@ -94,7 +94,7 @@ static void iterator_get_visible_state(const Iterator *self, Subtree **tree, TreeCursorEntry entry = self->cursor.stack.contents[i]; if (i > 0) { - Subtree *parent = self->cursor.stack.contents[i - 1].subtree; + const Subtree *parent = self->cursor.stack.contents[i - 1].subtree; const TSSymbol *alias_sequence = ts_language_alias_sequence( self->language, parent->alias_sequence_id @@ -129,7 +129,7 @@ static bool iterator_descend(Iterator *self, uint32_t goal_position) { Length position = entry.position; uint32_t structural_child_index = 0; for (uint32_t i = 0; i < entry.subtree->children.size; i++) { - Subtree *child = entry.subtree->children.contents[i]; + const Subtree *child = entry.subtree->children.contents[i]; Length child_left = length_add(position, child->padding); Length child_right = length_add(child_left, child->size); @@ -178,13 +178,13 @@ static void iterator_advance(Iterator *self) { TreeCursorEntry entry = array_pop(&self->cursor.stack); if (iterator_done(self)) return; - Subtree *parent = array_back(&self->cursor.stack)->subtree; + const Subtree *parent = array_back(&self->cursor.stack)->subtree; uint32_t child_index = entry.child_index + 1; if (parent->children.size > child_index) { Length position = length_add(entry.position, ts_subtree_total_size(entry.subtree)); uint32_t structural_child_index = entry.structural_child_index; if (!entry.subtree->extra) structural_child_index++; - Subtree *next_child = parent->children.contents[child_index]; + const Subtree *next_child = parent->children.contents[child_index]; array_push(&self->cursor.stack, ((TreeCursorEntry){ .subtree = next_child, @@ -214,7 +214,7 @@ typedef enum { } IteratorComparison; IteratorComparison iterator_compare(const Iterator *old_iter, const Iterator *new_iter) { - Subtree *old_tree = NULL, *new_tree = NULL; + const Subtree *old_tree = NULL, *new_tree = NULL; uint32_t old_start = 0, new_start = 0; TSSymbol old_alias_symbol = 0, new_alias_symbol = 0; iterator_get_visible_state(old_iter, &old_tree, &old_alias_symbol, &old_start); @@ -261,9 +261,9 @@ static inline void iterator_print_state(Iterator *self) { } #endif -unsigned ts_subtree_get_changed_ranges(Subtree *old_tree, Subtree *new_tree, - TSTreeCursor *cursor1, TSTreeCursor *cursor2, - const TSLanguage *language, TSRange **ranges) { +unsigned ts_subtree_get_changed_ranges(const Subtree *old_tree, const Subtree *new_tree, + TSTreeCursor *cursor1, TSTreeCursor *cursor2, + const TSLanguage *language, TSRange **ranges) { RangeArray results = array_new(); Iterator old_iter = iterator_new(cursor1, old_tree, language); diff --git a/src/runtime/get_changed_ranges.h b/src/runtime/get_changed_ranges.h index bf138a21..fbe9cc23 100644 --- a/src/runtime/get_changed_ranges.h +++ b/src/runtime/get_changed_ranges.h @@ -4,7 +4,8 @@ #include "runtime/subtree.h" unsigned ts_subtree_get_changed_ranges( - Subtree *old_tree, Subtree *new_tree, TSTreeCursor *cursor1, TSTreeCursor *cursor2, + const Subtree *old_tree, const Subtree *new_tree, + TSTreeCursor *cursor1, TSTreeCursor *cursor2, const TSLanguage *language, TSRange **ranges ); diff --git a/src/runtime/node.c b/src/runtime/node.c index e260f13b..1f221d12 100644 --- a/src/runtime/node.c +++ b/src/runtime/node.c @@ -47,7 +47,7 @@ static inline NodeChildIterator ts_node_child_iterator_begin(const TSNode *node) static inline bool ts_node_child_iterator_next(NodeChildIterator *self, TSNode *result) { if (self->child_index == self->parent->children.size) return false; - Subtree *child = self->parent->children.contents[self->child_index]; + const Subtree *child = self->parent->children.contents[self->child_index]; TSSymbol alias_symbol = 0; if (!child->extra) { if (self->alias_sequence) { diff --git a/src/runtime/parser.c b/src/runtime/parser.c index 8332501b..dde46f80 100644 --- a/src/runtime/parser.c +++ b/src/runtime/parser.c @@ -41,8 +41,8 @@ static const unsigned MAX_SUMMARY_DEPTH = 16; static const unsigned MAX_COST_DIFFERENCE = 16 * ERROR_COST_PER_SKIPPED_TREE; typedef struct { - Subtree *token; - Subtree *last_external_token; + const Subtree *token; + const Subtree *last_external_token; uint32_t byte_index; } TokenCache; @@ -52,7 +52,7 @@ struct TSParser { SubtreePool tree_pool; const TSLanguage *language; ReduceActionSet reduce_actions; - Subtree *finished_tree; + const Subtree *finished_tree; Subtree scratch_tree; TokenCache token_cache; ReusableNode reusable_node; @@ -112,10 +112,10 @@ static bool ts_parser__breakdown_top_of_stack(TSParser *self, StackVersion versi for (uint32_t i = 0; i < pop.size; i++) { StackSlice slice = pop.contents[i]; TSStateId state = ts_stack_state(self->stack, slice.version); - Subtree *parent = *array_front(&slice.subtrees); + const Subtree *parent = *array_front(&slice.subtrees); for (uint32_t j = 0; j < parent->children.size; j++) { - Subtree *child = parent->children.contents[j]; + const Subtree *child = parent->children.contents[j]; pending = child->children.size > 0; if (child->symbol == ts_builtin_sym_error) { @@ -129,7 +129,7 @@ static bool ts_parser__breakdown_top_of_stack(TSParser *self, StackVersion versi } for (uint32_t j = 1; j < slice.subtrees.size; j++) { - Subtree *tree = slice.subtrees.contents[j]; + const Subtree *tree = slice.subtrees.contents[j]; ts_stack_push(self->stack, slice.version, tree, false, state); } @@ -144,11 +144,10 @@ static bool ts_parser__breakdown_top_of_stack(TSParser *self, StackVersion versi return did_break_down; } -static void ts_parser__breakdown_lookahead(TSParser *self, Subtree **lookahead, - TSStateId state, - ReusableNode *reusable_node) { +static void ts_parser__breakdown_lookahead(TSParser *self, const Subtree **lookahead, + TSStateId state, ReusableNode *reusable_node) { bool did_descend = false; - Subtree *tree = reusable_node_tree(reusable_node); + const Subtree *tree = reusable_node_tree(reusable_node); while (tree->children.size > 0 && tree->parse_state != state) { LOG("state_mismatch sym:%s", SYM_NAME(tree->symbol)); reusable_node_descend(reusable_node); @@ -243,7 +242,7 @@ static bool ts_parser__better_version_exists(TSParser *self, StackVersion versio return false; } -static void ts_parser__restore_external_scanner(TSParser *self, Subtree *external_token) { +static void ts_parser__restore_external_scanner(TSParser *self, const Subtree *external_token) { if (external_token) { self->language->external_scanner.deserialize( self->external_scanner_payload, @@ -255,9 +254,9 @@ static void ts_parser__restore_external_scanner(TSParser *self, Subtree *externa } } -static Subtree *ts_parser__lex(TSParser *self, StackVersion version, TSStateId parse_state) { +static const Subtree *ts_parser__lex(TSParser *self, StackVersion version, TSStateId parse_state) { Length start_position = ts_stack_position(self->stack, version); - Subtree *external_token = ts_stack_last_external_token(self->stack, version); + const Subtree *external_token = ts_stack_last_external_token(self->stack, version); TSLexMode lex_mode = self->language->lex_modes[parse_state]; const bool *valid_external_tokens = ts_language_enabled_external_tokens( self->language, @@ -403,8 +402,8 @@ static Subtree *ts_parser__lex(TSParser *self, StackVersion version, TSStateId p return result; } -static Subtree *ts_parser__get_cached_token(TSParser *self, size_t byte_index, - Subtree *last_external_token) { +static const Subtree *ts_parser__get_cached_token(TSParser *self, size_t byte_index, + const Subtree *last_external_token) { TokenCache *cache = &self->token_cache; if (cache->token && cache->byte_index == byte_index && @@ -415,8 +414,8 @@ static Subtree *ts_parser__get_cached_token(TSParser *self, size_t byte_index, } } -static void ts_parser__set_cached_token(TSParser *self, size_t byte_index, Subtree *last_external_token, - Subtree *token) { +static void ts_parser__set_cached_token(TSParser *self, size_t byte_index, + const Subtree *last_external_token, const Subtree *token) { TokenCache *cache = &self->token_cache; if (token) ts_subtree_retain(token); if (last_external_token) ts_subtree_retain(last_external_token); @@ -427,8 +426,8 @@ static void ts_parser__set_cached_token(TSParser *self, size_t byte_index, Subtr cache->last_external_token = last_external_token; } -static bool ts_parser__can_reuse_first_leaf(TSParser *self, TSStateId state, Subtree *tree, - TableEntry *table_entry) { +static bool ts_parser__can_reuse_first_leaf(TSParser *self, TSStateId state, const Subtree *tree, + TableEntry *table_entry) { TSLexMode current_lex_mode = self->language->lex_modes[state]; // If the token was created in a state with the same set of lookaheads, it is reusable. @@ -445,12 +444,13 @@ static bool ts_parser__can_reuse_first_leaf(TSParser *self, TSStateId state, Sub return current_lex_mode.external_lex_state == 0 && table_entry->is_reusable; } -static Subtree *ts_parser__get_lookahead(TSParser *self, StackVersion version, TSStateId *state, - ReusableNode *reusable_node, TableEntry *table_entry) { +static const Subtree *ts_parser__get_lookahead(TSParser *self, StackVersion version, + TSStateId *state, ReusableNode *reusable_node, + TableEntry *table_entry) { Length position = ts_stack_position(self->stack, version); - Subtree *last_external_token = ts_stack_last_external_token(self->stack, version); + const Subtree *last_external_token = ts_stack_last_external_token(self->stack, version); - Subtree *result; + const Subtree *result; while ((result = reusable_node_tree(reusable_node))) { uint32_t byte_offset = reusable_node_byte_offset(reusable_node); if (byte_offset > position.bytes) { @@ -523,7 +523,7 @@ static Subtree *ts_parser__get_lookahead(TSParser *self, StackVersion version, T return result; } -static bool ts_parser__select_tree(TSParser *self, Subtree *left, Subtree *right) { +static bool ts_parser__select_tree(TSParser *self, const Subtree *left, const Subtree *right) { if (!left) return true; if (!right) return false; @@ -574,23 +574,21 @@ static bool ts_parser__select_tree(TSParser *self, Subtree *left, Subtree *right } static void ts_parser__shift(TSParser *self, StackVersion version, TSStateId state, - Subtree *lookahead, bool extra) { + const Subtree *lookahead, bool extra) { + const Subtree *subtree_to_push; if (extra != lookahead->extra) { - if (ts_stack_version_count(self->stack) > 1) { - lookahead = ts_subtree_new_copy(&self->tree_pool, lookahead); - } else { - ts_subtree_retain(lookahead); - } - lookahead->extra = extra; + Subtree *result = ts_subtree_make_mut(&self->tree_pool, lookahead); + result->extra = extra; + subtree_to_push = result; } else { - ts_subtree_retain(lookahead); + subtree_to_push = lookahead; } - bool is_pending = lookahead->children.size > 0; - ts_stack_push(self->stack, version, lookahead, is_pending, state); - if (lookahead->has_external_tokens) { + bool is_pending = subtree_to_push->children.size > 0; + ts_stack_push(self->stack, version, subtree_to_push, is_pending, state); + if (subtree_to_push->has_external_tokens) { ts_stack_set_last_external_token( - self->stack, version, ts_subtree_last_external_token(lookahead) + self->stack, version, ts_subtree_last_external_token(subtree_to_push) ); } } @@ -717,19 +715,17 @@ static void ts_parser__start(TSParser *self, TSInput input, const Subtree *previ self->in_ambiguity = false; } -static void ts_parser__accept(TSParser *self, StackVersion version, Subtree *lookahead) { - lookahead->extra = true; +static void ts_parser__accept(TSParser *self, StackVersion version, const Subtree *lookahead) { assert(lookahead->symbol == ts_builtin_sym_end); - ts_subtree_retain(lookahead); ts_stack_push(self->stack, version, lookahead, false, 1); StackSliceArray pop = ts_stack_pop_all(self->stack, version); for (uint32_t i = 0; i < pop.size; i++) { SubtreeArray trees = pop.contents[i].subtrees; - Subtree *root = NULL; + const Subtree *root = NULL; for (uint32_t j = trees.size - 1; j + 1 > 0; j--) { - Subtree *child = trees.contents[j]; + const Subtree *child = trees.contents[j]; if (!child->extra) { for (uint32_t k = 0; k < child->children.size; k++) { ts_subtree_retain(child->children.contents[k]); @@ -875,7 +871,9 @@ static void ts_parser__handle_error(TSParser *self, StackVersion version, lookahead_symbol )) { StackVersion version_with_missing_tree = ts_stack_copy_version(self->stack, v); - Subtree *missing_tree = ts_subtree_new_missing_leaf(&self->tree_pool, missing_symbol, self->language); + const Subtree *missing_tree = ts_subtree_new_missing_leaf( + &self->tree_pool, missing_symbol, self->language + ); ts_stack_push( self->stack, version_with_missing_tree, missing_tree, false, @@ -930,11 +928,10 @@ static void ts_parser__halt_parse(TSParser *self) { Subtree *eof = ts_subtree_new_leaf(&self->tree_pool, ts_builtin_sym_end, length_zero(), length_zero(), self->language); ts_parser__accept(self, 0, eof); - ts_subtree_release(&self->tree_pool, eof); } static bool ts_parser__recover_to_state(TSParser *self, StackVersion version, unsigned depth, - TSStateId goal_state) { + TSStateId goal_state) { StackSliceArray pop = ts_stack_pop_count(self->stack, version, depth); StackVersion previous_version = STACK_VERSION_NONE; @@ -975,7 +972,7 @@ static bool ts_parser__recover_to_state(TSParser *self, StackVersion version, un } for (unsigned j = 0; j < trailing_extras.size; j++) { - Subtree *tree = trailing_extras.contents[j]; + const Subtree *tree = trailing_extras.contents[j]; ts_stack_push(self->stack, slice.version, tree, false, goal_state); } @@ -986,7 +983,7 @@ static bool ts_parser__recover_to_state(TSParser *self, StackVersion version, un return previous_version != STACK_VERSION_NONE; } -static void ts_parser__recover(TSParser *self, StackVersion version, Subtree *lookahead) { +static void ts_parser__recover(TSParser *self, StackVersion version, const Subtree *lookahead) { bool did_recover = false; unsigned previous_version_count = ts_stack_version_count(self->stack); Length position = ts_stack_position(self->stack, version); @@ -1042,13 +1039,14 @@ static void ts_parser__recover(TSParser *self, StackVersion version, Subtree *lo if (did_recover && ts_stack_version_count(self->stack) > MAX_VERSION_COUNT) { ts_stack_halt(self->stack, version); + ts_subtree_release(&self->tree_pool, lookahead); return; } if (lookahead->symbol == ts_builtin_sym_end) { LOG("recover_eof"); SubtreeArray children = array_new(); - Subtree *parent = ts_subtree_new_error_node(&self->tree_pool, &children, self->language); + const Subtree *parent = ts_subtree_new_error_node(&self->tree_pool, &children, self->language); ts_stack_push(self->stack, version, parent, false, 1); ts_parser__accept(self, version, lookahead); return; @@ -1061,21 +1059,23 @@ static void ts_parser__recover(TSParser *self, StackVersion version, Subtree *lo if (ts_parser__better_version_exists(self, version, false, new_cost)) { ts_stack_halt(self->stack, version); + ts_subtree_release(&self->tree_pool, lookahead); return; } unsigned n; const TSParseAction *actions = ts_language_actions(self->language, 1, lookahead->symbol, &n); if (n > 0 && actions[n - 1].type == TSParseActionTypeShift && actions[n - 1].params.extra) { - lookahead->extra = true; + Subtree *mutable_lookahead = ts_subtree_make_mut(&self->tree_pool, lookahead); + mutable_lookahead->extra = true; + lookahead = mutable_lookahead; } LOG("skip_token symbol:%s", SYM_NAME(lookahead->symbol)); - ts_subtree_retain(lookahead); SubtreeArray children = array_new(); array_reserve(&children, 1); array_push(&children, lookahead); - Subtree *error_repeat = ts_subtree_new_node( + const Subtree *error_repeat = ts_subtree_new_node( &self->tree_pool, ts_builtin_sym_error_repeat, &children, @@ -1110,7 +1110,9 @@ static void ts_parser__recover(TSParser *self, StackVersion version, Subtree *lo static void ts_parser__advance(TSParser *self, StackVersion version, ReusableNode *reusable_node) { TSStateId state = ts_stack_state(self->stack, version); TableEntry table_entry; - Subtree *lookahead = ts_parser__get_lookahead(self, version, &state, reusable_node, &table_entry); + const Subtree *lookahead = ts_parser__get_lookahead( + self, version, &state, reusable_node, &table_entry + ); for (;;) { StackVersion last_reduction_version = STACK_VERSION_NONE; @@ -1143,7 +1145,6 @@ static void ts_parser__advance(TSParser *self, StackVersion version, ReusableNod if (lookahead == reusable_node_tree(reusable_node)) { reusable_node_advance(reusable_node); } - ts_subtree_release(&self->tree_pool, lookahead); return; } @@ -1163,7 +1164,6 @@ static void ts_parser__advance(TSParser *self, StackVersion version, ReusableNod case TSParseActionTypeAccept: { LOG("accept"); ts_parser__accept(self, version, lookahead); - ts_subtree_release(&self->tree_pool, lookahead); return; } @@ -1175,7 +1175,6 @@ static void ts_parser__advance(TSParser *self, StackVersion version, ReusableNod if (lookahead == reusable_node_tree(reusable_node)) { reusable_node_advance(reusable_node); } - ts_subtree_release(&self->tree_pool, lookahead); return; } } @@ -1186,7 +1185,6 @@ static void ts_parser__advance(TSParser *self, StackVersion version, ReusableNod LOG_STACK(); } else if (state == ERROR_STATE) { ts_parser__recover(self, version, lookahead); - ts_subtree_release(&self->tree_pool, lookahead); return; } else if (!ts_parser__breakdown_top_of_stack(self, version)) { LOG("detect_error"); diff --git a/src/runtime/reusable_node.h b/src/runtime/reusable_node.h index c1d4f06b..42ae6f1e 100644 --- a/src/runtime/reusable_node.h +++ b/src/runtime/reusable_node.h @@ -1,21 +1,21 @@ #include "runtime/subtree.h" typedef struct { - Subtree *tree; + const Subtree *tree; uint32_t child_index; uint32_t byte_offset; } StackEntry; typedef struct { Array(StackEntry) stack; - Subtree *last_external_token; + const Subtree *last_external_token; } ReusableNode; static inline ReusableNode reusable_node_new() { return (ReusableNode) {array_new(), NULL}; } -static inline void reusable_node_reset(ReusableNode *self, Subtree *tree) { +static inline void reusable_node_reset(ReusableNode *self, const Subtree *tree) { array_clear(&self->stack); array_push(&self->stack, ((StackEntry) { .tree = tree, @@ -51,7 +51,7 @@ static inline void reusable_node_advance(ReusableNode *self) { self->last_external_token = ts_subtree_last_external_token(last_entry.tree); } - Subtree *tree; + const Subtree *tree; uint32_t next_index; do { StackEntry popped_entry = array_pop(&self->stack); diff --git a/src/runtime/stack.c b/src/runtime/stack.c index 21468e49..8921d559 100644 --- a/src/runtime/stack.c +++ b/src/runtime/stack.c @@ -21,7 +21,7 @@ typedef struct StackNode StackNode; typedef struct { StackNode *node; - Subtree *subtree; + const Subtree *subtree; bool is_pending; } StackLink; @@ -58,7 +58,7 @@ typedef enum { typedef struct { StackNode *node; - Subtree *last_external_token; + const Subtree *last_external_token; StackSummary *summary; unsigned node_count_at_last_error; TSSymbol lookahead_when_paused; @@ -119,8 +119,8 @@ recur: } } -static StackNode *stack_node_new(StackNode *previous_node, Subtree *subtree, bool is_pending, - TSStateId state, StackNodeArray *pool) { +static StackNode *stack_node_new(StackNode *previous_node, const Subtree *subtree, + bool is_pending, TSStateId state, StackNodeArray *pool) { StackNode *node = pool->size > 0 ? array_pop(pool) : ts_malloc(sizeof(StackNode)); @@ -380,11 +380,11 @@ Length ts_stack_position(const Stack *self, StackVersion version) { return array_get(&self->heads, version)->node->position; } -Subtree *ts_stack_last_external_token(const Stack *self, StackVersion version) { +const Subtree *ts_stack_last_external_token(const Stack *self, StackVersion version) { return array_get(&self->heads, version)->last_external_token; } -void ts_stack_set_last_external_token(Stack *self, StackVersion version, Subtree *token) { +void ts_stack_set_last_external_token(Stack *self, StackVersion version, const Subtree *token) { StackHead *head = array_get(&self->heads, version); if (token) ts_subtree_retain(token); if (head->last_external_token) ts_subtree_release(self->subtree_pool, head->last_external_token); @@ -410,7 +410,8 @@ unsigned ts_stack_node_count_since_error(const Stack *self, StackVersion version return head->node->node_count - head->node_count_at_last_error; } -void ts_stack_push(Stack *self, StackVersion version, Subtree *subtree, bool pending, TSStateId state) { +void ts_stack_push(Stack *self, StackVersion version, const Subtree *subtree, + bool pending, TSStateId state) { StackHead *head = array_get(&self->heads, version); StackNode *new_node = stack_node_new(head->node, subtree, pending, state, &self->node_pool); if (!subtree) head->node_count_at_last_error = new_node->node_count; @@ -684,7 +685,7 @@ bool ts_stack_print_dot_graph(Stack *self, const TSLanguage *language, FILE *f) ); if (head->last_external_token) { - ExternalScannerState *state = &head->last_external_token->external_scanner_state; + const ExternalScannerState *state = &head->last_external_token->external_scanner_state; const char *data = ts_external_scanner_state_data(state); fprintf(f, "\nexternal_scanner_state:"); for (uint32_t j = 0; j < state->length; j++) fprintf(f, " %2X", data[j]); diff --git a/src/runtime/stack.h b/src/runtime/stack.h index 88c06bab..b7dba342 100644 --- a/src/runtime/stack.h +++ b/src/runtime/stack.h @@ -42,10 +42,10 @@ uint32_t ts_stack_version_count(const Stack *); TSStateId ts_stack_state(const Stack *, StackVersion); // Get the last external token associated with a given version of the stack. -Subtree *ts_stack_last_external_token(const Stack *, StackVersion); +const Subtree *ts_stack_last_external_token(const Stack *, StackVersion); // Set the last external token associated with a given version of the stack. -void ts_stack_set_last_external_token(Stack *, StackVersion, Subtree *); +void ts_stack_set_last_external_token(Stack *, StackVersion, const Subtree *); // Get the position of the given version of the stack within the document. Length ts_stack_position(const Stack *, StackVersion); @@ -55,7 +55,7 @@ Length ts_stack_position(const Stack *, StackVersion); // This transfers ownership of the tree to the Stack. Callers that // need to retain ownership of the tree for their own purposes should // first retain the tree. -void ts_stack_push(Stack *, StackVersion, Subtree *, bool, TSStateId); +void ts_stack_push(Stack *, StackVersion, const Subtree *, bool, TSStateId); // Pop the given number of entries from the given version of the stack. This // operation can increase the number of stack versions by revealing multiple diff --git a/src/runtime/subtree.c b/src/runtime/subtree.c index 0cd125bf..0991b67c 100644 --- a/src/runtime/subtree.c +++ b/src/runtime/subtree.c @@ -59,7 +59,7 @@ bool ts_external_scanner_state_eq(const ExternalScannerState *a, const ExternalS // SubtreeArray bool ts_subtree_array_copy(SubtreeArray self, SubtreeArray *dest) { - Subtree **contents = NULL; + const Subtree **contents = NULL; if (self.capacity > 0) { contents = ts_calloc(self.capacity, sizeof(Subtree *)); memcpy(contents, self.contents, self.size * sizeof(Subtree *)); @@ -86,7 +86,7 @@ SubtreeArray ts_subtree_array_remove_trailing_extras(SubtreeArray *self) { uint32_t i = self->size - 1; for (; i + 1 > 0; i--) { - Subtree *child = self->contents[i]; + const Subtree *child = self->contents[i]; if (!child->extra) break; array_push(&result, child); } @@ -99,7 +99,7 @@ SubtreeArray ts_subtree_array_remove_trailing_extras(SubtreeArray *self) { void ts_subtree_array_reverse(SubtreeArray *self) { for (uint32_t i = 0, limit = self->size / 2; i < limit; i++) { size_t reverse_index = self->size - 1 - i; - Subtree *swap = self->contents[i]; + const Subtree *swap = self->contents[i]; self->contents[i] = self->contents[reverse_index]; self->contents[reverse_index] = swap; } @@ -142,7 +142,7 @@ void ts_subtree_pool_free(SubtreePool *self, Subtree *tree) { // Subtree Subtree *ts_subtree_new_leaf(SubtreePool *pool, TSSymbol symbol, Length padding, Length size, - const TSLanguage *language) { + const TSLanguage *language) { TSSymbolMetadata metadata = ts_language_symbol_metadata(language, symbol); Subtree *result = ts_subtree_pool_allocate(pool); *result = (Subtree){ @@ -163,11 +163,12 @@ Subtree *ts_subtree_new_leaf(SubtreePool *pool, TSSymbol symbol, Length padding, }, .has_external_tokens = false, }; + if (symbol == ts_builtin_sym_end) result->extra = true; return result; } Subtree *ts_subtree_new_error(SubtreePool *pool, Length size, Length padding, - int32_t lookahead_char, const TSLanguage *language) { + int32_t lookahead_char, const TSLanguage *language) { Subtree *result = ts_subtree_new_leaf(pool, ts_builtin_sym_error, padding, size, language); result->fragile_left = true; result->fragile_right = true; @@ -175,7 +176,7 @@ Subtree *ts_subtree_new_error(SubtreePool *pool, Length size, Length padding, return result; } -Subtree *ts_subtree_new_copy(SubtreePool *pool, Subtree *self) { +Subtree *ts_subtree_new_copy(SubtreePool *pool, const Subtree *self) { Subtree *result = ts_subtree_pool_allocate(pool); *result = *self; if (result->children.size > 0) { @@ -185,9 +186,9 @@ Subtree *ts_subtree_new_copy(SubtreePool *pool, Subtree *self) { return result; } -static Subtree *ts_subtree_new_mut(SubtreePool *pool, Subtree *self) { +Subtree *ts_subtree_make_mut(SubtreePool *pool, const Subtree *self) { if (self->ref_count == 1) { - return self; + return (Subtree *)self; } else { Subtree *result = ts_subtree_new_copy(pool, self); ts_subtree_release(pool, self); @@ -196,21 +197,21 @@ static Subtree *ts_subtree_new_mut(SubtreePool *pool, Subtree *self) { } static void ts_subtree__compress(Subtree *self, unsigned count, const TSLanguage *language, - SubtreeArray *stack) { + MutableSubtreeArray *stack) { unsigned initial_stack_size = stack->size; Subtree *tree = self; for (unsigned i = 0; i < count; i++) { if (tree->ref_count > 1 || tree->children.size != 2) break; - Subtree *child = tree->children.contents[0]; + Subtree *child = (Subtree *)tree->children.contents[0]; if ( child->ref_count > 1 || child->children.size != 2 || child->symbol != tree->symbol ) break; - Subtree *grandchild = child->children.contents[0]; + Subtree *grandchild = (Subtree *)child->children.contents[0]; if ( grandchild->ref_count > 1 || grandchild->children.size != 2 || @@ -227,38 +228,41 @@ static void ts_subtree__compress(Subtree *self, unsigned count, const TSLanguage while (stack->size > initial_stack_size) { tree = array_pop(stack); assert(tree); - Subtree *child = tree->children.contents[0]; - Subtree *grandchild = child->children.contents[1]; + Subtree *child = (Subtree *)tree->children.contents[0]; + Subtree *grandchild = (Subtree *)child->children.contents[1]; ts_subtree_set_children(grandchild, &grandchild->children, language); ts_subtree_set_children(child, &child->children, language); ts_subtree_set_children(tree, &tree->children, language); } } -void ts_subtree_balance(Subtree *self, SubtreePool *pool, const TSLanguage *language) { +void ts_subtree_balance(const Subtree *self, SubtreePool *pool, const TSLanguage *language) { array_clear(&pool->tree_stack); - array_push(&pool->tree_stack, self); + + if (self->ref_count == 1) { + array_push(&pool->tree_stack, (Subtree *)self); + } + while (pool->tree_stack.size > 0) { Subtree *tree = array_pop(&pool->tree_stack); assert(tree); - if (tree->repeat_depth > 0) { - if (tree->children.contents[0]->repeat_depth > tree->children.contents[1]->repeat_depth) { - unsigned n = ( - tree->children.contents[0]->repeat_depth - - tree->children.contents[1]->repeat_depth - ); - for (unsigned i = n / 2; i > 0; i /= 2) { - ts_subtree__compress(tree, i, language, &pool->tree_stack); - n -= i; - } + if (tree->repeat_depth > 0 && + tree->children.contents[0]->repeat_depth > tree->children.contents[1]->repeat_depth) { + unsigned n = ( + tree->children.contents[0]->repeat_depth - + tree->children.contents[1]->repeat_depth + ); + for (unsigned i = n / 2; i > 0; i /= 2) { + ts_subtree__compress(tree, i, language, &pool->tree_stack); + n -= i; } } for (uint32_t i = 0; i < tree->children.size; i++) { - Subtree *child = tree->children.contents[i]; + const Subtree *child = tree->children.contents[i]; if (child->ref_count == 1) { - array_push(&pool->tree_stack, child); + array_push(&pool->tree_stack, (Subtree *)child); } } } @@ -282,7 +286,7 @@ void ts_subtree_set_children(Subtree *self, SubtreeArray *children, const TSLang const TSSymbol *alias_sequence = ts_language_alias_sequence(language, self->alias_sequence_id); for (uint32_t i = 0; i < self->children.size; i++) { - Subtree *child = self->children.contents[i]; + const Subtree *child = self->children.contents[i]; if (i == 0) { self->padding = child->padding; @@ -328,7 +332,7 @@ void ts_subtree_set_children(Subtree *self, SubtreeArray *children, const TSLang ERROR_COST_PER_SKIPPED_CHAR * self->size.bytes + ERROR_COST_PER_SKIPPED_LINE * self->size.extent.row; for (uint32_t i = 0; i < self->children.size; i++) { - Subtree *child = self->children.contents[i]; + const Subtree *child = self->children.contents[i]; if (child->extra) continue; if (child->symbol == ts_builtin_sym_error && child->children.size == 0) continue; if (child->visible) { @@ -340,8 +344,8 @@ void ts_subtree_set_children(Subtree *self, SubtreeArray *children, const TSLang } if (self->children.size > 0) { - Subtree *first_child = self->children.contents[0]; - Subtree *last_child = self->children.contents[self->children.size - 1]; + const Subtree *first_child = self->children.contents[0]; + const Subtree *last_child = self->children.contents[self->children.size - 1]; self->first_leaf = first_child->first_leaf; if (first_child->fragile_left) self->fragile_left = true; if (last_child->fragile_right) self->fragile_right = true; @@ -361,7 +365,7 @@ void ts_subtree_set_children(Subtree *self, SubtreeArray *children, const TSLang } Subtree *ts_subtree_new_node(SubtreePool *pool, TSSymbol symbol, SubtreeArray *children, - unsigned alias_sequence_id, const TSLanguage *language) { + unsigned alias_sequence_id, const TSLanguage *language) { Subtree *result = ts_subtree_new_leaf(pool, symbol, length_zero(), length_zero(), language); result->alias_sequence_id = alias_sequence_id; if (symbol == ts_builtin_sym_error || symbol == ts_builtin_sym_error_repeat) { @@ -373,41 +377,46 @@ Subtree *ts_subtree_new_node(SubtreePool *pool, TSSymbol symbol, SubtreeArray *c } Subtree *ts_subtree_new_error_node(SubtreePool *pool, SubtreeArray *children, - const TSLanguage *language) { + const TSLanguage *language) { return ts_subtree_new_node(pool, ts_builtin_sym_error, children, 0, language); } Subtree *ts_subtree_new_missing_leaf(SubtreePool *pool, TSSymbol symbol, - const TSLanguage *language) { + const TSLanguage *language) { Subtree *result = ts_subtree_new_leaf(pool, symbol, length_zero(), length_zero(), language); result->is_missing = true; result->error_cost = ERROR_COST_PER_MISSING_TREE + ERROR_COST_PER_RECOVERY; return result; } -void ts_subtree_retain(Subtree *self) { +void ts_subtree_retain(const Subtree *self) { assert(self->ref_count > 0); - atomic_inc(&self->ref_count); + atomic_inc((volatile uint32_t *)&self->ref_count); assert(self->ref_count != 0); } -void ts_subtree_release(SubtreePool *pool, Subtree *self) { +void ts_subtree_release(SubtreePool *pool, const Subtree *self) { array_clear(&pool->tree_stack); - array_push(&pool->tree_stack, self); + + assert(self->ref_count > 0); + if (atomic_dec((volatile uint32_t *)&self->ref_count) == 0) { + array_push(&pool->tree_stack, (Subtree *)self); + } + while (pool->tree_stack.size > 0) { Subtree *tree = array_pop(&pool->tree_stack); - assert(tree->ref_count > 0); - if (atomic_dec(&tree->ref_count) == 0) { - if (tree->children.size > 0) { - for (uint32_t i = 0; i < tree->children.size; i++) { - array_push(&pool->tree_stack, tree->children.contents[i]); + if (tree->children.size > 0) { + for (uint32_t i = 0; i < tree->children.size; i++) { + const Subtree *child = tree->children.contents[i]; + if (atomic_dec((volatile uint32_t *)&child->ref_count) == 0) { + array_push(&pool->tree_stack, (Subtree *)child); } - array_delete(&tree->children); - } else if (tree->has_external_tokens) { - ts_external_scanner_state_delete(&tree->external_scanner_state); } - ts_subtree_pool_free(pool, tree); + array_delete(&tree->children); + } else if (tree->has_external_tokens) { + ts_external_scanner_state_delete(&tree->external_scanner_state); } + ts_subtree_pool_free(pool, tree); } } @@ -446,8 +455,8 @@ int ts_subtree_compare(const Subtree *left, const Subtree *right) { if (right->children.size < left->children.size) return 1; for (uint32_t i = 0; i < left->children.size; i++) { - Subtree *left_child = left->children.contents[i]; - Subtree *right_child = right->children.contents[i]; + const Subtree *left_child = left->children.contents[i]; + const Subtree *right_child = right->children.contents[i]; switch (ts_subtree_compare(left_child, right_child)) { case -1: return -1; @@ -460,17 +469,17 @@ int ts_subtree_compare(const Subtree *left, const Subtree *right) { return 0; } -Subtree *ts_subtree_invalidate_lookahead(Subtree *self, uint32_t edit_byte_offset, - SubtreePool *pool) { +const Subtree *ts_subtree_invalidate_lookahead(const Subtree *self, uint32_t edit_byte_offset, + SubtreePool *pool) { if (edit_byte_offset >= self->bytes_scanned) return self; - Subtree *result = ts_subtree_new_mut(pool, self); + Subtree *result = ts_subtree_make_mut(pool, self); result->has_changes = true; if (result->children.size > 0) { uint32_t child_start_byte = 0; for (uint32_t i = 0; i < result->children.size; i++) { - Subtree **child = &result->children.contents[i]; + const Subtree **child = &result->children.contents[i]; if (child_start_byte > edit_byte_offset) break; *child = ts_subtree_invalidate_lookahead(*child, edit_byte_offset - child_start_byte, pool); child_start_byte += ts_subtree_total_bytes(*child); @@ -480,11 +489,11 @@ Subtree *ts_subtree_invalidate_lookahead(Subtree *self, uint32_t edit_byte_offse return result; } -Subtree *ts_subtree__edit(Subtree *self, Edit edit, SubtreePool *pool) { +const Subtree *ts_subtree__edit(const Subtree *self, Edit edit, SubtreePool *pool) { Length new_end = length_add(edit.start, edit.added); Length old_end = length_add(edit.start, edit.removed); - Subtree *result = ts_subtree_new_mut(pool, self); + Subtree *result = ts_subtree_make_mut(pool, self); result->has_changes = true; if (old_end.bytes <= result->padding.bytes) { @@ -501,7 +510,7 @@ Subtree *ts_subtree__edit(Subtree *self, Edit edit, SubtreePool *pool) { Length child_left, child_right = length_zero(); for (uint32_t i = 0; i < result->children.size; i++) { - Subtree **child = &result->children.contents[i]; + const Subtree **child = &result->children.contents[i]; Length child_size = ts_subtree_total_size(*child); child_left = child_right; child_right = length_add(child_left, child_size); @@ -537,7 +546,7 @@ Subtree *ts_subtree__edit(Subtree *self, Edit edit, SubtreePool *pool) { return result; } -Subtree *ts_subtree_edit(Subtree *self, const TSInputEdit *edit, SubtreePool *pool) { +const Subtree *ts_subtree_edit(const Subtree *self, const TSInputEdit *edit, SubtreePool *pool) { return ts_subtree__edit(self, (Edit) { .start = {edit->start_byte, edit->start_point}, .added = {edit->bytes_added, edit->extent_added}, @@ -545,11 +554,11 @@ Subtree *ts_subtree_edit(Subtree *self, const TSInputEdit *edit, SubtreePool *po }, pool); } -Subtree *ts_subtree_last_external_token(Subtree *tree) { +const Subtree *ts_subtree_last_external_token(const Subtree *tree) { if (!tree->has_external_tokens) return NULL; while (tree->children.size > 0) { for (uint32_t i = tree->children.size - 1; i + 1 > 0; i--) { - Subtree *child = tree->children.contents[i]; + const Subtree *child = tree->children.contents[i]; if (child->has_external_tokens) { tree = child; break; @@ -611,7 +620,7 @@ static size_t ts_subtree__write_to_string(const Subtree *self, char *string, siz const TSSymbol *alias_sequence = ts_language_alias_sequence(language, self->alias_sequence_id); uint32_t structural_child_index = 0; for (uint32_t i = 0; i < self->children.size; i++) { - Subtree *child = self->children.contents[i]; + const Subtree *child = self->children.contents[i]; if (child->extra) { cursor += ts_subtree__write_to_string( child, *writer, limit, diff --git a/src/runtime/subtree.h b/src/runtime/subtree.h index da69383d..cf59db43 100644 --- a/src/runtime/subtree.h +++ b/src/runtime/subtree.h @@ -24,7 +24,8 @@ typedef struct { typedef struct Subtree Subtree; -typedef Array(Subtree *) SubtreeArray; +typedef Array(const Subtree *) SubtreeArray; +typedef Array(Subtree *) MutableSubtreeArray; struct Subtree { Length padding; @@ -71,8 +72,8 @@ struct Subtree { }; typedef struct { - SubtreeArray free_trees; - SubtreeArray tree_stack; + MutableSubtreeArray free_trees; + MutableSubtreeArray tree_stack; } SubtreePool; void ts_external_scanner_state_init(ExternalScannerState *, const char *, unsigned); @@ -90,20 +91,21 @@ void ts_subtree_pool_free(SubtreePool *, Subtree *); Subtree *ts_subtree_new_leaf(SubtreePool *, TSSymbol, Length, Length, const TSLanguage *); Subtree *ts_subtree_new_node(SubtreePool *, TSSymbol, SubtreeArray *, unsigned, const TSLanguage *); -Subtree *ts_subtree_new_copy(SubtreePool *, Subtree *child); +Subtree *ts_subtree_new_copy(SubtreePool *, const Subtree *); Subtree *ts_subtree_new_error_node(SubtreePool *, SubtreeArray *, const TSLanguage *); Subtree *ts_subtree_new_error(SubtreePool *, Length, Length, int32_t, const TSLanguage *); Subtree *ts_subtree_new_missing_leaf(SubtreePool *, TSSymbol, const TSLanguage *); -void ts_subtree_retain(Subtree *tree); -void ts_subtree_release(SubtreePool *, Subtree *tree); +Subtree *ts_subtree_make_mut(SubtreePool *, const Subtree *); +void ts_subtree_retain(const Subtree *tree); +void ts_subtree_release(SubtreePool *, const Subtree *tree); bool ts_subtree_eq(const Subtree *tree1, const Subtree *tree2); int ts_subtree_compare(const Subtree *tree1, const Subtree *tree2); void ts_subtree_set_children(Subtree *, SubtreeArray *, const TSLanguage *); -void ts_subtree_balance(Subtree *, SubtreePool *, const TSLanguage *); -Subtree *ts_subtree_edit(Subtree *, const TSInputEdit *edit, SubtreePool *); +void ts_subtree_balance(const Subtree *, SubtreePool *, const TSLanguage *); +const Subtree *ts_subtree_edit(const Subtree *, const TSInputEdit *edit, SubtreePool *); char *ts_subtree_string(const Subtree *, const TSLanguage *, bool include_all); void ts_subtree_print_dot_graph(const Subtree *, const TSLanguage *, FILE *); -Subtree *ts_subtree_last_external_token(Subtree *); +const Subtree *ts_subtree_last_external_token(const Subtree *); bool ts_subtree_external_scanner_state_eq(const Subtree *, const Subtree *); static inline uint32_t ts_subtree_total_bytes(const Subtree *self) { diff --git a/src/runtime/tree.c b/src/runtime/tree.c index 2c365644..3e8a145e 100644 --- a/src/runtime/tree.c +++ b/src/runtime/tree.c @@ -17,7 +17,7 @@ TSTree *ts_tree_copy(const TSTree *self) { return ts_tree_new(self->root, self->language); } -void ts_tree_delete(const TSTree *self) { +void ts_tree_delete(TSTree *self) { SubtreePool pool = ts_subtree_pool_new(0); ts_subtree_release(&pool, self->root); ts_subtree_pool_delete(&pool); diff --git a/src/runtime/tree_cursor.c b/src/runtime/tree_cursor.c index c7aa9691..31eee8b4 100644 --- a/src/runtime/tree_cursor.c +++ b/src/runtime/tree_cursor.c @@ -28,7 +28,7 @@ void ts_tree_cursor_delete(TSTreeCursor *self) { bool ts_tree_cursor_goto_first_child(TSTreeCursor *self) { TreeCursorEntry *last_entry = array_back(&self->stack); - Subtree *tree = last_entry->subtree; + const Subtree *tree = last_entry->subtree; Length position = last_entry->position; bool did_descend; @@ -37,7 +37,7 @@ bool ts_tree_cursor_goto_first_child(TSTreeCursor *self) { uint32_t structural_child_index = 0; for (uint32_t i = 0; i < tree->children.size; i++) { - Subtree *child = tree->children.contents[i]; + const Subtree *child = tree->children.contents[i]; if (child->visible || child->visible_child_count > 0) { array_push(&self->stack, ((TreeCursorEntry) { .subtree = child, @@ -68,11 +68,11 @@ bool ts_tree_cursor_goto_next_sibling(TSTreeCursor *self) { for (unsigned i = self->stack.size - 2; i + 1 > 0; i--) { TreeCursorEntry *parent_entry = &self->stack.contents[i]; - Subtree *parent = parent_entry->subtree; + const Subtree *parent = parent_entry->subtree; uint32_t child_index = child_entry->child_index; uint32_t structural_child_index = child_entry->structural_child_index; Length position = child_entry->position; - Subtree *child = parent->children.contents[child_index]; + const Subtree *child = parent->children.contents[child_index]; while (++child_index < parent->children.size) { if (!child->extra) structural_child_index++; diff --git a/src/runtime/tree_cursor.h b/src/runtime/tree_cursor.h index c016b276..615e7e06 100644 --- a/src/runtime/tree_cursor.h +++ b/src/runtime/tree_cursor.h @@ -4,7 +4,7 @@ #include "runtime/subtree.h" typedef struct { - Subtree *subtree; + const Subtree *subtree; Length position; uint32_t child_index; uint32_t structural_child_index; diff --git a/test/helpers/tree_helpers.cc b/test/helpers/tree_helpers.cc index 7fd015a3..0e63a19f 100644 --- a/test/helpers/tree_helpers.cc +++ b/test/helpers/tree_helpers.cc @@ -14,11 +14,11 @@ const char *symbol_names[24] = { "twenty-two", "twenty-three" }; -SubtreeArray *tree_array(std::vector trees) { +SubtreeArray *tree_array(std::vector trees) { static SubtreeArray result; result.capacity = trees.size(); result.size = trees.size(); - result.contents = (Subtree **)calloc(trees.size(), sizeof(Subtree *)); + result.contents = (const Subtree **)calloc(trees.size(), sizeof(Subtree *)); for (size_t i = 0; i < trees.size(); i++) { result.contents[i] = trees[i]; } @@ -49,7 +49,7 @@ bool operator==(const TSNode &left, const TSNode &right) { return ts_node_eq(left, right); } -bool operator==(const std::vector &vec, const SubtreeArray &array) { +bool operator==(const std::vector &vec, const SubtreeArray &array) { if (vec.size() != array.size) return false; for (size_t i = 0; i < array.size; i++) diff --git a/test/helpers/tree_helpers.h b/test/helpers/tree_helpers.h index bd08aad7..00740faf 100644 --- a/test/helpers/tree_helpers.h +++ b/test/helpers/tree_helpers.h @@ -6,12 +6,12 @@ #include extern const char *symbol_names[24]; -SubtreeArray *tree_array(std::vector trees); +SubtreeArray *tree_array(std::vector trees); std::ostream &operator<<(std::ostream &stream, const Subtree *tree); std::ostream &operator<<(std::ostream &stream, const TSNode &node); bool operator==(const TSNode &left, const TSNode &right); -bool operator==(const std::vector &right, const SubtreeArray &array); +bool operator==(const std::vector &right, const SubtreeArray &array); void assert_consistent_tree_sizes(TSNode node); diff --git a/test/runtime/stack_test.cc b/test/runtime/stack_test.cc index 67812a07..68104935 100644 --- a/test/runtime/stack_test.cc +++ b/test/runtime/stack_test.cc @@ -44,6 +44,10 @@ void free_slice_array(SubtreePool *pool, StackSliceArray *slices) { } } +Subtree *mutate(const Subtree *subtree) { + return (Subtree *)subtree; +} + struct StackEntry { TSStateId state; size_t depth; @@ -69,7 +73,7 @@ START_TEST describe("Stack", [&]() { Stack *stack; const size_t subtree_count = 11; - Subtree *subtrees[subtree_count]; + const Subtree *subtrees[subtree_count]; Length tree_len = {3, {0, 3}}; SubtreePool pool; @@ -84,7 +88,7 @@ describe("Stack", [&]() { dummy_language.symbol_metadata = symbol_metadata; for (size_t i = 0; i < subtree_count; i++) { - subtrees[i] = ts_subtree_new_leaf(&pool, i, length_zero(), tree_len, &dummy_language); + subtrees[i] = ts_subtree_new_leaf(&pool, i + 1, length_zero(), tree_len, &dummy_language); } }); @@ -99,7 +103,7 @@ describe("Stack", [&]() { AssertThat(record_alloc::outstanding_allocation_indices(), IsEmpty()); }); - auto push = [&](StackVersion version, Subtree *tree, TSStateId state) { + auto push = [&](StackVersion version, const Subtree *tree, TSStateId state) { ts_subtree_retain(tree); ts_stack_push(stack, version, tree, false, state); }; @@ -181,7 +185,7 @@ describe("Stack", [&]() { // . <──0── A <──1── B <────3──── D* // ↑ // └───2─── C <──4── D* - subtrees[3]->size = tree_len * 3; + mutate(subtrees[3])->size = tree_len * 3; push(0, subtrees[1], stateB); push(1, subtrees[2], stateC); push(0, subtrees[3], stateD); @@ -224,8 +228,8 @@ describe("Stack", [&]() { // . <──0── A <────1──── B* // ↑ // └2─ A <──1── B* - subtrees[2]->extra = true; - subtrees[2]->size = tree_len * 0; + mutate(subtrees[2])->extra = true; + mutate(subtrees[2])->size = tree_len * 0; push(0, subtrees[1], stateB); push(1, subtrees[2], stateA); @@ -261,14 +265,14 @@ describe("Stack", [&]() { StackSlice slice = pop.contents[0]; AssertThat(slice.version, Equals(1)); - AssertThat(slice.subtrees, Equals(vector({ subtrees[1], subtrees[2] }))); + AssertThat(slice.subtrees, Equals(vector({ subtrees[1], subtrees[2] }))); AssertThat(ts_stack_state(stack, 1), Equals(stateA)); free_slice_array(&pool,&pop); }); it("does not count 'extra' subtrees toward the given count", [&]() { - subtrees[1]->extra = true; + mutate(subtrees[1])->extra = true; // . <──0── A <──1── B <──2── C* // ↑ @@ -277,7 +281,7 @@ describe("Stack", [&]() { AssertThat(pop.size, Equals(1)); StackSlice slice = pop.contents[0]; - AssertThat(slice.subtrees, Equals(vector({ subtrees[0], subtrees[1], subtrees[2] }))); + AssertThat(slice.subtrees, Equals(vector({ subtrees[0], subtrees[1], subtrees[2] }))); AssertThat(ts_stack_state(stack, 1), Equals(1)); free_slice_array(&pool,&pop); @@ -322,11 +326,11 @@ describe("Stack", [&]() { StackSlice slice1 = pop.contents[0]; AssertThat(slice1.version, Equals(1)); - AssertThat(slice1.subtrees, Equals(vector({ subtrees[2], subtrees[3], subtrees[10] }))); + AssertThat(slice1.subtrees, Equals(vector({ subtrees[2], subtrees[3], subtrees[10] }))); StackSlice slice2 = pop.contents[1]; AssertThat(slice2.version, Equals(2)); - AssertThat(slice2.subtrees, Equals(vector({ subtrees[5], subtrees[6], subtrees[10] }))); + AssertThat(slice2.subtrees, Equals(vector({ subtrees[5], subtrees[6], subtrees[10] }))); AssertThat(ts_stack_version_count(stack), Equals(3)); AssertThat(get_stack_entries(stack, 0), Equals(vector({ @@ -366,7 +370,7 @@ describe("Stack", [&]() { StackSlice slice1 = pop.contents[0]; AssertThat(slice1.version, Equals(1)); - AssertThat(slice1.subtrees, Equals(vector({ subtrees[10] }))); + AssertThat(slice1.subtrees, Equals(vector({ subtrees[10] }))); AssertThat(ts_stack_version_count(stack), Equals(2)); AssertThat(ts_stack_state(stack, 0), Equals(stateI)); @@ -388,11 +392,11 @@ describe("Stack", [&]() { StackSlice slice1 = pop.contents[0]; AssertThat(slice1.version, Equals(1)); - AssertThat(slice1.subtrees, Equals(vector({ subtrees[1], subtrees[2], subtrees[3], subtrees[10] }))); + AssertThat(slice1.subtrees, Equals(vector({ subtrees[1], subtrees[2], subtrees[3], subtrees[10] }))); StackSlice slice2 = pop.contents[1]; AssertThat(slice2.version, Equals(1)); - AssertThat(slice2.subtrees, Equals(vector({ subtrees[4], subtrees[5], subtrees[6], subtrees[10] }))); + AssertThat(slice2.subtrees, Equals(vector({ subtrees[4], subtrees[5], subtrees[6], subtrees[10] }))); AssertThat(ts_stack_version_count(stack), Equals(2)); AssertThat(ts_stack_state(stack, 0), Equals(stateI)); @@ -443,15 +447,15 @@ describe("Stack", [&]() { StackSlice slice1 = pop.contents[0]; AssertThat(slice1.version, Equals(1)); - AssertThat(slice1.subtrees, Equals(vector({ subtrees[3], subtrees[10] }))); + AssertThat(slice1.subtrees, Equals(vector({ subtrees[3], subtrees[10] }))); StackSlice slice2 = pop.contents[1]; AssertThat(slice2.version, Equals(2)); - AssertThat(slice2.subtrees, Equals(vector({ subtrees[6], subtrees[10] }))); + AssertThat(slice2.subtrees, Equals(vector({ subtrees[6], subtrees[10] }))); StackSlice slice3 = pop.contents[2]; AssertThat(slice3.version, Equals(3)); - AssertThat(slice3.subtrees, Equals(vector({ subtrees[9], subtrees[10] }))); + AssertThat(slice3.subtrees, Equals(vector({ subtrees[9], subtrees[10] }))); AssertThat(ts_stack_version_count(stack), Equals(4)); AssertThat(ts_stack_state(stack, 0), Equals(stateI)); @@ -489,8 +493,8 @@ describe("Stack", [&]() { ts_stack_push(stack, 0, subtrees[1], true, stateB); ts_subtree_retain(subtrees[1]); - subtrees[2]->extra = true; - subtrees[3]->extra = true; + mutate(subtrees[2])->extra = true; + mutate(subtrees[3])->extra = true; push(0, subtrees[2], stateB); push(0, subtrees[3], stateB); @@ -498,7 +502,7 @@ describe("Stack", [&]() { StackSliceArray pop = ts_stack_pop_pending(stack, 0); AssertThat(pop.size, Equals(1)); - AssertThat(pop.contents[0].subtrees, Equals(vector({ subtrees[1], subtrees[2], subtrees[3] }))); + AssertThat(pop.contents[0].subtrees, Equals(vector({ subtrees[1], subtrees[2], subtrees[3] }))); AssertThat(get_stack_entries(stack, 0), Equals(vector({ {stateA, 0}, @@ -526,10 +530,10 @@ describe("Stack", [&]() { describe("setting external token state", [&]() { before_each([&]() { - subtrees[1]->has_external_tokens = true; - subtrees[2]->has_external_tokens = true; - ts_external_scanner_state_init(&subtrees[1]->external_scanner_state, NULL, 0); - ts_external_scanner_state_init(&subtrees[2]->external_scanner_state, NULL, 0); + mutate(subtrees[1])->has_external_tokens = true; + mutate(subtrees[2])->has_external_tokens = true; + ts_external_scanner_state_init(&mutate(subtrees[1])->external_scanner_state, NULL, 0); + ts_external_scanner_state_init(&mutate(subtrees[2])->external_scanner_state, NULL, 0); }); it("allows the state to be retrieved", [&]() { @@ -546,8 +550,8 @@ describe("Stack", [&]() { }); it("does not merge stack versions with different external token states", [&]() { - ts_external_scanner_state_init(&subtrees[1]->external_scanner_state, "abcd", 2); - ts_external_scanner_state_init(&subtrees[2]->external_scanner_state, "ABCD", 2); + ts_external_scanner_state_init(&mutate(subtrees[1])->external_scanner_state, "abcd", 2); + ts_external_scanner_state_init(&mutate(subtrees[2])->external_scanner_state, "ABCD", 2); ts_stack_copy_version(stack, 0); push(0, subtrees[0], 5); @@ -560,8 +564,8 @@ describe("Stack", [&]() { }); it("merges stack versions with identical external token states", [&]() { - ts_external_scanner_state_init(&subtrees[1]->external_scanner_state, "abcd", 2); - ts_external_scanner_state_init(&subtrees[2]->external_scanner_state, "abcd", 2); + ts_external_scanner_state_init(&mutate(subtrees[1])->external_scanner_state, "abcd", 2); + ts_external_scanner_state_init(&mutate(subtrees[2])->external_scanner_state, "abcd", 2); ts_stack_copy_version(stack, 0); push(0, subtrees[0], 5); diff --git a/test/runtime/subtree_test.cc b/test/runtime/subtree_test.cc index 4d32ec32..3c1c9ad2 100644 --- a/test/runtime/subtree_test.cc +++ b/test/runtime/subtree_test.cc @@ -10,7 +10,7 @@ void assert_consistent(const Subtree *tree) { Length total_children_size = length_zero(); for (size_t i = 0; i < tree->children.size; i++) { - Subtree *child = tree->children.contents[i]; + const Subtree *child = tree->children.contents[i]; assert_consistent(child); total_children_size = length_add(total_children_size, ts_subtree_total_size(child)); } @@ -50,7 +50,7 @@ describe("Subtree", []() { describe("make_leaf", [&]() { it("does not mark the tree as fragile", [&]() { - Subtree *tree = ts_subtree_new_leaf(&pool, symbol1, {2, {0, 1}}, {5, {0, 4}}, &language); + const Subtree *tree = ts_subtree_new_leaf(&pool, symbol1, {2, {0, 1}}, {5, {0, 4}}, &language); AssertThat(tree->fragile_left, IsFalse()); AssertThat(tree->fragile_right, IsFalse()); @@ -60,7 +60,7 @@ describe("Subtree", []() { describe("make_error", [&]() { it("marks the tree as fragile", [&]() { - Subtree *error_tree = ts_subtree_new_error( + const Subtree *error_tree = ts_subtree_new_error( &pool, length_zero(), length_zero(), @@ -76,7 +76,7 @@ describe("Subtree", []() { }); describe("make_node", [&]() { - Subtree *tree1, *tree2, *parent1; + const Subtree *tree1, *tree2, *parent1; before_each([&]() { tree1 = ts_subtree_new_leaf(&pool, symbol1, {2, {0, 1}}, {5, {0, 4}}, &language); @@ -104,11 +104,12 @@ describe("Subtree", []() { }); describe("when the first node is fragile on the left side", [&]() { - Subtree *parent; + const Subtree *parent; before_each([&]() { - tree1->fragile_left = true; - tree1->extra = true; + Subtree *mutable_tree1 = (Subtree *)tree1; + mutable_tree1->fragile_left = true; + mutable_tree1->extra = true; ts_subtree_retain(tree1); ts_subtree_retain(tree2); @@ -128,11 +129,12 @@ describe("Subtree", []() { }); describe("when the last node is fragile on the right side", [&]() { - Subtree *parent; + const Subtree *parent; before_each([&]() { - tree2->fragile_right = true; - tree2->extra = true; + Subtree *mutable_tree2 = (Subtree *)tree2; + mutable_tree2->fragile_right = true; + mutable_tree2->extra = true; ts_subtree_retain(tree1); ts_subtree_retain(tree2); @@ -152,11 +154,13 @@ describe("Subtree", []() { }); describe("when the outer nodes aren't fragile on their outer side", [&]() { - Subtree *parent; + const Subtree *parent; before_each([&]() { - tree1->fragile_right = true; - tree2->fragile_left = true; + Subtree *mutable_tree1 = (Subtree *)tree1; + Subtree *mutable_tree2 = (Subtree *)tree2; + mutable_tree1->fragile_right = true; + mutable_tree2->fragile_left = true; ts_subtree_retain(tree1); ts_subtree_retain(tree2); @@ -178,7 +182,7 @@ describe("Subtree", []() { }); describe("edit", [&]() { - Subtree *tree; + const Subtree *tree; before_each([&]() { tree = ts_subtree_new_node(&pool, symbol1, tree_array({ @@ -205,7 +209,7 @@ describe("Subtree", []() { edit.extent_added = {0, 1}; ts_subtree_retain(tree); - Subtree *new_tree = ts_subtree_edit(tree, &edit, &pool); + const Subtree *new_tree = ts_subtree_edit(tree, &edit, &pool); assert_consistent(tree); assert_consistent(new_tree); @@ -352,7 +356,8 @@ describe("Subtree", []() { describe("edits within a tree's range of scanned bytes", [&]() { it("marks preceding trees as changed", [&]() { - tree->children.contents[0]->bytes_scanned = 7; + Subtree *mutable_child = (Subtree *)tree->children.contents[0]; + mutable_child->bytes_scanned = 7; TSInputEdit edit; edit.start_byte = 6; @@ -370,7 +375,7 @@ describe("Subtree", []() { }); describe("eq", [&]() { - Subtree *leaf; + const Subtree *leaf; before_each([&]() { leaf = ts_subtree_new_leaf(&pool, symbol1, {2, {0, 1}}, {5, {0, 4}}, &language); @@ -381,17 +386,17 @@ describe("Subtree", []() { }); it("returns true for identical trees", [&]() { - Subtree *leaf_copy = ts_subtree_new_leaf(&pool, symbol1, {2, {1, 1}}, {5, {1, 4}}, &language); + const Subtree *leaf_copy = ts_subtree_new_leaf(&pool, symbol1, {2, {1, 1}}, {5, {1, 4}}, &language); AssertThat(ts_subtree_eq(leaf, leaf_copy), IsTrue()); - Subtree *parent = ts_subtree_new_node(&pool, symbol2, tree_array({ + const Subtree *parent = ts_subtree_new_node(&pool, symbol2, tree_array({ leaf, leaf_copy, }), 0, &language); ts_subtree_retain(leaf); ts_subtree_retain(leaf_copy); - Subtree *parent_copy = ts_subtree_new_node(&pool, symbol2, tree_array({ + const Subtree *parent_copy = ts_subtree_new_node(&pool, symbol2, tree_array({ leaf, leaf_copy, }), 0, &language); @@ -406,7 +411,7 @@ describe("Subtree", []() { }); it("returns false for trees with different symbols", [&]() { - Subtree *different_leaf = ts_subtree_new_leaf( + const Subtree *different_leaf = ts_subtree_new_leaf( &pool, leaf->symbol + 1, leaf->padding, @@ -419,14 +424,16 @@ describe("Subtree", []() { }); it("returns false for trees with different options", [&]() { - Subtree *different_leaf = ts_subtree_new_leaf(&pool, leaf->symbol, leaf->padding, leaf->size, &language); - different_leaf->visible = !leaf->visible; + const Subtree *different_leaf = ts_subtree_new_leaf( + &pool, leaf->symbol, leaf->padding, leaf->size, &language + ); + ((Subtree *)different_leaf)->visible = !leaf->visible; AssertThat(ts_subtree_eq(leaf, different_leaf), IsFalse()); ts_subtree_release(&pool, different_leaf); }); it("returns false for trees with different paddings or sizes", [&]() { - Subtree *different_leaf = ts_subtree_new_leaf(&pool, leaf->symbol, {}, leaf->size, &language); + const Subtree *different_leaf = ts_subtree_new_leaf(&pool, leaf->symbol, {}, leaf->size, &language); AssertThat(ts_subtree_eq(leaf, different_leaf), IsFalse()); ts_subtree_release(&pool, different_leaf); @@ -436,16 +443,16 @@ describe("Subtree", []() { }); it("returns false for trees with different children", [&]() { - Subtree *leaf2 = ts_subtree_new_leaf(&pool, symbol2, {1, {0, 1}}, {3, {0, 3}}, &language); + const Subtree *leaf2 = ts_subtree_new_leaf(&pool, symbol2, {1, {0, 1}}, {3, {0, 3}}, &language); - Subtree *parent = ts_subtree_new_node(&pool, symbol2, tree_array({ + const Subtree *parent = ts_subtree_new_node(&pool, symbol2, tree_array({ leaf, leaf2, }), 0, &language); ts_subtree_retain(leaf); ts_subtree_retain(leaf2); - Subtree *different_parent = ts_subtree_new_node(&pool, symbol2, tree_array({ + const Subtree *different_parent = ts_subtree_new_node(&pool, symbol2, tree_array({ leaf2, leaf, }), 0, &language); @@ -465,13 +472,13 @@ describe("Subtree", []() { Length padding = {1, {0, 1}}; Length size = {2, {0, 2}}; - auto make_external = [](Subtree *tree) { - tree->has_external_tokens = true; + auto make_external = [](const Subtree *tree) { + ((Subtree *)tree)->has_external_tokens = true; return tree; }; it("returns the last serialized external token state in the given tree", [&]() { - Subtree *tree1, *tree2, *tree3, *tree4, *tree5, *tree6, *tree7, *tree8, *tree9; + const Subtree *tree1, *tree2, *tree3, *tree4, *tree5, *tree6, *tree7, *tree8, *tree9; tree1 = ts_subtree_new_node(&pool, symbol1, tree_array({ (tree2 = ts_subtree_new_node(&pool, symbol2, tree_array({