From c3f3f19ea87a3fe5a333b7e8adb566d1587e88e2 Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Mon, 7 Sep 2015 21:11:37 -0700 Subject: [PATCH] Add concrete_child and concrete_child_count Node methods --- include/tree_sitter/parser.h | 4 +- include/tree_sitter/runtime.h | 3 ++ spec/runtime/node_spec.cc | 84 ++++++++++++++++++++++++++++++++--- spec/runtime/tree_spec.cc | 6 +-- src/runtime/node.c | 40 ++++++++++++----- src/runtime/tree.c | 74 +++++++++++++++++++----------- src/runtime/tree.h | 6 +-- 7 files changed, 166 insertions(+), 51 deletions(-) diff --git a/include/tree_sitter/parser.h b/include/tree_sitter/parser.h index 2b9fdec4..f1ffee89 100644 --- a/include/tree_sitter/parser.h +++ b/include/tree_sitter/parser.h @@ -17,9 +17,9 @@ typedef struct TSTree TSTree; typedef unsigned short TSStateId; typedef enum { - TSNodeTypeNormal, - TSNodeTypeConcrete, TSNodeTypeHidden, + TSNodeTypeConcrete, + TSNodeTypeNormal, } TSNodeType; typedef struct TSLexer { diff --git a/include/tree_sitter/runtime.h b/include/tree_sitter/runtime.h index 93ea8351..91773703 100644 --- a/include/tree_sitter/runtime.h +++ b/include/tree_sitter/runtime.h @@ -51,6 +51,8 @@ TSLength ts_node_size(TSNode); TSSymbol ts_node_sym(TSNode); TSNode ts_node_child(TSNode, size_t); size_t ts_node_child_count(TSNode); +TSNode ts_node_concrete_child(TSNode, size_t); +size_t ts_node_concrete_child_count(TSNode); TSNode ts_node_find_for_pos(TSNode, size_t); TSNode ts_node_find_for_range(TSNode, size_t, size_t); TSNode ts_node_parent(TSNode); @@ -59,6 +61,7 @@ TSNode ts_node_prev_sibling(TSNode); const char *ts_node_name(TSNode, const TSDocument *); const char *ts_node_string(TSNode, const TSDocument *); bool ts_node_eq(TSNode, TSNode); +bool ts_node_is_concrete(TSNode); TSDocument *ts_document_make(); void ts_document_free(TSDocument *); diff --git a/spec/runtime/node_spec.cc b/spec/runtime/node_spec.cc index ef4e4f4d..be079df2 100644 --- a/spec/runtime/node_spec.cc +++ b/spec/runtime/node_spec.cc @@ -24,14 +24,10 @@ describe("Node", []() { ts_document_free(document); }); - describe("child_count()", [&]() { - it("returns the number of visible child nodes", [&]() { - AssertThat(ts_node_child_count(array_node), Equals(3)); - }); - }); - - describe("child(i)", [&]() { + describe("child_count(), child(i)", [&]() { it("returns the child node at the given index", [&]() { + AssertThat(ts_node_child_count(array_node), Equals(3)); + TSNode child1 = ts_node_child(array_node, 0); TSNode child2 = ts_node_child(array_node, 1); TSNode child3 = ts_node_child(array_node, 2); @@ -53,6 +49,14 @@ describe("Node", []() { AssertThat(ts_node_pos(child3).bytes, Equals(15)); AssertThat(ts_node_size(child3).bytes, Equals(11)); + AssertThat(ts_node_child_count(child3), Equals(2)); + + TSNode grandchild1 = ts_node_child(child3, 0); + TSNode grandchild2 = ts_node_child(child3, 1); + + AssertThat(ts_node_name(grandchild1, document), Equals("string")); + AssertThat(ts_node_name(grandchild2, document), Equals("null")); + AssertThat(ts_node_parent(child1), Equals(array_node)); AssertThat(ts_node_parent(child2), Equals(array_node)); AssertThat(ts_node_parent(child3), Equals(array_node)); @@ -60,6 +64,72 @@ describe("Node", []() { }); }); + describe("concrete_child_count(), concrete_child(i)", [&]() { + it("returns the child node at the given index, counting anonymous token nodes", [&]() { + AssertThat(ts_node_concrete_child_count(array_node), Equals(7)); + TSNode child1 = ts_node_concrete_child(array_node, 0); + TSNode child2 = ts_node_concrete_child(array_node, 1); + TSNode child3 = ts_node_concrete_child(array_node, 2); + TSNode child4 = ts_node_concrete_child(array_node, 3); + TSNode child5 = ts_node_concrete_child(array_node, 4); + TSNode child6 = ts_node_concrete_child(array_node, 5); + TSNode child7 = ts_node_concrete_child(array_node, 6); + + AssertThat(ts_node_name(array_node, document), Equals("array")); + AssertThat(ts_node_name(child1, document), Equals("[")); + AssertThat(ts_node_name(child2, document), Equals("number")); + AssertThat(ts_node_name(child3, document), Equals(",")); + AssertThat(ts_node_name(child4, document), Equals("false")); + AssertThat(ts_node_name(child5, document), Equals(",")); + AssertThat(ts_node_name(child6, document), Equals("object")); + AssertThat(ts_node_name(child7, document), Equals("]")); + + AssertThat(ts_node_is_concrete(array_node), IsFalse()); + AssertThat(ts_node_is_concrete(child1), IsTrue()); + AssertThat(ts_node_is_concrete(child2), IsFalse()); + AssertThat(ts_node_is_concrete(child3), IsTrue()); + AssertThat(ts_node_is_concrete(child4), IsFalse()); + AssertThat(ts_node_is_concrete(child5), IsTrue()); + AssertThat(ts_node_is_concrete(child6), IsFalse()); + AssertThat(ts_node_is_concrete(child7), IsTrue()); + + AssertThat(ts_node_pos(child1).bytes, Equals(2)); + AssertThat(ts_node_size(child1).bytes, Equals(1)); + + AssertThat(ts_node_pos(child3).bytes, Equals(6)); + AssertThat(ts_node_size(child3).bytes, Equals(1)); + + AssertThat(ts_node_pos(child5).bytes, Equals(13)); + AssertThat(ts_node_size(child5).bytes, Equals(1)); + + AssertThat(ts_node_pos(child7).bytes, Equals(26)); + AssertThat(ts_node_size(child7).bytes, Equals(1)); + + AssertThat(ts_node_concrete_child_count(child6), Equals(5)) + + TSNode grandchild1 = ts_node_concrete_child(child6, 0); + TSNode grandchild2 = ts_node_concrete_child(child6, 1); + TSNode grandchild3 = ts_node_concrete_child(child6, 2); + TSNode grandchild4 = ts_node_concrete_child(child6, 3); + TSNode grandchild5 = ts_node_concrete_child(child6, 4); + + AssertThat(ts_node_name(grandchild1, document), Equals("{")); + AssertThat(ts_node_name(grandchild2, document), Equals("string")); + AssertThat(ts_node_name(grandchild3, document), Equals(":")); + AssertThat(ts_node_name(grandchild4, document), Equals("null")); + AssertThat(ts_node_name(grandchild5, document), Equals("}")); + + AssertThat(ts_node_parent(child1), Equals(array_node)); + AssertThat(ts_node_parent(child2), Equals(array_node)); + AssertThat(ts_node_parent(child3), Equals(array_node)); + AssertThat(ts_node_parent(child4), Equals(array_node)); + AssertThat(ts_node_parent(child5), Equals(array_node)); + AssertThat(ts_node_parent(child6), Equals(array_node)); + AssertThat(ts_node_parent(child7), Equals(array_node)); + AssertThat(ts_node_parent(array_node).data, Equals(nullptr)); + }); + }); + describe("next_sibling() and prev_sibling()", [&]() { it("returns the node's next and previous siblings", [&]() { TSNode number_node = ts_node_child(array_node, 0); diff --git a/spec/runtime/tree_spec.cc b/spec/runtime/tree_spec.cc index d0351c3b..8c8ec79c 100644 --- a/spec/runtime/tree_spec.cc +++ b/spec/runtime/tree_spec.cc @@ -215,7 +215,7 @@ describe("Tree", []() { }); it("hides invisible nodes", [&]() { - tree2->options.hidden = true; + tree2->options.type = TSNodeTypeHidden; char *string1 = ts_tree_string(parent1, names); AssertThat(string(string1), Equals("(dog (cat))")); @@ -224,13 +224,13 @@ describe("Tree", []() { describe("when the root node is not visible", [&]() { it("still serializes it", [&]() { - parent1->options.hidden = true; + parent1->options.type = TSNodeTypeHidden; char *string1 = ts_tree_string(parent1, names); AssertThat(string(string1), Equals("(dog (cat) (cat))")); free(string1); - tree1->options.hidden = true; + tree1->options.type = TSNodeTypeHidden; char *string2 = ts_tree_string(tree1, names); AssertThat(string(string2), Equals("(cat)")); diff --git a/src/runtime/node.c b/src/runtime/node.c index 1526f8ba..57bde1ce 100644 --- a/src/runtime/node.c +++ b/src/runtime/node.c @@ -74,11 +74,11 @@ TSNode ts_node_prev_sibling(TSNode this) { for (size_t i = tree->context.index - 1; i + 1 > 0; i--) { const TSTree *child = parent->children[i]; position = ts_length_sub(position, ts_tree_total_size(child)); - if (ts_tree_is_visible(child)) + if (child->options.type == TSNodeTypeNormal) return ts_node_make(child, position); - if (child->visible_child_count > 0) + if (child->named_child_count > 0) return ts_node_child(ts_node_make(child, position), - child->visible_child_count - 1); + child->named_child_count - 1); } tree = parent; @@ -100,9 +100,9 @@ TSNode ts_node_next_sibling(TSNode this) { for (size_t i = tree->context.index + 1; i < parent->child_count; i++) { const TSTree *child = parent->children[i]; position = ts_length_add(position, ts_tree_total_size(prev_child)); - if (ts_tree_is_visible(child)) + if (child->options.type == TSNodeTypeNormal) return ts_node_make(child, position); - if (child->visible_child_count > 0) + if (child->named_child_count > 0) return ts_node_child(ts_node_make(child, position), 0); prev_child = child; } @@ -113,11 +113,20 @@ TSNode ts_node_next_sibling(TSNode this) { return ts_node__null(); } -size_t ts_node_child_count(TSNode this) { +size_t ts_node_concrete_child_count(TSNode this) { return ts_node__tree(this)->visible_child_count; } -TSNode ts_node_child(TSNode this, size_t child_index) { +bool ts_node_is_concrete(TSNode this) { + return ts_node__tree(this)->options.type == TSNodeTypeConcrete; +} + +size_t ts_node_child_count(TSNode this) { + return ts_node__tree(this)->named_child_count; +} + +static TSNode ts_node__child_with_type(TSNode this, size_t child_index, + TSNodeType type) { const TSTree *tree = ts_node__tree(this); TSLength position = ts_node__offset(this); @@ -128,19 +137,22 @@ TSNode ts_node_child(TSNode this, size_t child_index) { 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 (child->options.type >= type) { if (index == child_index) return ts_node_make(child, position); index++; } else { size_t grandchild_index = child_index - index; - if (grandchild_index < child->visible_child_count) { + size_t grandchild_count = (type == TSNodeTypeNormal) + ? child->named_child_count + : child->visible_child_count; + if (grandchild_index < grandchild_count) { did_descend = true; tree = child; child_index = grandchild_index; break; } - index += child->visible_child_count; + index += grandchild_count; } position = ts_length_add(position, ts_tree_total_size(child)); } @@ -149,6 +161,14 @@ TSNode ts_node_child(TSNode this, size_t child_index) { return ts_node__null(); } +TSNode ts_node_child(TSNode this, size_t child_index) { + return ts_node__child_with_type(this, child_index, TSNodeTypeNormal); +} + +TSNode ts_node_concrete_child(TSNode this, size_t child_index) { + return ts_node__child_with_type(this, child_index, TSNodeTypeConcrete); +} + TSNode ts_node_find_for_range(TSNode this, size_t min, size_t max) { const TSTree *tree = ts_node__tree(this), *last_visible_tree = tree; TSLength position = ts_node__offset(this), last_visible_position = position; diff --git a/src/runtime/tree.c b/src/runtime/tree.c index db99463a..fe97ed0d 100644 --- a/src/runtime/tree.c +++ b/src/runtime/tree.c @@ -14,19 +14,18 @@ TSTree *ts_tree_make_leaf(TSSymbol sym, TSLength size, TSLength padding, .symbol = sym, .size = size, .child_count = 0, + .visible_child_count = 0, + .named_child_count = 0, .children = NULL, .padding = padding, - .options = - (TSTreeOptions){ - .hidden = (node_type == TSNodeTypeHidden), - .concrete = (node_type == TSNodeTypeConcrete), - }, + .options = {.type = node_type }, }; return result; } TSTree *ts_tree_make_error(TSLength size, TSLength padding, char lookahead_char) { - TSTree *result = ts_tree_make_leaf(ts_builtin_sym_error, size, padding, false); + TSTree *result = + ts_tree_make_leaf(ts_builtin_sym_error, size, padding, TSNodeTypeNormal); ts_tree_set_fragile_left(result); ts_tree_set_fragile_right(result); result->lookahead_char = lookahead_char; @@ -42,7 +41,7 @@ TSTree *ts_tree_make_node(TSSymbol symbol, size_t child_count, * the given child nodes. */ TSLength size = ts_length_zero(), padding = ts_length_zero(); - size_t visible_child_count = 0; + size_t visible_child_count = 0, named_child_count = 0; for (size_t i = 0; i < child_count; i++) { TSTree *child = children[i]; ts_tree_retain(child); @@ -56,15 +55,23 @@ TSTree *ts_tree_make_node(TSSymbol symbol, size_t child_count, size = ts_length_add(ts_length_add(size, child->padding), child->size); } - if (ts_tree_is_visible(child)) - visible_child_count++; - else - visible_child_count += child->visible_child_count; + switch (child->options.type) { + case TSNodeTypeNormal: + visible_child_count++; + named_child_count++; + break; + case TSNodeTypeConcrete: + visible_child_count++; + break; + case TSNodeTypeHidden: + visible_child_count += child->visible_child_count; + named_child_count += child->named_child_count; + break; + } } TSTreeOptions options = (TSTreeOptions){ - .hidden = (node_type == TSNodeTypeHidden), - .concrete = (node_type == TSNodeTypeConcrete), + .type = node_type, }; if (symbol == ts_builtin_sym_error) { @@ -75,15 +82,18 @@ TSTree *ts_tree_make_node(TSSymbol symbol, size_t child_count, options.fragile_right = children[child_count - 1]->options.fragile_right; } - *result = (TSTree){.ref_count = 1, - .context = {.parent = NULL, .index = 0 }, - .symbol = symbol, - .children = children, - .child_count = child_count, - .visible_child_count = visible_child_count, - .size = size, - .padding = padding, - .options = options }; + *result = (TSTree){ + .ref_count = 1, + .context = {.parent = NULL, .index = 0 }, + .symbol = symbol, + .children = children, + .child_count = child_count, + .visible_child_count = visible_child_count, + .named_child_count = named_child_count, + .size = size, + .padding = padding, + .options = options, + }; return result; } @@ -124,6 +134,8 @@ bool ts_tree_eq(const TSTree *node1, const TSTree *node2) { return false; if (node1->visible_child_count != node2->visible_child_count) return false; + if (node1->named_child_count != node2->named_child_count) + return false; for (size_t i = 0; i < node1->child_count; i++) if (!ts_tree_eq(node1->children[i], node2->children[i])) return false; @@ -148,7 +160,7 @@ static size_t ts_tree__write_to_string(const TSTree *tree, char *cursor = string; char **writer = (limit > 0) ? &cursor : &string; - int visible = ts_tree_is_visible(tree) || is_root; + int visible = tree->options.type == TSNodeTypeNormal || is_root; if (visible && !is_root) cursor += snprintf(*writer, limit, " "); @@ -187,15 +199,24 @@ void ts_tree_prepend_children(TSTree *tree, size_t count, TSTree **children) { tree->size = ts_length_add(tree->size, tree->padding); - size_t visible_count = 0; + size_t visible_count = 0, named_count = 0; for (size_t i = 0; i < count; i++) { if (i == 0) tree->padding = children[i]->padding; else tree->size = ts_length_add(tree->size, children[i]->padding); tree->size = ts_length_add(tree->size, children[i]->size); - if (ts_tree_is_visible(children[i])) - visible_count++; + switch (children[i]->options.type) { + case TSNodeTypeNormal: + visible_count++; + named_count++; + break; + case TSNodeTypeConcrete: + visible_count++; + break; + case TSNodeTypeHidden: + break; + } } size_t new_child_count = count + tree->child_count; @@ -206,5 +227,6 @@ void ts_tree_prepend_children(TSTree *tree, size_t count, TSTree **children) { tree->children = new_children; tree->visible_child_count += visible_count; + tree->named_child_count += named_count; tree->child_count += count; } diff --git a/src/runtime/tree.h b/src/runtime/tree.h index c6f4654a..c75b858b 100644 --- a/src/runtime/tree.h +++ b/src/runtime/tree.h @@ -9,8 +9,7 @@ extern "C" { #include "tree_sitter/parser.h" typedef struct { - bool hidden : 1; - bool concrete : 1; + TSNodeType type : 4; bool extra : 1; bool fragile_left : 1; bool fragile_right : 1; @@ -23,6 +22,7 @@ struct TSTree { } context; size_t child_count; size_t visible_child_count; + size_t named_child_count; union { struct TSTree **children; char lookahead_char; @@ -44,7 +44,7 @@ static inline bool ts_tree_is_extra(const TSTree *tree) { } static inline bool ts_tree_is_visible(const TSTree *tree) { - return !(tree->options.hidden || tree->options.concrete); + return tree->options.type != TSNodeTypeHidden; } static inline void ts_tree_set_extra(TSTree *tree) {