From 1ecafb874ed6cef4062d6eb64c7ec3c6e44f2aad Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Fri, 18 Jul 2014 13:24:03 -0700 Subject: [PATCH] Add functions to retrieve nodes' siblings and parents --- include/tree_sitter/runtime.h | 5 ++- spec/runtime/document_spec.cc | 32 ---------------- spec/runtime/node_spec.cc | 70 ++++++++++++++++++++++------------- src/runtime/node.c | 23 ++++++++++-- src/runtime/node.h | 2 +- 5 files changed, 69 insertions(+), 63 deletions(-) diff --git a/include/tree_sitter/runtime.h b/include/tree_sitter/runtime.h index 3adc0af8..57b2f38f 100644 --- a/include/tree_sitter/runtime.h +++ b/include/tree_sitter/runtime.h @@ -33,11 +33,12 @@ const char * ts_node_name(const TSNode *); TSNode * ts_node_child(TSNode *, size_t); TSNode * ts_node_leaf_at_pos(TSNode *, size_t); TSNode * ts_node_parent(TSNode *node); -TSNode * ts_node_next(TSNode *node); -TSNode * ts_node_prev(TSNode *node); +TSNode * ts_node_next_sibling(TSNode *node); +TSNode * ts_node_prev_sibling(TSNode *node); void ts_node_retain(TSNode *node); void ts_node_release(TSNode *node); const char * ts_node_string(const TSNode *); +int ts_node_eq(const TSNode *, const TSNode *); TSDocument * ts_document_make(); void ts_document_free(TSDocument *doc); diff --git a/spec/runtime/document_spec.cc b/spec/runtime/document_spec.cc index 93e4635c..5e0a4473 100644 --- a/spec/runtime/document_spec.cc +++ b/spec/runtime/document_spec.cc @@ -82,38 +82,6 @@ describe("incremental parsing", [&]() { }); }); - it("records the widths and offsets of nodes", [&]() { - ts_document_set_input_string(doc, " [12, 5, 345]"); - - TSNode *array = ts_document_root_node(doc); - AssertThat(ts_node_string(array), Equals("(array (number) (number) (number))")); - - TSNode *number1 = ts_node_child(array, 0); - TSNode *number2 = ts_node_child(array, 1); - TSNode *number3 = ts_node_child(array, 2); - - AssertThat(ts_node_name(array), Equals("array")); - AssertThat(ts_node_name(number1), Equals("number")); - AssertThat(ts_node_name(number2), Equals("number")); - AssertThat(ts_node_name(number3), Equals("number")); - - AssertThat(ts_node_pos(array), Equals(2)); - AssertThat(ts_node_size(array), Equals(12)); - - AssertThat(ts_node_pos(number1), Equals(3)); - AssertThat(ts_node_size(number1), Equals(2)); - - AssertThat(ts_node_pos(number2), Equals(7)); - AssertThat(ts_node_size(number2), Equals(1)); - - AssertThat(ts_node_pos(number3), Equals(10)); - AssertThat(ts_node_size(number3), Equals(3)); - - ts_node_release(array); - ts_node_release(number1); - ts_node_release(number2); - ts_node_release(number3); - }); }); END_TEST diff --git a/spec/runtime/node_spec.cc b/spec/runtime/node_spec.cc index 611396b9..a2e9ffe8 100644 --- a/spec/runtime/node_spec.cc +++ b/spec/runtime/node_spec.cc @@ -1,52 +1,72 @@ #include "runtime/runtime_spec_helper.h" -extern "C" TSParser * ts_parser_arithmetic(); +extern "C" TSParser * ts_parser_json(); START_TEST describe("Node", []() { TSDocument *document; + TSNode *root; before_each([&]() { document = ts_document_make(); - ts_document_set_parser(document, ts_parser_arithmetic()); + ts_document_set_parser(document, ts_parser_json()); + + ts_document_set_input_string(document, " [12, 5, 345]"); + root = ts_document_root_node(document); + AssertThat(ts_node_string(root), Equals("(array (number) (number) (number))")); }); after_each([&]() { ts_document_free(document); + ts_node_release(root); }); - describe("getting the nth child node", [&]() { - TSNode *root; + it("knows its position and size", [&]() { + TSNode *number1 = ts_node_child(root, 0); + TSNode *number2 = ts_node_child(root, 1); + TSNode *number3 = ts_node_child(root, 2); - describe("when the child has more than n visible children", [&]() { - before_each([&]() { - ts_document_set_input_string(document, "x + 1"); - root = ts_document_root_node(document); + AssertThat(ts_node_name(root), Equals("array")); + AssertThat(ts_node_name(number1), Equals("number")); + AssertThat(ts_node_name(number2), Equals("number")); + AssertThat(ts_node_name(number3), Equals("number")); - AssertThat(ts_node_name(root), Equals("sum")); - AssertThat(ts_node_string(root), Equals("(sum (variable) (number))")); - }); + AssertThat(ts_node_pos(root), Equals(2)); + AssertThat(ts_node_size(root), Equals(12)); - after_each([&]() { - ts_node_release(root); - }); + AssertThat(ts_node_pos(number1), Equals(3)); + AssertThat(ts_node_size(number1), Equals(2)); - it("returns the nth child", [&]() { - TSNode *child1 = ts_node_child(root, 0); - AssertThat(ts_node_name(child1), Equals("variable")); + AssertThat(ts_node_pos(number2), Equals(7)); + AssertThat(ts_node_size(number2), Equals(1)); - TSNode *child2 = ts_node_child(root, 1); - AssertThat(ts_node_name(child2), Equals("number")); + AssertThat(ts_node_pos(number3), Equals(10)); + AssertThat(ts_node_size(number3), Equals(3)); - ts_node_release(child1); - ts_node_release(child2); - }); - }); + ts_node_release(number1); + ts_node_release(number2); + ts_node_release(number3); }); - it("gets the first token", [&]() { - // ts_document_get_node(document, 0); + it("can retrieve its parent node", [&]() { + TSNode *number2 = ts_node_child(root, 1); + AssertThat(ts_node_parent(number2), Equals(root)); + + ts_node_release(number2); + }); + + it("can retrieve its sibling nodes", [&]() { + TSNode *number1 = ts_node_child(root, 0); + TSNode *number2 = ts_node_child(root, 1); + TSNode *number3 = ts_node_child(root, 2); + + AssertThat(ts_node_eq(ts_node_next_sibling(number2), number3), IsTrue()); + AssertThat(ts_node_eq(ts_node_prev_sibling(number2), number1), IsTrue()); + + ts_node_release(number1); + ts_node_release(number2); + ts_node_release(number3); }); }); diff --git a/src/runtime/node.c b/src/runtime/node.c index 8eb7b0b3..c3561c2f 100644 --- a/src/runtime/node.c +++ b/src/runtime/node.c @@ -2,12 +2,13 @@ #include "tree_sitter/parser.h" #include "runtime/tree.h" -TSNode * ts_node_make(const TSTree *tree, TSNode *parent, size_t start_position, TSParserConfig *config) { +TSNode * ts_node_make(const TSTree *tree, TSNode *parent, size_t index, size_t start_position, TSParserConfig *config) { if (parent) ts_node_retain(parent); TSNode *result = malloc(sizeof(TSNode)); *result = (TSNode) { .ref_count = 1, .parent = parent, + .index = index, .content = tree, .start_position = start_position, .config = config @@ -18,7 +19,7 @@ TSNode * ts_node_make(const TSTree *tree, TSNode *parent, size_t start_position, TSNode * ts_node_make_root(const TSTree *tree, TSParserConfig *config) { while (ts_tree_is_wrapper(tree)) tree = tree->children[0]; - return ts_node_make(tree, NULL, 0, config); + return ts_node_make(tree, NULL, 0, 0, config); } void ts_node_retain(TSNode *node) { @@ -41,6 +42,10 @@ size_t ts_node_size(const TSNode *node) { return node->content->size; } +int ts_node_eq(const TSNode *left, const TSNode *right) { + return ts_tree_equals(left->content, right->content); +} + const char * ts_node_name(const TSNode *node) { return node->config->symbol_names[node->content->symbol]; } @@ -49,13 +54,25 @@ const char * ts_node_string(const TSNode *node) { return ts_tree_string(node->content, node->config->symbol_names); } +TSNode * ts_node_parent(TSNode *child) { + return child->parent; +} + +TSNode * ts_node_prev_sibling(TSNode *child) { + return ts_node_child(child->parent, child->index - 1); +} + +TSNode * ts_node_next_sibling(TSNode *child) { + return ts_node_child(child->parent, child->index + 1); +} + 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) return NULL; size_t position = parent->start_position + children[index].position; - return ts_node_make(children[index].tree, parent, position, parent->config); + return ts_node_make(children[index].tree, parent, index, position, parent->config); } TSNode * ts_node_leaf_at_pos(TSNode *parent, size_t child_index) { diff --git a/src/runtime/node.h b/src/runtime/node.h index 85dab80f..db2a08c2 100644 --- a/src/runtime/node.h +++ b/src/runtime/node.h @@ -12,7 +12,7 @@ struct TSNode { TSParserConfig *config; }; -TSNode * ts_node_make(const TSTree *tree, TSNode *parent, size_t start_position, TSParserConfig *config); +TSNode * ts_node_make(const TSTree *tree, TSNode *parent, size_t index, size_t start_position, TSParserConfig *config); TSNode * ts_node_make_root(const TSTree *tree, TSParserConfig *config); #endif