From 09be0b6ef5902ce114494b994a9118880e4f4762 Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Mon, 2 Apr 2018 18:04:26 -0700 Subject: [PATCH] Store trees' children in TreeArrays, not w/ separate pointer and length --- src/runtime/array.h | 8 +- src/runtime/get_changed_ranges.c | 8 +- src/runtime/node.c | 20 ++-- src/runtime/parser.c | 53 +++++----- src/runtime/reusable_node.h | 12 +-- src/runtime/stack.c | 4 +- src/runtime/tree.c | 163 +++++++++++++++---------------- src/runtime/tree.h | 72 +++++++------- test/helpers/tree_helpers.cc | 11 ++- test/helpers/tree_helpers.h | 2 +- test/runtime/tree_test.cc | 88 ++++++++--------- 11 files changed, 220 insertions(+), 221 deletions(-) diff --git a/src/runtime/array.h b/src/runtime/array.h index 0fa08d5a..e4e7ff0f 100644 --- a/src/runtime/array.h +++ b/src/runtime/array.h @@ -12,18 +12,18 @@ extern "C" { #include #include "runtime/alloc.h" -#define Array(T) \ - struct { \ - T *contents; \ +#define Array(T) \ + struct { \ uint32_t size; \ uint32_t capacity; \ + T *contents; \ } #define array_init(self) \ ((self)->size = 0, (self)->capacity = 0, (self)->contents = NULL) #define array_new() \ - { NULL, 0, 0 } + { 0, 0, NULL } #define array_get(self, index) \ (assert((uint32_t)index < (self)->size), &(self)->contents[index]) diff --git a/src/runtime/get_changed_ranges.c b/src/runtime/get_changed_ranges.c index 41fc1877..26211613 100644 --- a/src/runtime/get_changed_ranges.c +++ b/src/runtime/get_changed_ranges.c @@ -127,8 +127,8 @@ static bool iterator_descend(Iterator *self, uint32_t goal_position) { TreePathEntry entry = *array_back(&self->path); Length position = entry.position; uint32_t structural_child_index = 0; - for (uint32_t i = 0; i < entry.tree->child_count; i++) { - Tree *child = entry.tree->children[i]; + for (uint32_t i = 0; i < entry.tree->children.size; i++) { + Tree *child = entry.tree->children.contents[i]; Length child_left = length_add(position, child->padding); Length child_right = length_add(child_left, child->size); @@ -179,11 +179,11 @@ static void iterator_advance(Iterator *self) { Tree *parent = array_back(&self->path)->tree; uint32_t child_index = entry.child_index + 1; - if (parent->child_count > child_index) { + if (parent->children.size > child_index) { Length position = length_add(entry.position, ts_tree_total_size(entry.tree)); uint32_t structural_child_index = entry.structural_child_index; if (!entry.tree->extra) structural_child_index++; - Tree *next_child = parent->children[child_index]; + Tree *next_child = parent->children.contents[child_index]; array_push(&self->path, ((TreePathEntry){ .tree = next_child, diff --git a/src/runtime/node.c b/src/runtime/node.c index 1f7487cb..c825a104 100644 --- a/src/runtime/node.c +++ b/src/runtime/node.c @@ -39,7 +39,7 @@ static inline bool ts_node__is_relevant(TSNode self, bool include_anonymous) { static inline uint32_t ts_node__relevant_child_count(TSNode self, bool include_anonymous) { const Tree *tree = ts_node__tree(self); - if (tree->child_count > 0) { + if (tree->children.size > 0) { if (include_anonymous) { return tree->visible_child_count; } else { @@ -61,7 +61,7 @@ static inline TSNode ts_node__direct_parent(TSNode self, uint32_t *index) { } static inline TSNode ts_node__direct_child(TSNode self, uint32_t i) { - const Tree *child_tree = ts_node__tree(self)->children[i]; + const Tree *child_tree = ts_node__tree(self)->children.contents[i]; return ts_node_make( child_tree, ts_node__offset_byte(self) + child_tree->context.offset.bytes, @@ -78,7 +78,7 @@ static inline TSNode ts_node__child(TSNode self, uint32_t child_index, did_descend = false; uint32_t index = 0; - for (uint32_t i = 0; i < ts_node__tree(result)->child_count; i++) { + for (uint32_t i = 0; i < ts_node__tree(result)->children.size; i++) { TSNode child = ts_node__direct_child(result, i); if (ts_node__is_relevant(child, include_anonymous)) { if (index == child_index) @@ -134,7 +134,7 @@ static inline TSNode ts_node__next_sibling(TSNode self, bool include_anonymous) if (!result.data) break; - for (uint32_t i = index + 1; i < ts_node__tree(result)->child_count; i++) { + for (uint32_t i = index + 1; i < ts_node__tree(result)->children.size; i++) { TSNode child = ts_node__direct_child(result, i); if (ts_node__is_relevant(child, include_anonymous)) return child; @@ -160,7 +160,7 @@ static inline TSNode ts_node__first_child_for_byte(TSNode self, uint32_t goal, while (did_descend) { did_descend = false; - for (uint32_t i = 0; i < ts_node__tree(node)->child_count; i++) { + for (uint32_t i = 0; i < ts_node__tree(node)->children.size; i++) { TSNode child = ts_node__direct_child(node, i); if (ts_node_end_byte(child) > goal) { if (ts_node__is_relevant(child, include_anonymous)) { @@ -187,7 +187,7 @@ static inline TSNode ts_node__descendant_for_byte_range(TSNode self, uint32_t mi while (did_descend) { did_descend = false; - for (uint32_t i = 0, n = ts_node__tree(node)->child_count; i < n; i++) { + for (uint32_t i = 0, n = ts_node__tree(node)->children.size; i < n; i++) { TSNode child = ts_node__direct_child(node, i); if (ts_node_end_byte(child) > max) { if (ts_node_start_byte(child) > min) break; @@ -214,7 +214,7 @@ static inline TSNode ts_node__descendant_for_point_range(TSNode self, TSPoint mi while (did_descend) { did_descend = false; - for (uint32_t i = 0, n = ts_node__tree(node)->child_count; i < n; i++) { + for (uint32_t i = 0, n = ts_node__tree(node)->children.size; i < n; i++) { TSNode child = ts_node__direct_child(node, i); const Tree *child_tree = ts_node__tree(child); if (i > 0) start_position = point_add(start_position, child_tree->padding.extent); @@ -318,7 +318,7 @@ uint32_t ts_node_child_index(TSNode self) { uint32_t index = tree->context.index; if (!parent) return UINT32_MAX; for (uint32_t i = 0; i < index; i++) { - Tree *child = parent->children[i]; + Tree *child = parent->children.contents[i]; result += child->visible ? 1 : child->visible_child_count; } if (parent->visible) break; @@ -338,7 +338,7 @@ TSNode ts_node_named_child(TSNode self, uint32_t child_index) { uint32_t ts_node_child_count(TSNode self) { const Tree *tree = ts_node__tree(self); - if (tree->child_count > 0) { + if (tree->children.size > 0) { return tree->visible_child_count; } else { return 0; @@ -347,7 +347,7 @@ uint32_t ts_node_child_count(TSNode self) { uint32_t ts_node_named_child_count(TSNode self) { const Tree *tree = ts_node__tree(self); - if (tree->child_count > 0) { + if (tree->children.size > 0) { return tree->named_child_count; } else { return 0; diff --git a/src/runtime/parser.c b/src/runtime/parser.c index 9baf4ce2..a377c42a 100644 --- a/src/runtime/parser.c +++ b/src/runtime/parser.c @@ -86,9 +86,9 @@ static bool parser__breakdown_top_of_stack(Parser *self, StackVersion version) { TSStateId state = ts_stack_state(self->stack, slice.version); Tree *parent = *array_front(&slice.trees); - for (uint32_t j = 0; j < parent->child_count; j++) { - Tree *child = parent->children[j]; - pending = child->child_count > 0; + for (uint32_t j = 0; j < parent->children.size; j++) { + Tree *child = parent->children.contents[j]; + pending = child->children.size > 0; if (child->symbol == ts_builtin_sym_error) { state = ERROR_STATE; @@ -120,7 +120,7 @@ static void parser__breakdown_lookahead(Parser *self, Tree **lookahead, TSStateId state, ReusableNode *reusable_node) { bool did_break_down = false; - while (reusable_node->tree->child_count > 0 && reusable_node->tree->parse_state != state) { + while (reusable_node->tree->children.size > 0 && reusable_node->tree->parse_state != state) { LOG("state_mismatch sym:%s", SYM_NAME(reusable_node->tree->symbol)); reusable_node_breakdown(reusable_node); did_break_down = true; @@ -447,7 +447,7 @@ static Tree *parser__get_lookahead(Parser *self, StackVersion version, TSStateId reason = "is_missing"; } else if (result->fragile_left || result->fragile_right) { reason = "is_fragile"; - } else if (self->in_ambiguity && result->child_count) { + } else if (self->in_ambiguity && result->children.size) { reason = "in_ambiguity"; } @@ -555,7 +555,7 @@ static void parser__shift(Parser *self, StackVersion version, TSStateId state, ts_tree_retain(lookahead); } - bool is_pending = lookahead->child_count > 0; + bool is_pending = lookahead->children.size > 0; ts_stack_push(self->stack, version, lookahead, is_pending, state); if (lookahead->has_external_tokens) { ts_stack_set_last_external_token( @@ -564,10 +564,10 @@ static void parser__shift(Parser *self, StackVersion version, TSStateId state, } } -static bool parser__replace_children(Parser *self, Tree *tree, Tree **children, uint32_t count) { +static bool parser__replace_children(Parser *self, Tree *tree, TreeArray *children) { self->scratch_tree = *tree; - self->scratch_tree.child_count = 0; - ts_tree_set_children(&self->scratch_tree, count, children, self->language); + self->scratch_tree.children.size = 0; + ts_tree_set_children(&self->scratch_tree, children, self->language); if (parser__select_tree(self, tree, &self->scratch_tree)) { *tree = self->scratch_tree; return true; @@ -589,13 +589,13 @@ static StackSliceArray parser__reduce(Parser *self, StackVersion version, TSSymb // Extra tokens on top of the stack should not be included in this new parent // node. They will be re-pushed onto the stack after the parent node is // created and pushed. - uint32_t child_count = slice.trees.size; - while (child_count > 0 && slice.trees.contents[child_count - 1]->extra) { - child_count--; + TreeArray children = slice.trees; + while (children.size > 0 && children.contents[children.size - 1]->extra) { + children.size--; } Tree *parent = ts_tree_make_node(&self->tree_pool, - symbol, child_count, slice.trees.contents, alias_sequence_id, self->language + symbol, &children, alias_sequence_id, self->language ); // This pop operation may have caused multiple stack versions to collapse @@ -607,12 +607,12 @@ static StackSliceArray parser__reduce(Parser *self, StackVersion version, TSSymb if (next_slice.version != slice.version) break; i++; - uint32_t child_count = next_slice.trees.size; - while (child_count > 0 && next_slice.trees.contents[child_count - 1]->extra) { - child_count--; + TreeArray children = next_slice.trees; + while (children.size > 0 && children.contents[children.size - 1]->extra) { + children.size--; } - if (parser__replace_children(self, parent, next_slice.trees.contents, child_count)) { + if (parser__replace_children(self, parent, &children)) { ts_tree_array_delete(&self->tree_pool, &slice.trees); slice = next_slice; } else { @@ -636,9 +636,8 @@ static StackSliceArray parser__reduce(Parser *self, StackVersion version, TSSymb // 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); - 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); + for (uint32_t j = parent->children.size; j < slice.trees.size; j++) { + ts_stack_push(self->stack, slice.version, slice.trees.contents[j], false, next_state); } } @@ -690,12 +689,12 @@ static void parser__accept(Parser *self, StackVersion version, Tree *child = trees.contents[j]; if (!child->extra) { root = ts_tree_make_copy(&self->tree_pool, child); - root->child_count = 0; - for (uint32_t k = 0; k < child->child_count; k++) { - ts_tree_retain(child->children[k]); + root->children.size = 0; + for (uint32_t k = 0; k < child->children.size; k++) { + ts_tree_retain(child->children.contents[k]); } - array_splice(&trees, j, 1, child->child_count, child->children); - ts_tree_set_children(root, trees.size, trees.contents, self->language); + array_splice(&trees, j, 1, child->children.size, child->children.contents); + ts_tree_set_children(root, &trees, self->language); ts_tree_release(&self->tree_pool, child); break; } @@ -1020,7 +1019,7 @@ static void parser__advance(Parser *self, StackVersion version, ReusableNode *re LOG("shift state:%u", next_state); } - if (lookahead->child_count > 0) { + if (lookahead->children.size > 0) { parser__breakdown_lookahead(self, &lookahead, state, reusable_node); next_state = ts_language_next_state(self->language, state, lookahead->symbol); } @@ -1052,7 +1051,7 @@ static void parser__advance(Parser *self, StackVersion version, ReusableNode *re } case TSParseActionTypeRecover: { - while (lookahead->child_count > 0) { + while (lookahead->children.size > 0) { parser__breakdown_lookahead(self, &lookahead, state, reusable_node); } parser__recover(self, version, lookahead); diff --git a/src/runtime/reusable_node.h b/src/runtime/reusable_node.h index 87d20dbf..04b9af7e 100644 --- a/src/runtime/reusable_node.h +++ b/src/runtime/reusable_node.h @@ -20,8 +20,8 @@ static inline void reusable_node_pop(ReusableNode *self) { while (self->tree) { Tree *parent = self->tree->context.parent; uint32_t next_index = self->tree->context.index + 1; - if (parent && parent->child_count > next_index) { - self->tree = parent->children[next_index]; + if (parent && parent->children.size > next_index) { + self->tree = parent->children.contents[next_index]; return; } self->tree = parent; @@ -30,17 +30,17 @@ static inline void reusable_node_pop(ReusableNode *self) { static inline ReusableNode reusable_node_after_leaf(const ReusableNode *self) { ReusableNode result = *self; - while (result.tree->child_count > 0) - result.tree = result.tree->children[0]; + while (result.tree->children.size > 0) + result.tree = result.tree->children.contents[0]; reusable_node_pop(&result); return result; } static inline bool reusable_node_breakdown(ReusableNode *self) { - if (self->tree->child_count == 0) { + if (self->tree->children.size == 0) { return false; } else { - self->tree = self->tree->children[0]; + self->tree = self->tree->children.contents[0]; return true; } } diff --git a/src/runtime/stack.c b/src/runtime/stack.c index 885083e4..aa2eaed4 100644 --- a/src/runtime/stack.c +++ b/src/runtime/stack.c @@ -147,7 +147,7 @@ static StackNode *stack_node_new(StackNode *previous_node, Tree *tree, bool is_p if (state == ERROR_STATE) { node->error_cost += - ERROR_COST_PER_SKIPPED_TREE * ((tree->visible || tree->child_count == 0) ? 1 : tree->visible_child_count) + + ERROR_COST_PER_SKIPPED_TREE * ((tree->visible || tree->children.size == 0) ? 1 : tree->visible_child_count) + ERROR_COST_PER_SKIPPED_CHAR * tree->size.bytes + ERROR_COST_PER_SKIPPED_LINE * tree->size.extent.row; if (previous_node->links[0].tree) { @@ -173,7 +173,7 @@ static bool stack__tree_is_equivalent(const Tree *left, const Tree *right) { right && left->symbol == right->symbol && ((left->error_cost > 0 && right->error_cost > 0) || - (left->child_count == 0 && right->child_count == 0 && + (left->children.size == 0 && right->children.size == 0 && left->padding.bytes == right->padding.bytes && left->size.bytes == right->size.bytes && left->extra == right->extra && diff --git a/src/runtime/tree.c b/src/runtime/tree.c index f88895d2..06828f3b 100644 --- a/src/runtime/tree.c +++ b/src/runtime/tree.c @@ -169,8 +169,6 @@ Tree *ts_tree_make_leaf(TreePool *pool, TSSymbol symbol, Length padding, Length .ref_count = 1, .symbol = symbol, .size = size, - .child_count = 0, - .children = NULL, .visible_child_count = 0, .named_child_count = 0, .alias_sequence_id = 0, @@ -207,50 +205,50 @@ Tree *ts_tree_make_copy(TreePool *pool, Tree *self) { static void ts_tree__compress(Tree *self, unsigned count, const TSLanguage *language) { Tree *tree = self; for (unsigned i = 0; i < count; i++) { - if (tree->ref_count > 1 || tree->child_count != 2) break; + if (tree->ref_count > 1 || tree->children.size != 2) break; - Tree *child = tree->children[0]; + Tree *child = tree->children.contents[0]; if ( child->ref_count > 1 || - child->child_count != 2 || + child->children.size != 2 || child->symbol != tree->symbol ) break; - Tree *grandchild = child->children[0]; + Tree *grandchild = child->children.contents[0]; if ( grandchild->ref_count > 1 || - grandchild->child_count != 2 || + grandchild->children.size != 2 || grandchild->symbol != tree->symbol ) break; - tree->children[0] = grandchild; + tree->children.contents[0] = grandchild; grandchild->context.parent = tree; grandchild->context.index = -1; - child->children[0] = grandchild->children[1]; - child->children[0]->context.parent = child; - child->children[0]->context.index = -1; + child->children.contents[0] = grandchild->children.contents[1]; + child->children.contents[0]->context.parent = child; + child->children.contents[0]->context.index = -1; - grandchild->children[1] = child; - grandchild->children[1]->context.parent = grandchild; - grandchild->children[1]->context.index = -1; + grandchild->children.contents[1] = child; + grandchild->children.contents[1]->context.parent = grandchild; + grandchild->children.contents[1]->context.index = -1; tree = grandchild; } while (tree != self) { tree = tree->context.parent; - Tree *child = tree->children[0]; - Tree *grandchild = child->children[1]; - ts_tree_set_children(grandchild, 2, grandchild->children, language); - ts_tree_set_children(child, 2, child->children, language); - ts_tree_set_children(tree, 2, tree->children, language); + Tree *child = tree->children.contents[0]; + Tree *grandchild = child->children.contents[1]; + ts_tree_set_children(grandchild, &grandchild->children, language); + ts_tree_set_children(child, &child->children, language); + ts_tree_set_children(tree, &tree->children, language); } } void ts_tree__balance(Tree *self, const TSLanguage *language) { - if (self->children[0]->repeat_depth > self->children[1]->repeat_depth) { - unsigned n = self->children[0]->repeat_depth - self->children[1]->repeat_depth; + if (self->children.contents[0]->repeat_depth > self->children.contents[1]->repeat_depth) { + unsigned n = self->children.contents[0]->repeat_depth - self->children.contents[1]->repeat_depth; for (unsigned i = n / 2; i > 0; i /= 2) { ts_tree__compress(self, i, language); n -= i; @@ -273,8 +271,8 @@ void ts_tree_assign_parents(Tree *self, TreePool *pool, const TSLanguage *langua const TSSymbol *alias_sequence = ts_language_alias_sequence(language, tree->alias_sequence_id); uint32_t non_extra_index = 0; bool earlier_child_was_changed = false; - for (uint32_t i = 0; i < tree->child_count; i++) { - Tree *child = tree->children[i]; + for (uint32_t i = 0; i < tree->children.size; i++) { + Tree *child = tree->children.contents[i]; if (earlier_child_was_changed || child->context.parent != tree || child->context.index != i) { earlier_child_was_changed = true; child->context.parent = tree; @@ -296,12 +294,12 @@ void ts_tree_assign_parents(Tree *self, TreePool *pool, const TSLanguage *langua } } -void ts_tree_set_children(Tree *self, uint32_t child_count, Tree **children, - const TSLanguage *language) { - if (self->child_count > 0 && children != self->children) ts_free(self->children); +void ts_tree_set_children(Tree *self, TreeArray *children, const TSLanguage *language) { + if (self->children.size > 0 && children->contents != self->children.contents) { + array_delete(&self->children); + } - self->children = children; - self->child_count = child_count; + self->children = *children; self->named_child_count = 0; self->visible_child_count = 0; self->error_cost = 0; @@ -313,8 +311,8 @@ void ts_tree_set_children(Tree *self, uint32_t child_count, Tree **children, uint32_t non_extra_index = 0; const TSSymbol *alias_sequence = ts_language_alias_sequence(language, self->alias_sequence_id); - for (uint32_t i = 0; i < child_count; i++) { - Tree *child = children[i]; + for (uint32_t i = 0; i < self->children.size; i++) { + Tree *child = self->children.contents[i]; if (i == 0) { self->padding = child->padding; @@ -338,7 +336,7 @@ void ts_tree_set_children(Tree *self, uint32_t child_count, Tree **children, } else if (child->visible) { self->visible_child_count++; if (child->named) self->named_child_count++; - } else if (child->child_count > 0) { + } else if (child->children.size > 0) { self->visible_child_count += child->visible_child_count; self->named_child_count += child->named_child_count; } @@ -357,62 +355,55 @@ void ts_tree_set_children(Tree *self, uint32_t child_count, Tree **children, self->error_cost += ERROR_COST_PER_RECOVERY + ERROR_COST_PER_SKIPPED_CHAR * self->size.bytes + ERROR_COST_PER_SKIPPED_LINE * self->size.extent.row; - for (uint32_t i = 0; i < child_count; i++) { - if (!self->children[i]->extra) { + for (uint32_t i = 0; i < self->children.size; i++) { + if (!self->children.contents[i]->extra) { self->error_cost += ERROR_COST_PER_SKIPPED_TREE; } } } - if (child_count > 0) { - self->first_leaf = children[0]->first_leaf; - if (children[0]->fragile_left) { - self->fragile_left = true; - } - if (children[child_count - 1]->fragile_right) { - self->fragile_right = true; - } + if (self->children.size > 0) { + Tree *first_child = self->children.contents[0]; + Tree *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; if ( - self->child_count == 2 && + self->children.size == 2 && !self->visible && !self->named && - self->children[0]->symbol == self->symbol && - self->children[1]->symbol == self->symbol + first_child->symbol == self->symbol && + last_child->symbol == self->symbol ) { - if (self->children[0]->repeat_depth > self->children[1]->repeat_depth) { - self->repeat_depth = self->children[0]->repeat_depth + 1; + if (first_child->repeat_depth > last_child->repeat_depth) { + self->repeat_depth = first_child->repeat_depth + 1; } else { - self->repeat_depth = self->children[1]->repeat_depth + 1; + self->repeat_depth = last_child->repeat_depth + 1; } } } } -Tree *ts_tree_make_node(TreePool *pool, TSSymbol symbol, uint32_t child_count, Tree **children, +Tree *ts_tree_make_node(TreePool *pool, TSSymbol symbol, TreeArray *children, unsigned alias_sequence_id, const TSLanguage *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); + ts_tree_set_children(result, children, language); return result; } 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) { - array_splice(children, i, 1, child->child_count, child->children); - i += child->child_count - 1; - for (uint32_t j = 0; j < child->child_count; j++) - ts_tree_retain(child->children[j]); + if (child->symbol == ts_builtin_sym_error && child->children.size > 0) { + array_splice(children, i, 1, child->children.size, child->children.contents); + i += child->children.size - 1; + for (uint32_t j = 0; j < child->children.size; j++) + ts_tree_retain(child->children.contents[j]); ts_tree_release(pool, child); } } - Tree *result = ts_tree_make_node( - pool, ts_builtin_sym_error, - children->size, children->contents, - 0, language - ); - + Tree *result = ts_tree_make_node(pool, ts_builtin_sym_error, children, 0, language); result->fragile_left = true; result->fragile_right = true; return result; @@ -439,11 +430,11 @@ void ts_tree_release(TreePool *pool, Tree *self) { 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]); + if (tree->children.size > 0) { + for (uint32_t i = 0; i < tree->children.size; i++) { + array_push(&pool->tree_stack, tree->children.contents[i]); } - ts_free(tree->children); + array_delete(&tree->children); } else if (tree->has_external_tokens) { ts_external_token_state_delete(&tree->external_token_state); } @@ -484,12 +475,12 @@ bool ts_tree_eq(const Tree *self, const Tree *other) { if (self->padding.bytes != other->padding.bytes) return false; if (self->size.bytes != other->size.bytes) return false; if (self->symbol == ts_builtin_sym_error) return self->lookahead_char == other->lookahead_char; - if (self->child_count != other->child_count) return false; + if (self->children.size != other->children.size) return false; if (self->visible_child_count != other->visible_child_count) return false; if (self->named_child_count != other->named_child_count) return false; - for (uint32_t i = 0; i < self->child_count; i++) { - if (!ts_tree_eq(self->children[i], other->children[i])) { + for (uint32_t i = 0; i < self->children.size; i++) { + if (!ts_tree_eq(self->children.contents[i], other->children.contents[i])) { return false; } } @@ -501,13 +492,13 @@ int ts_tree_compare(const Tree *left, const Tree *right) { return -1; if (right->symbol < left->symbol) return 1; - if (left->child_count < right->child_count) + if (left->children.size < right->children.size) return -1; - if (right->child_count < left->child_count) + if (right->children.size < left->children.size) return 1; - for (uint32_t i = 0; i < left->child_count; i++) { - Tree *left_child = left->children[i]; - Tree *right_child = right->children[i]; + for (uint32_t i = 0; i < left->children.size; i++) { + Tree *left_child = left->children.contents[i]; + Tree *right_child = right->children.contents[i]; switch (ts_tree_compare(left_child, right_child)) { case -1: return -1; @@ -527,10 +518,10 @@ static inline long min_byte(long a, long b) { bool ts_tree_invalidate_lookahead(Tree *self, uint32_t edit_byte_offset) { if (edit_byte_offset >= self->bytes_scanned) return false; self->has_changes = true; - if (self->child_count > 0) { + if (self->children.size > 0) { uint32_t child_start_byte = 0; - for (uint32_t i = 0; i < self->child_count; i++) { - Tree *child = self->children[i]; + for (uint32_t i = 0; i < self->children.size; i++) { + Tree *child = self->children.contents[i]; if (child_start_byte > edit_byte_offset) break; ts_tree_invalidate_lookahead(child, edit_byte_offset - child_start_byte); child_start_byte += ts_tree_total_bytes(child); @@ -581,8 +572,8 @@ void ts_tree_edit(Tree *self, const TSInputEdit *edit) { long remaining_bytes_to_delete = 0; TSPoint remaining_extent_to_delete = {0, 0}; Length child_left, child_right = length_zero(); - for (uint32_t i = 0; i < self->child_count; i++) { - Tree *child = self->children[i]; + for (uint32_t i = 0; i < self->children.size; i++) { + Tree *child = self->children.contents[i]; child_left = child_right; child_right = length_add(child_left, ts_tree_total_size(child)); @@ -628,9 +619,9 @@ void ts_tree_edit(Tree *self, const TSInputEdit *edit) { Tree *ts_tree_last_external_token(Tree *tree) { if (!tree->has_external_tokens) return NULL; - while (tree->child_count > 0) { - for (uint32_t i = tree->child_count - 1; i + 1 > 0; i--) { - Tree *child = tree->children[i]; + while (tree->children.size > 0) { + for (uint32_t i = tree->children.size - 1; i + 1 > 0; i--) { + Tree *child = tree->children.contents[i]; if (child->has_external_tokens) { tree = child; break; @@ -676,7 +667,7 @@ static size_t ts_tree__write_to_string(const Tree *self, const TSLanguage *langu } if (visible) { - if (self->symbol == ts_builtin_sym_error && self->child_count == 0 && self->size.bytes > 0) { + if (self->symbol == ts_builtin_sym_error && self->children.size == 0 && self->size.bytes > 0) { cursor += snprintf(*writer, limit, "(UNEXPECTED "); cursor += ts_tree__write_char_to_string(*writer, limit, self->lookahead_char); } else if (self->is_missing) { @@ -688,8 +679,8 @@ static size_t ts_tree__write_to_string(const Tree *self, const TSLanguage *langu } } - for (uint32_t i = 0; i < self->child_count; i++) { - Tree *child = self->children[i]; + for (uint32_t i = 0; i < self->children.size; i++) { + Tree *child = self->children.contents[i]; cursor += ts_tree__write_to_string(child, language, *writer, limit, false, include_all); } @@ -711,7 +702,7 @@ void ts_tree__print_dot_graph(const Tree *self, uint32_t byte_offset, TSSymbol symbol = self->context.alias_symbol ? self->context.alias_symbol : self->symbol; fprintf(f, "tree_%p [label=\"%s\"", self, ts_language_symbol_name(language, symbol)); - if (self->child_count == 0) + if (self->children.size == 0) fprintf(f, ", shape=plaintext"); if (self->extra) fprintf(f, ", fontcolor=gray"); @@ -719,8 +710,8 @@ void ts_tree__print_dot_graph(const Tree *self, uint32_t byte_offset, fprintf(f, ", tooltip=\"address:%p\nrange:%u - %u\nstate:%d\nerror-cost:%u\nrepeat-depth:%u\"]\n", self, byte_offset, byte_offset + ts_tree_total_bytes(self), self->parse_state, self->error_cost, self->repeat_depth); - for (uint32_t i = 0; i < self->child_count; i++) { - const Tree *child = self->children[i]; + for (uint32_t i = 0; i < self->children.size; i++) { + const Tree *child = self->children.contents[i]; ts_tree__print_dot_graph(child, byte_offset, language, f); fprintf(f, "tree_%p -> tree_%p [tooltip=%u]\n", self, child, i); byte_offset += ts_tree_total_bytes(child); diff --git a/src/runtime/tree.h b/src/runtime/tree.h index ad104894..09dae3dd 100644 --- a/src/runtime/tree.h +++ b/src/runtime/tree.h @@ -17,12 +17,16 @@ extern TSStateId TS_TREE_STATE_NONE; typedef struct { union { char *long_data; - char short_data[sizeof(char *) + sizeof(unsigned)]; + char short_data[sizeof(char *) + sizeof(uint32_t)]; }; - unsigned length; + uint32_t length; } TSExternalTokenState; -typedef struct Tree { +typedef struct Tree Tree; + +typedef Array(Tree *) TreeArray; + +struct Tree { struct { struct Tree *parent; uint32_t index; @@ -31,35 +35,16 @@ typedef struct Tree { bool alias_is_named : 1; } context; - uint32_t child_count; - union { - struct { - struct Tree **children; - uint32_t visible_child_count; - uint32_t named_child_count; - unsigned short alias_sequence_id; - }; - TSExternalTokenState external_token_state; - int32_t lookahead_char; - }; - Length padding; Length size; - uint32_t bytes_scanned; - - TSSymbol symbol; - TSStateId parse_state; - unsigned error_cost; - unsigned node_count; - unsigned repeat_depth; - - struct { - TSSymbol symbol; - TSLexMode lex_mode; - } first_leaf; - uint32_t ref_count; - int dynamic_precedence; + uint32_t bytes_scanned; + uint32_t error_cost; + uint32_t node_count; + uint32_t repeat_depth; + uint32_t child_count; + int32_t dynamic_precedence; + bool visible : 1; bool named : 1; bool extra : 1; @@ -68,9 +53,30 @@ typedef struct Tree { bool has_changes : 1; bool has_external_tokens : 1; bool is_missing : 1; -} Tree; + TSSymbol symbol; + TSStateId parse_state; + struct { + TSSymbol symbol; + TSLexMode lex_mode; + } first_leaf; -typedef Array(Tree *) TreeArray; + union { + struct { + TreeArray children; + uint32_t visible_child_count; + uint32_t named_child_count; + uint16_t alias_sequence_id; + }; + struct { + uint32_t _2; + TSExternalTokenState external_token_state; + }; + struct { + uint32_t _1; + int32_t lookahead_char; + }; + }; +}; typedef struct { TreeArray free_trees; @@ -93,7 +99,7 @@ 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_node(TreePool *, TSSymbol, TreeArray *, 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 *); @@ -104,7 +110,7 @@ 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_set_children(Tree *, TreeArray *, 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); diff --git a/test/helpers/tree_helpers.cc b/test/helpers/tree_helpers.cc index abd6bc10..5142ca8d 100644 --- a/test/helpers/tree_helpers.cc +++ b/test/helpers/tree_helpers.cc @@ -16,11 +16,14 @@ const char *symbol_names[24] = { "twenty-two", "twenty-three" }; -Tree ** tree_array(std::vector trees) { - Tree ** result = (Tree **)calloc(trees.size(), sizeof(Tree *)); +TreeArray *tree_array(std::vector trees) { + static TreeArray result; + result.capacity = trees.size(); + result.size = trees.size(); + result.contents = (Tree **)calloc(trees.size(), sizeof(Tree *)); for (size_t i = 0; i < trees.size(); i++) - result[i] = trees[i]; - return result; + result.contents[i] = trees[i]; + return &result; } ostream &operator<<(std::ostream &stream, const Tree *tree) { diff --git a/test/helpers/tree_helpers.h b/test/helpers/tree_helpers.h index 19ae2c70..c28dcd98 100644 --- a/test/helpers/tree_helpers.h +++ b/test/helpers/tree_helpers.h @@ -6,7 +6,7 @@ #include extern const char *symbol_names[24]; -Tree ** tree_array(std::vector trees); +TreeArray *tree_array(std::vector trees); std::ostream &operator<<(std::ostream &stream, const Tree *tree); std::ostream &operator<<(std::ostream &stream, const TSNode &node); diff --git a/test/runtime/tree_test.cc b/test/runtime/tree_test.cc index 96f485f7..8669b6c1 100644 --- a/test/runtime/tree_test.cc +++ b/test/runtime/tree_test.cc @@ -7,11 +7,11 @@ void assert_consistent(const Tree *tree) { if (tree->child_count == 0) return; - AssertThat(tree->children[0]->padding, Equals(tree->padding)); + AssertThat(tree->children.contents[0]->padding, Equals(tree->padding)); Length total_children_size = length_zero(); - for (size_t i = 0; i < tree->child_count; i++) { - Tree *child = tree->children[i]; + for (size_t i = 0; i < tree->children.size; i++) { + Tree *child = tree->children.contents[i]; AssertThat(child->context.offset, Equals(total_children_size)); assert_consistent(child); total_children_size = length_add(total_children_size, ts_tree_total_size(child)); @@ -86,7 +86,7 @@ describe("Tree", []() { ts_tree_retain(tree1); ts_tree_retain(tree2); - parent1 = ts_tree_make_node(&pool, symbol3, 2, tree_array({ + parent1 = ts_tree_make_node(&pool, symbol3, tree_array({ tree1, tree2, }), 0, &language); @@ -114,7 +114,7 @@ describe("Tree", []() { ts_tree_retain(tree1); ts_tree_retain(tree2); - parent = ts_tree_make_node(&pool, symbol3, 2, tree_array({ + parent = ts_tree_make_node(&pool, symbol3, tree_array({ tree1, tree2, }), 0, &language); @@ -138,7 +138,7 @@ describe("Tree", []() { ts_tree_retain(tree1); ts_tree_retain(tree2); - parent = ts_tree_make_node(&pool, symbol3, 2, tree_array({ + parent = ts_tree_make_node(&pool, symbol3, tree_array({ tree1, tree2, }), 0, &language); @@ -162,7 +162,7 @@ describe("Tree", []() { ts_tree_retain(tree1); ts_tree_retain(tree2); - parent = ts_tree_make_node(&pool, symbol3, 2, tree_array({ + parent = ts_tree_make_node(&pool, symbol3, tree_array({ tree1, tree2, }), 0, &language); @@ -183,7 +183,7 @@ describe("Tree", []() { Tree *tree = nullptr; before_each([&]() { - tree = ts_tree_make_node(&pool, symbol1, 3, tree_array({ + tree = ts_tree_make_node(&pool, symbol1, 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), @@ -213,13 +213,13 @@ describe("Tree", []() { AssertThat(tree->padding, Equals({3, {0, 3}})); AssertThat(tree->size, Equals({13, {0, 13}})); - AssertThat(tree->children[0]->has_changes, IsTrue()); - AssertThat(tree->children[0]->padding, Equals({3, {0, 3}})); - AssertThat(tree->children[0]->size, Equals({3, {0, 3}})); + AssertThat(tree->children.contents[0]->has_changes, IsTrue()); + AssertThat(tree->children.contents[0]->padding, Equals({3, {0, 3}})); + AssertThat(tree->children.contents[0]->size, Equals({3, {0, 3}})); - AssertThat(tree->children[1]->has_changes, IsFalse()); - AssertThat(tree->children[1]->padding, Equals({2, {0, 2}})); - AssertThat(tree->children[1]->size, Equals({3, {0, 3}})); + AssertThat(tree->children.contents[1]->has_changes, IsFalse()); + AssertThat(tree->children.contents[1]->padding, Equals({2, {0, 2}})); + AssertThat(tree->children.contents[1]->size, Equals({3, {0, 3}})); }); }); @@ -239,9 +239,9 @@ describe("Tree", []() { AssertThat(tree->padding, Equals({5, {0, 5}})); AssertThat(tree->size, Equals({11, {0, 11}})); - AssertThat(tree->children[0]->has_changes, IsTrue()); - AssertThat(tree->children[0]->padding, Equals({5, {0, 5}})); - AssertThat(tree->children[0]->size, Equals({1, {0, 1}})); + AssertThat(tree->children.contents[0]->has_changes, IsTrue()); + AssertThat(tree->children.contents[0]->padding, Equals({5, {0, 5}})); + AssertThat(tree->children.contents[0]->size, Equals({1, {0, 1}})); }); }); @@ -263,11 +263,11 @@ describe("Tree", []() { AssertThat(tree->padding, Equals({4, {0, 4}})); AssertThat(tree->size, Equals({13, {0, 13}})); - AssertThat(tree->children[0]->has_changes, IsTrue()); - AssertThat(tree->children[0]->padding, Equals({4, {0, 4}})); - AssertThat(tree->children[0]->size, Equals({3, {0, 3}})); + AssertThat(tree->children.contents[0]->has_changes, IsTrue()); + AssertThat(tree->children.contents[0]->padding, Equals({4, {0, 4}})); + AssertThat(tree->children.contents[0]->size, Equals({3, {0, 3}})); - AssertThat(tree->children[1]->has_changes, IsFalse()); + AssertThat(tree->children.contents[1]->has_changes, IsFalse()); }); }); @@ -287,11 +287,11 @@ describe("Tree", []() { AssertThat(tree->padding, Equals({2, {0, 2}})); AssertThat(tree->size, Equals({16, {0, 16}})); - AssertThat(tree->children[0]->has_changes, IsTrue()); - AssertThat(tree->children[0]->padding, Equals({2, {0, 2}})); - AssertThat(tree->children[0]->size, Equals({6, {0, 6}})); + AssertThat(tree->children.contents[0]->has_changes, IsTrue()); + AssertThat(tree->children.contents[0]->padding, Equals({2, {0, 2}})); + AssertThat(tree->children.contents[0]->size, Equals({6, {0, 6}})); - AssertThat(tree->children[1]->has_changes, IsFalse()); + AssertThat(tree->children.contents[1]->has_changes, IsFalse()); }); }); @@ -313,23 +313,23 @@ describe("Tree", []() { AssertThat(tree->padding, Equals({4, {0, 4}})); AssertThat(tree->size, Equals({4, {0, 4}})); - AssertThat(tree->children[0]->has_changes, IsTrue()); - AssertThat(tree->children[0]->padding, Equals({4, {0, 4}})); - AssertThat(tree->children[0]->size, Equals({0, {0, 0}})); + AssertThat(tree->children.contents[0]->has_changes, IsTrue()); + AssertThat(tree->children.contents[0]->padding, Equals({4, {0, 4}})); + AssertThat(tree->children.contents[0]->size, Equals({0, {0, 0}})); - AssertThat(tree->children[1]->has_changes, IsTrue()); - AssertThat(tree->children[1]->padding, Equals({0, {0, 0}})); - AssertThat(tree->children[1]->size, Equals({0, {0, 0}})); + AssertThat(tree->children.contents[1]->has_changes, IsTrue()); + AssertThat(tree->children.contents[1]->padding, Equals({0, {0, 0}})); + AssertThat(tree->children.contents[1]->size, Equals({0, {0, 0}})); - AssertThat(tree->children[2]->has_changes, IsTrue()); - AssertThat(tree->children[2]->padding, Equals({1, {0, 1}})); - AssertThat(tree->children[2]->size, Equals({3, {0, 3}})); + AssertThat(tree->children.contents[2]->has_changes, IsTrue()); + AssertThat(tree->children.contents[2]->padding, Equals({1, {0, 1}})); + AssertThat(tree->children.contents[2]->size, Equals({3, {0, 3}})); }); }); describe("edits within a tree's range of scanned bytes", [&]() { it("marks preceding trees as changed", [&]() { - tree->children[0]->bytes_scanned = 7; + tree->children.contents[0]->bytes_scanned = 7; TSInputEdit edit; edit.start_byte = 6; @@ -341,7 +341,7 @@ describe("Tree", []() { ts_tree_edit(tree, &edit); assert_consistent(tree); - AssertThat(tree->children[0]->has_changes, IsTrue()); + AssertThat(tree->children.contents[0]->has_changes, IsTrue()); }); }); }); @@ -361,14 +361,14 @@ describe("Tree", []() { 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(&pool, symbol2, 2, tree_array({ + Tree *parent = ts_tree_make_node(&pool, symbol2, tree_array({ leaf, leaf_copy, }), 0, &language); ts_tree_retain(leaf); ts_tree_retain(leaf_copy); - Tree *parent_copy = ts_tree_make_node(&pool, symbol2, 2, tree_array({ + Tree *parent_copy = ts_tree_make_node(&pool, symbol2, tree_array({ leaf, leaf_copy, }), 0, &language); @@ -415,14 +415,14 @@ describe("Tree", []() { it("returns false for trees with different children", [&]() { Tree *leaf2 = ts_tree_make_leaf(&pool, symbol2, {1, {0, 1}}, {3, {0, 3}}, &language); - Tree *parent = ts_tree_make_node(&pool, symbol2, 2, tree_array({ + Tree *parent = ts_tree_make_node(&pool, symbol2, tree_array({ leaf, leaf2, }), 0, &language); ts_tree_retain(leaf); ts_tree_retain(leaf2); - Tree *different_parent = ts_tree_make_node(&pool, symbol2, 2, tree_array({ + Tree *different_parent = ts_tree_make_node(&pool, symbol2, tree_array({ leaf2, leaf, }), 0, &language); @@ -450,14 +450,14 @@ 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(&pool, symbol1, 2, tree_array({ - (tree2 = ts_tree_make_node(&pool, symbol2, 3, tree_array({ + tree1 = ts_tree_make_node(&pool, symbol1, tree_array({ + (tree2 = ts_tree_make_node(&pool, symbol2, 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(&pool, symbol6, 2, tree_array({ - (tree7 = ts_tree_make_node(&pool, symbol7, 1, tree_array({ + (tree6 = ts_tree_make_node(&pool, symbol6, tree_array({ + (tree7 = ts_tree_make_node(&pool, symbol7, tree_array({ (tree8 = ts_tree_make_leaf(&pool, symbol8, padding, size, &language)), }), 0, &language)), (tree9 = ts_tree_make_leaf(&pool, symbol9, padding, size, &language)),