From 3430a5edcc0dfdf5e96e0950bcd821bb36638312 Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Thu, 28 Aug 2014 13:22:06 -0700 Subject: [PATCH] Clarify distinction btwn tree padding, tree offset, node position - Node position is public. It represents the node's first character index in the document. - Tree offset is private. It represents the distance between the tree's first character index and it's parent's first character index. - Tree padding is private. It represents the amount of whitespace (or other separator characters) immediately preceding the tree. --- spec/runtime/tree_spec.cc | 51 +++++++++++++++++++++-- src/runtime/lexer.c | 4 +- src/runtime/node.c | 43 ++++++++------------ src/runtime/node.h | 4 +- src/runtime/tree.c | 86 ++++++++++++++++++++++----------------- src/runtime/tree.h | 16 ++++---- 6 files changed, 126 insertions(+), 78 deletions(-) diff --git a/spec/runtime/tree_spec.cc b/spec/runtime/tree_spec.cc index 734b72d2..1956e042 100644 --- a/spec/runtime/tree_spec.cc +++ b/spec/runtime/tree_spec.cc @@ -26,13 +26,58 @@ describe("Tree", []() { ts_tree_release(parent1); }); - describe("making a parent node", [&]() { + describe("building a parent node", [&]() { it("computes its size based on its child nodes", [&]() { AssertThat(parent1->size, Equals(9)); }); - it("computes its offset based on its first child", [&]() { - AssertThat(parent1->offset, Equals(2)); + it("computes its padding based on its first child", [&]() { + AssertThat(parent1->padding, Equals(2)); + }); + + 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, Equals(0)); + AssertThat(children[1].tree, Equals(tree2)); + AssertThat(children[1].offset, Equals( + tree1->size + tree2->padding)); + }); + + describe("when one of the child nodes is hidden", [&]() { + TSTree *grandparent, *tree3; + + before_each([&]() { + parent1->options = TSTreeOptionsHidden; + tree3 = ts_tree_make_leaf(cat, 8, 5, 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, Equals(0)); + AssertThat(children[1].tree, Equals(tree2)); + AssertThat(children[1].offset, Equals( + tree1->size + tree2->padding)); + AssertThat(children[2].tree, Equals(tree3)); + AssertThat(children[2].offset, Equals( + tree1->size + tree2->padding + tree2->size + tree3->padding)); + }); }); }); diff --git a/src/runtime/lexer.c b/src/runtime/lexer.c index d69fb29b..080a86a6 100644 --- a/src/runtime/lexer.c +++ b/src/runtime/lexer.c @@ -22,9 +22,9 @@ static int advance(TSLexer *lexer) { static TSTree *accept(TSLexer *lexer, TSSymbol symbol, int is_hidden) { size_t current_position = ts_lexer_position(lexer); size_t size = current_position - lexer->token_start_position; - size_t offset = lexer->token_start_position - lexer->token_end_position; + size_t padding = lexer->token_start_position - lexer->token_end_position; lexer->token_end_position = current_position; - return ts_tree_make_leaf(symbol, size, offset, is_hidden); + return ts_tree_make_leaf(symbol, size, padding, is_hidden); } TSLexer ts_lexer_make() { diff --git a/src/runtime/node.c b/src/runtime/node.c index eac27d1f..c06bed72 100644 --- a/src/runtime/node.c +++ b/src/runtime/node.c @@ -2,7 +2,7 @@ #include "runtime/tree.h" TSNode *ts_node_make(const TSTree *tree, TSNode *parent, size_t index, - size_t start_position, const char **names) { + size_t position, const char **names) { if (parent) ts_node_retain(parent); TSNode *result = malloc(sizeof(TSNode)); @@ -10,15 +10,13 @@ TSNode *ts_node_make(const TSTree *tree, TSNode *parent, size_t index, .parent = parent, .index = index, .content = tree, - .start_position = start_position, + .position = position, .names = names, }; return result; } TSNode *ts_node_make_root(const TSTree *tree, const char **names) { - while (ts_tree_is_wrapper(tree)) - tree = tree->children[0]; - return ts_node_make(tree, NULL, 0, 0, names); + return ts_node_make(tree, NULL, 0, tree->padding, names); } void ts_node_retain(TSNode *node) { node->ref_count++; } @@ -33,7 +31,7 @@ void ts_node_release(TSNode *node) { } size_t ts_node_pos(const TSNode *node) { - return node->start_position + node->content->offset; + return node->position; } size_t ts_node_size(const TSNode *node) { return node->content->size; } @@ -72,31 +70,26 @@ size_t ts_node_child_count(const TSNode *parent) { return result; } -TSNode *ts_node_child(TSNode *parent, size_t index) { - size_t child_count; - TSChildWithPosition *children = - ts_tree_visible_children(parent->content, &child_count); - if (child_count <= index) +TSNode *ts_node_child(TSNode *parent, size_t i) { + size_t count; + TSTreeChild *children = ts_tree_visible_children(parent->content, &count); + if (i >= count) return NULL; - size_t position = parent->start_position + children[index].position; - return ts_node_make(children[index].tree, parent, index, position, - parent->names); + size_t child_pos = parent->position + children[i].offset; + return ts_node_make(children[i].tree, parent, i, child_pos, parent->names); } TSNode *ts_node_find_for_range(TSNode *parent, size_t min, size_t max) { - size_t child_count; - TSChildWithPosition *children = - ts_tree_visible_children(parent->content, &child_count); - for (size_t i = 0; i < child_count; i++) { - TSChildWithPosition child = children[i]; - size_t child_left = - parent->start_position + child.position + child.tree->offset; - if (child_left > min) + size_t count; + TSTreeChild *children = ts_tree_visible_children(parent->content, &count); + for (size_t i = 0; i < count; i++) { + TSTreeChild child = children[i]; + size_t child_pos = parent->position + child.offset; + if (child_pos > min) break; - if (child_left + child.tree->size > max) { + if (child_pos + child.tree->size > max) { TSNode *node = - ts_node_make(child.tree, parent, i, - parent->start_position + child.position, parent->names); + ts_node_make(child.tree, parent, i, child_pos, parent->names); TSNode *result = ts_node_find_for_range(node, min, max); ts_node_release(node); return result; diff --git a/src/runtime/node.h b/src/runtime/node.h index 88ecc7fb..ffeaf166 100644 --- a/src/runtime/node.h +++ b/src/runtime/node.h @@ -6,7 +6,7 @@ struct TSNode { size_t ref_count; - size_t start_position; + size_t position; size_t index; const TSTree *content; struct TSNode *parent; @@ -14,7 +14,7 @@ struct TSNode { }; TSNode *ts_node_make(const TSTree *tree, TSNode *parent, size_t index, - size_t start_position, const char **names); + size_t position, const char **names); TSNode *ts_node_make_root(const TSTree *tree, const char **names); #endif diff --git a/src/runtime/tree.c b/src/runtime/tree.c index 4b8e6576..63505285 100644 --- a/src/runtime/tree.c +++ b/src/runtime/tree.c @@ -3,20 +3,30 @@ #include "tree_sitter/parser.h" #include "runtime/tree.h" -static TSTree *ts_tree_make(TSSymbol symbol, size_t size, size_t offset, +static TSTree *ts_tree_make(TSSymbol symbol, size_t size, size_t padding, int is_hidden) { TSTree *result = malloc(sizeof(TSTree)); *result = (TSTree) { .ref_count = 1, .symbol = symbol, .size = size, - .offset = offset, + .padding = padding, .options = is_hidden ? TSTreeOptionsHidden : 0, }; return result; } -TSTree *ts_tree_make_leaf(TSSymbol symbol, size_t size, size_t offset, +TSTree *ts_tree_make_error(char lookahead_char, size_t expected_input_count, + const TSSymbol *expected_inputs, size_t size, + size_t padding) { + TSTree *result = ts_tree_make(ts_builtin_sym_error, size, padding, 0); + result->lookahead_char = lookahead_char; + result->expected_input_count = expected_input_count; + result->expected_inputs = expected_inputs; + return result; +} + +TSTree *ts_tree_make_leaf(TSSymbol symbol, size_t size, size_t padding, int is_hidden) { - TSTree *result = ts_tree_make(symbol, size, offset, is_hidden); + TSTree *result = ts_tree_make(symbol, size, padding, is_hidden); result->child_count = 0; result->children = NULL; return result; @@ -24,15 +34,18 @@ TSTree *ts_tree_make_leaf(TSSymbol symbol, size_t size, size_t offset, TSTree *ts_tree_make_node(TSSymbol symbol, size_t child_count, TSTree **children, int is_hidden) { - size_t size = 0, offset = 0, visible_child_count = 0; + /* + * Determine size, padding and visible child count based on child nodes. + */ + size_t size = 0, padding = 0, visible_child_count = 0; for (size_t i = 0; i < child_count; i++) { TSTree *child = children[i]; ts_tree_retain(child); if (i == 0) { - offset = child->offset; + padding = child->padding; size = child->size; } else { - size += child->offset + child->size; + size += child->padding + child->size; } if (ts_tree_is_visible(child)) @@ -41,6 +54,9 @@ TSTree *ts_tree_make_node(TSSymbol symbol, size_t child_count, visible_child_count += ts_tree_visible_child_count(child); } + /* + * Mark tree as hidden if it wraps a single child node. + */ TSTreeOptions options = 0; if (is_hidden) options |= TSTreeOptionsHidden; @@ -48,56 +64,50 @@ TSTree *ts_tree_make_node(TSSymbol symbol, size_t child_count, (ts_tree_is_visible(children[0]) || ts_tree_is_wrapper(children[0]))) options |= (TSTreeOptionsWrapper | TSTreeOptionsHidden); - TSTree *result = malloc(sizeof(TSTree) + - (visible_child_count * sizeof(TSChildWithPosition))); + TSTree *result = + malloc(sizeof(TSTree) + (visible_child_count * sizeof(TSTreeChild))); *result = (TSTree) { .ref_count = 1, .symbol = symbol, .size = size, - .offset = offset, + .padding = padding, .options = options }; result->children = children; result->child_count = child_count; result->visible_child_count = visible_child_count; - TSChildWithPosition *visible_children = - ts_tree_visible_children(result, NULL); - - for (size_t i = 0, visible_i = 0, child_position = 0; i < child_count; i++) { + /* + * Associate a relative offset with each of the visible child nodes, so + * that their positions can be queried without dealing with the hidden child + * nodes. + */ + TSTreeChild *visible_children = ts_tree_visible_children(result, NULL); + for (size_t i = 0, vis_i = 0, offset = 0; i < child_count; i++) { TSTree *child = children[i]; + + if (i > 0) + offset += child->padding; + if (ts_tree_is_visible(child)) { - visible_children[visible_i] = - (TSChildWithPosition) { .tree = child, .position = child_position }; - visible_i++; + visible_children[vis_i].tree = child; + visible_children[vis_i].offset = offset; + vis_i++; } else { - size_t granchild_count = 0; - TSChildWithPosition *grandchildren = - ts_tree_visible_children(child, &granchild_count); - for (size_t j = 0; j < granchild_count; j++) { - visible_children[visible_i] = (TSChildWithPosition) { - .tree = grandchildren[j].tree, - .position = grandchildren[j].position + child_position - }; - visible_i++; + 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 = offset + grandchildren[j].offset; + vis_i++; } } - child_position += child->offset + child->size; + offset += child->size; } return result; } -TSTree *ts_tree_make_error(char lookahead_char, size_t expected_input_count, - const TSSymbol *expected_inputs, size_t size, - size_t offset) { - TSTree *result = ts_tree_make(ts_builtin_sym_error, size, offset, 0); - result->lookahead_char = lookahead_char; - result->expected_input_count = expected_input_count; - result->expected_inputs = expected_inputs; - return result; -} - void ts_tree_retain(TSTree *tree) { tree->ref_count++; } void ts_tree_release(TSTree *tree) { @@ -113,7 +123,7 @@ void ts_tree_release(TSTree *tree) { } size_t ts_tree_total_size(const TSTree *tree) { - return tree->offset + tree->size; + return tree->padding + tree->size; } int ts_tree_equals(const TSTree *node1, const TSTree *node2) { diff --git a/src/runtime/tree.h b/src/runtime/tree.h index 43f7137f..e7c7cfb8 100644 --- a/src/runtime/tree.h +++ b/src/runtime/tree.h @@ -17,7 +17,7 @@ struct TSTree { TSSymbol symbol; TSTreeOptions options; size_t ref_count; - size_t offset; + size_t padding; size_t size; union { struct { @@ -35,8 +35,8 @@ struct TSTree { typedef struct { TSTree *tree; - size_t position; -} TSChildWithPosition; + size_t offset; +} TSTreeChild; static inline int ts_tree_is_extra(const TSTree *tree) { return (tree->options & TSTreeOptionsExtra); @@ -61,8 +61,8 @@ static inline size_t ts_tree_visible_child_count(const TSTree *tree) { return tree->visible_child_count; } -static inline TSChildWithPosition *ts_tree_visible_children(const TSTree *tree, - size_t *count) { +static inline TSTreeChild *ts_tree_visible_children(const TSTree *tree, + size_t *count) { if (tree->symbol == ts_builtin_sym_error || tree->visible_child_count == 0) { if (count) *count = 0; @@ -70,17 +70,17 @@ static inline TSChildWithPosition *ts_tree_visible_children(const TSTree *tree, } else { if (count) *count = tree->visible_child_count; - return (TSChildWithPosition *)(tree + 1); + return (TSTreeChild *)(tree + 1); } } -TSTree *ts_tree_make_leaf(TSSymbol symbol, size_t size, size_t offset, +TSTree *ts_tree_make_leaf(TSSymbol symbol, size_t size, size_t padding, int is_hidden); TSTree *ts_tree_make_node(TSSymbol symbol, size_t child_count, TSTree **children, int is_hidden); TSTree *ts_tree_make_error(char lookahead_char, size_t expected_input_count, const TSSymbol *expected_inputs, size_t size, - size_t offset); + size_t padding); void ts_tree_retain(TSTree *tree); void ts_tree_release(TSTree *tree); int ts_tree_equals(const TSTree *tree1, const TSTree *tree2);