diff --git a/spec/runtime/node_spec.cc b/spec/runtime/node_spec.cc index 110cf134..1aef5e8e 100644 --- a/spec/runtime/node_spec.cc +++ b/spec/runtime/node_spec.cc @@ -54,23 +54,11 @@ describe("Node", []() { AssertThat(ts_node_pos(child3).bytes, Equals(15)); AssertThat(ts_node_size(child3).bytes, Equals(11)); - }); - }); - describe("parent()", [&]() { - it("returns the node's parent node", [&]() { - TSNode array = ts_node_child(root, 0); - TSNode child1 = ts_node_child(array, 0); - TSNode child2 = ts_node_child(array, 1); - TSNode child3 = ts_node_child(array, 2); - - AssertThat(ts_node_parent(child1), Equals(array)); - AssertThat(ts_node_parent(child2), Equals(array)); - AssertThat(ts_node_parent(child3), Equals(array)); - AssertThat(ts_node_parent(array), Equals(root)); - }); - - it("returns null if the node has no parent", [&]() { + AssertThat(ts_node_parent(child1), Equals(parent)); + AssertThat(ts_node_parent(child2), Equals(parent)); + AssertThat(ts_node_parent(child3), Equals(parent)); + AssertThat(ts_node_parent(parent), Equals(root)); AssertThat(ts_node_parent(root).data, Equals(nullptr)); }); }); diff --git a/spec/runtime/tree_spec.cc b/spec/runtime/tree_spec.cc index 485352bc..186e4608 100644 --- a/spec/runtime/tree_spec.cc +++ b/spec/runtime/tree_spec.cc @@ -80,58 +80,6 @@ describe("Tree", []() { AssertThat(parent1->padding.chars, Equals(tree1->padding.chars)); }); - it("computes the offset of each child node", [&]() { - size_t count; - TSTreeChild *children = ts_tree_visible_children(parent1, &count); - - AssertThat(count, Equals(2)); - - AssertThat(children[0].tree, Equals(tree1)); - AssertThat(children[0].offset.bytes, Equals(0)); - AssertThat(children[0].offset.chars, Equals(0)); - - AssertThat(children[1].tree, Equals(tree2)); - AssertThat(children[1].offset, Equals(ts_tree_total_size(tree1))); - }); - - describe("when one of the child nodes is hidden", [&]() { - TSTree *grandparent, *tree3; - - before_each([&]() { - parent1->options = TSTreeOptionsHidden; - tree3 = ts_tree_make_leaf( - cat, - ts_length_make(8, 6), - ts_length_make(5, 3), - 0); - grandparent = ts_tree_make_node(pig, 2, tree_array({ - parent1, - tree3, - }), 0); - }); - - after_each([&]() { - ts_tree_release(tree3); - ts_tree_release(grandparent); - }); - - it("claims the hidden node's children as its own", [&]() { - size_t count; - TSTreeChild *children = ts_tree_visible_children(grandparent, &count); - - AssertThat(count, Equals(3)); - AssertThat(children[0].tree, Equals(tree1)); - AssertThat(children[0].offset.bytes, Equals(0)); - AssertThat(children[0].offset.chars, Equals(0)); - - AssertThat(children[1].tree, Equals(tree2)); - AssertThat(children[1].offset, Equals(ts_tree_total_size(tree1))); - - AssertThat(children[2].tree, Equals(tree3)); - AssertThat(children[2].offset, Equals(ts_length_add(ts_tree_total_size(tree1), ts_tree_total_size(tree2)))); - }); - }); - describe("when the first node is fragile on the left side", [&]() { TSTree *parent; diff --git a/src/runtime/node.c b/src/runtime/node.c index 6c38392d..fc371a81 100644 --- a/src/runtime/node.c +++ b/src/runtime/node.c @@ -39,10 +39,10 @@ typedef struct { } NodeWithIndex; static inline NodeWithIndex ts_node_parent_with_index(TSNode this) { - const TSTree *tree = get_tree(this); - size_t index = 0; TSLength position = this.position; + const TSTree *tree = get_tree(this); + size_t index = 0; do { TSTree *parent = tree->parent; if (!parent) @@ -52,15 +52,10 @@ static inline NodeWithIndex ts_node_parent_with_index(TSNode this) { TSTree *child = parent->children[i]; if (child == tree) break; - if (ts_tree_is_visible(child)) { - index += 1; - } else { - size_t child_count; - ts_tree_visible_children(child, &child_count); - index += child_count; - } + index += ts_tree_is_visible(child) ? 1 : child->visible_child_count; position = ts_length_sub(position, ts_tree_total_size(child)); } + tree = parent; } while (!ts_tree_is_visible(tree)); @@ -88,18 +83,30 @@ TSNode ts_node_next_sibling(TSNode this) { } size_t ts_node_child_count(TSNode this) { - size_t result; - ts_tree_visible_children(get_tree(this), &result); - return result; + return get_tree(this)->visible_child_count; } -TSNode ts_node_child(TSNode this, size_t i) { - size_t count; - TSTreeChild *children = ts_tree_visible_children(get_tree(this), &count); - if (i >= count) - return ts_node_null(); - TSLength position = ts_length_add(this.position, children[i].offset); - return ts_node_make(children[i].tree, position); +TSNode ts_node_child(TSNode this, size_t child_index) { + TSLength position = this.position; + const TSTree *tree = get_tree(this); + + size_t index = 0; + for (size_t i = 0; i < tree->child_count; i++) { + TSTree *child = tree->children[i]; + if (ts_tree_is_visible(child)) { + if (index == child_index) + return ts_node_make(child, position); + index++; + } else { + size_t index_within = child_index - index; + if (index_within < child->visible_child_count) + return ts_node_child(ts_node_make(child, position), index_within); + index += child->visible_child_count; + } + position = ts_length_add(position, ts_tree_total_size(child)); + } + + return ts_node_null(); } TSNode ts_node_find_for_range(TSNode this, size_t min, size_t max) { @@ -107,18 +114,17 @@ TSNode ts_node_find_for_range(TSNode this, size_t min, size_t max) { bool did_descend = true; while (did_descend) { did_descend = false; - size_t count; - TSTreeChild *children = ts_tree_visible_children(get_tree(node), &count); - - for (size_t i = 0; i < count; i++) { - TSTreeChild child = children[i]; - TSLength position = ts_length_add(node.position, child.offset); - if (position.chars > min) + const TSTree *tree = get_tree(node); + TSLength position = node.position; + for (size_t i = 0; i < tree->child_count; i++) { + const TSTree *child = tree->children[i]; + if (position.chars + child->padding.chars > min) break; - if (position.chars + child.tree->size.chars > max) { - node = ts_node_make(child.tree, position); + if (position.chars + child->padding.chars + child->size.chars > max) { + node = ts_node_make(child, position); did_descend = true; } + position = ts_length_add(position, ts_tree_total_size(child)); } } return node; diff --git a/src/runtime/parser.c b/src/runtime/parser.c index 60668f80..c7c62030 100644 --- a/src/runtime/parser.c +++ b/src/runtime/parser.c @@ -60,8 +60,11 @@ static TSLength break_down_left_stack(TSParser *parser, TSInputEdit edit) { break; TSTree *node = entry->tree; - size_t child_count; - TSTree **children = ts_tree_children(node, &child_count); + size_t child_count = node->child_count; + TSTree **children = node->children; + if (node->symbol == ts_builtin_sym_error) + child_count = 0; + if (left_subtree_end.chars < edit.position && !children && node->symbol != ts_builtin_sym_error) break; @@ -129,8 +132,8 @@ static TSTree *break_down_right_stack(TSParser *parser) { return node; } - size_t child_count; - TSTree **children = ts_tree_children(node, &child_count); + size_t child_count = node->child_count; + TSTree **children = node->children; DEBUG("pop_right sym:%s", SYM_NAME(node->symbol)); stack->size--; diff --git a/src/runtime/tree.c b/src/runtime/tree.c index ba71021b..7214b5d7 100644 --- a/src/runtime/tree.c +++ b/src/runtime/tree.c @@ -31,6 +31,7 @@ TSTree *ts_tree_make_error(TSLength size, TSLength padding, char lookahead_char) TSTree *ts_tree_make_node(TSSymbol symbol, size_t child_count, TSTree **children, bool is_hidden) { + TSTree *result = malloc(sizeof(TSTree)); /* * Determine the new node's size, padding and visible child count based on @@ -41,6 +42,7 @@ TSTree *ts_tree_make_node(TSSymbol symbol, size_t child_count, for (size_t i = 0; i < child_count; i++) { TSTree *child = children[i]; ts_tree_retain(child); + child->parent = result; if (i == 0) { padding = child->padding; @@ -75,12 +77,6 @@ TSTree *ts_tree_make_node(TSSymbol symbol, size_t child_count, } } - /* - * Store the visible child array adjacent to the tree itself. This avoids - * performing a second allocation and storing an additional pointer. - */ - TSTree *result = - malloc(sizeof(TSTree) + (visible_child_count * sizeof(TSTreeChild))); *result = (TSTree){.ref_count = 1, .parent = NULL, .symbol = symbol, @@ -90,35 +86,6 @@ TSTree *ts_tree_make_node(TSSymbol symbol, size_t child_count, .size = size, .padding = padding, .options = options }; - - /* - * Associate a relative offset with each of the visible child nodes, so that - * their positions can be queried without using the hidden child nodes. - */ - TSTreeChild *visible_children = ts_tree_visible_children(result, NULL); - TSLength offset = ts_length_zero(); - for (size_t i = 0, vis_i = 0; i < child_count; i++) { - TSTree *child = children[i]; - child->parent = result; - - if (ts_tree_is_visible(child)) { - visible_children[vis_i].tree = child; - visible_children[vis_i].offset = offset; - vis_i++; - } else { - size_t n = 0; - TSTreeChild *grandchildren = ts_tree_visible_children(child, &n); - for (size_t j = 0; j < n; j++) { - visible_children[vis_i].tree = grandchildren[j].tree; - visible_children[vis_i].offset = - ts_length_add(offset, grandchildren[j].offset); - vis_i++; - } - } - - offset = ts_length_add(offset, ts_tree_total_size(child)); - } - return result; } @@ -131,13 +98,10 @@ void ts_tree_release(TSTree *tree) { assert(tree->ref_count > 0); tree->ref_count--; if (tree->ref_count == 0) { - size_t count; - TSTree **children = ts_tree_children(tree, &count); - if (children) { - for (size_t i = 0; i < count; i++) - ts_tree_release(children[i]); + for (size_t i = 0; i < tree->child_count; i++) + ts_tree_release(tree->children[i]); + if (tree->child_count > 0) free(tree->children); - } free(tree); } } @@ -168,30 +132,6 @@ bool ts_tree_eq(const TSTree *node1, const TSTree *node2) { return true; } -TSTree **ts_tree_children(const TSTree *tree, size_t *count) { - if (tree->symbol == ts_builtin_sym_error) { - if (count) - *count = 0; - return NULL; - } else { - if (count) - *count = tree->child_count; - return tree->children; - } -} - -TSTreeChild *ts_tree_visible_children(const TSTree *tree, size_t *count) { - if (tree->child_count == 0) { - if (count) - *count = 0; - return NULL; - } else { - if (count) - *count = tree->visible_child_count; - return (TSTreeChild *)(tree + 1); - } -} - static size_t write_lookahead_to_string(char *string, size_t limit, char lookahead) { switch (lookahead) { diff --git a/src/runtime/tree.h b/src/runtime/tree.h index b66ad9b9..d107f5e7 100644 --- a/src/runtime/tree.h +++ b/src/runtime/tree.h @@ -19,11 +19,9 @@ typedef enum { struct TSTree { struct TSTree *parent; size_t child_count; + size_t visible_child_count; union { - struct { - struct TSTree **children; - size_t visible_child_count; - }; + struct TSTree **children; char lookahead_char; }; TSLength padding; @@ -82,8 +80,6 @@ void ts_tree_release(TSTree *tree); bool ts_tree_eq(const TSTree *tree1, const TSTree *tree2); char *ts_tree_string(const TSTree *tree, const char **names); char *ts_tree_error_string(const TSTree *tree, const char **names); -TSTree **ts_tree_children(const TSTree *tree, size_t *count); -TSTreeChild *ts_tree_visible_children(const TSTree *tree, size_t *count); TSLength ts_tree_total_size(const TSTree *tree); static inline bool ts_tree_is_empty(TSTree *tree) {