diff --git a/include/tree_sitter/parser.h b/include/tree_sitter/parser.h index 7e4d5141..e03ba757 100644 --- a/include/tree_sitter/parser.h +++ b/include/tree_sitter/parser.h @@ -112,9 +112,11 @@ struct TSLanguage { * Parse Table Macros */ -#define ACTIONS(...) \ - (TSParseAction[]) { \ - __VA_ARGS__, { .type = 0 } \ +#define ACTIONS(...) \ + (TSParseAction[]) { \ + __VA_ARGS__, { \ + .type = 0 \ + } \ } #define SHIFT(to_state_value) \ @@ -155,7 +157,9 @@ struct TSLanguage { .lex_fn = ts_lex, \ }; \ \ - const TSLanguage *language_name() { return &language; } + const TSLanguage *language_name() { \ + return &language; \ + } #ifdef __cplusplus } diff --git a/include/tree_sitter/runtime.h b/include/tree_sitter/runtime.h index bef414d2..2bfea562 100644 --- a/include/tree_sitter/runtime.h +++ b/include/tree_sitter/runtime.h @@ -37,27 +37,29 @@ typedef struct { size_t chars_removed; } TSInputEdit; +typedef struct { + const void *data; + TSLength position; +} TSNode; + typedef unsigned short TSSymbol; typedef struct TSLanguage TSLanguage; - -typedef struct TSNode TSNode; -TSLength ts_node_pos(const TSNode *); -TSLength ts_node_size(const TSNode *); -TSSymbol ts_node_sym(const TSNode *); -TSNode *ts_node_child(TSNode *, size_t); -size_t ts_node_child_count(const 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 *node); -TSNode *ts_node_next_sibling(TSNode *node); -TSNode *ts_node_prev_sibling(TSNode *node); -const char *ts_node_name(const TSNode *); -const char *ts_node_string(const TSNode *); -void ts_node_retain(TSNode *node); -void ts_node_release(TSNode *node); -bool ts_node_eq(const TSNode *, const TSNode *); - typedef struct TSDocument TSDocument; + +TSLength ts_node_pos(TSNode); +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_find_for_pos(TSNode, size_t); +TSNode ts_node_find_for_range(TSNode, size_t, size_t); +TSNode ts_node_parent(TSNode); +TSNode ts_node_next_sibling(TSNode); +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); + TSDocument *ts_document_make(); void ts_document_free(TSDocument *); void ts_document_set_language(TSDocument *, const TSLanguage *); @@ -66,7 +68,7 @@ void ts_document_set_input_string(TSDocument *, const char *); void ts_document_edit(TSDocument *, TSInputEdit); TSDebugger ts_document_get_debugger(const TSDocument *); void ts_document_set_debugger(TSDocument *, TSDebugger); -TSNode *ts_document_root_node(const TSDocument *); +TSNode ts_document_root_node(const TSDocument *); #define ts_builtin_sym_error 0 #define ts_builtin_sym_end 1 diff --git a/spec/runtime/document_spec.cc b/spec/runtime/document_spec.cc index 5fcd0784..6a13d00c 100644 --- a/spec/runtime/document_spec.cc +++ b/spec/runtime/document_spec.cc @@ -26,7 +26,7 @@ describe("Document", [&]() { it("parses the document", [&]() { ts_document_set_input_string(doc, "{ \"key\": [1, 2] }"); - AssertThat(ts_node_string(ts_document_root_node(doc)), Equals( + AssertThat(ts_node_string(ts_document_root_node(doc), doc), Equals( "(DOCUMENT (object (string) (array (number) (number))))")); }); }); @@ -35,7 +35,7 @@ describe("Document", [&]() { it("does not try to parse the document", [&]() { ts_document_set_input_string(doc, "{ \"key\": [1, 2] }"); - AssertThat(ts_document_root_node(doc), Equals(nullptr)); + AssertThat(ts_document_root_node(doc).data, Equals(nullptr)); }); }); }); @@ -45,7 +45,7 @@ describe("Document", [&]() { it("does not try to parse the document", [&]() { ts_document_set_language(doc, ts_language_json()); - AssertThat(ts_document_root_node(doc), Equals(nullptr)); + AssertThat(ts_document_root_node(doc).data, Equals(nullptr)); }); }); @@ -57,7 +57,7 @@ describe("Document", [&]() { it("parses the document", [&]() { ts_document_set_language(doc, ts_language_json()); - AssertThat(ts_node_string(ts_document_root_node(doc)), Equals( + AssertThat(ts_node_string(ts_document_root_node(doc), doc), Equals( "(DOCUMENT (object (string) (array (number) (number))))")); }); }); diff --git a/spec/runtime/helpers/tree_helpers.cc b/spec/runtime/helpers/tree_helpers.cc index f698a1fb..2e20b4c0 100644 --- a/spec/runtime/helpers/tree_helpers.cc +++ b/spec/runtime/helpers/tree_helpers.cc @@ -27,3 +27,8 @@ std::ostream &operator<<(std::ostream &stream, const EqualsTree &matcher) { std::ostream &operator<<(std::ostream &stream, const TSTree *tree) { return stream << std::string(ts_tree_string(tree, symbol_names));; } + +std::ostream &operator<<(std::ostream &stream, const TSNode ref) { + return stream << std::string("{") << (const TSTree *)ref.data << + std::string(", ") << std::to_string(ref.position.chars) << std::string("}"); +} diff --git a/spec/runtime/helpers/tree_helpers.h b/spec/runtime/helpers/tree_helpers.h index 99a24624..433a64ca 100644 --- a/spec/runtime/helpers/tree_helpers.h +++ b/spec/runtime/helpers/tree_helpers.h @@ -18,5 +18,6 @@ struct EqualsTree { std::ostream &operator<<(std::ostream &stream, const EqualsTree &matcher); std::ostream &operator<<(std::ostream &stream, const TSTree *tree); +std::ostream &operator<<(std::ostream &stream, const TSNode ref); #endif // HELPERS_TREE_HELPERS_H_ diff --git a/spec/runtime/languages/language_specs.cc b/spec/runtime/languages/language_specs.cc index e17b1bd2..edc1be15 100644 --- a/spec/runtime/languages/language_specs.cc +++ b/spec/runtime/languages/language_specs.cc @@ -32,7 +32,7 @@ describe("Languages", [&]() { for (auto &entry : test_entries_for_language(language_name)) { auto expect_the_correct_tree = [&]() { - const char *node_string = ts_node_string(ts_document_root_node(doc)); + const char *node_string = ts_node_string(ts_document_root_node(doc), doc); AssertThat(node_string, Equals(("(DOCUMENT " + entry.tree_string + ")").c_str())); free((void *)node_string); }; diff --git a/spec/runtime/node_spec.cc b/spec/runtime/node_spec.cc index 126091f9..110cf134 100644 --- a/spec/runtime/node_spec.cc +++ b/spec/runtime/node_spec.cc @@ -6,14 +6,14 @@ START_TEST describe("Node", []() { TSDocument *document; - TSNode *root; + TSNode root; before_each([&]() { document = ts_document_make(); ts_document_set_language(document, ts_language_json()); ts_document_set_input_string(document, " [123, false, {\"x\": null}]"); root = ts_document_root_node(document); - AssertThat(ts_node_string(root), Equals( + AssertThat(ts_node_string(root, document), Equals( "(DOCUMENT (array " "(number) " "(false) " @@ -24,27 +24,24 @@ describe("Node", []() { ts_document_free(document); }); - describe("child_count", [&]() { + describe("child_count()", [&]() { it("returns the number of visible child nodes", [&]() { - TSNode *array = ts_node_child(root, 0); - + TSNode array = ts_node_child(root, 0); AssertThat(ts_node_child_count(array), Equals(3)); - - ts_node_release(array); }); }); describe("child(i)", [&]() { it("returns the child node at the given index", [&]() { - TSNode *parent = ts_node_child(root, 0); - TSNode *child1 = ts_node_child(parent, 0); - TSNode *child2 = ts_node_child(parent, 1); - TSNode *child3 = ts_node_child(parent, 2); + TSNode parent = ts_node_child(root, 0); + TSNode child1 = ts_node_child(parent, 0); + TSNode child2 = ts_node_child(parent, 1); + TSNode child3 = ts_node_child(parent, 2); - AssertThat(ts_node_name(parent), Equals("array")); - AssertThat(ts_node_name(child1), Equals("number")); - AssertThat(ts_node_name(child2), Equals("false")); - AssertThat(ts_node_name(child3), Equals("object")); + AssertThat(ts_node_name(parent, document), Equals("array")); + AssertThat(ts_node_name(child1, document), Equals("number")); + AssertThat(ts_node_name(child2, document), Equals("false")); + AssertThat(ts_node_name(child3, document), Equals("object")); AssertThat(ts_node_pos(parent).bytes, Equals(2)); AssertThat(ts_node_size(parent).bytes, Equals(25)); @@ -57,100 +54,95 @@ describe("Node", []() { AssertThat(ts_node_pos(child3).bytes, Equals(15)); AssertThat(ts_node_size(child3).bytes, Equals(11)); - - ts_node_release(parent); - ts_node_release(child1); - ts_node_release(child2); - ts_node_release(child3); }); }); - describe("parent", [&]() { + describe("parent()", [&]() { it("returns the node's parent node", [&]() { - TSNode *array = ts_node_child(root, 0); - TSNode *child1 = ts_node_child(array, 1); + 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)); - - ts_node_release(array); - ts_node_release(child1); }); it("returns null if the node has no parent", [&]() { - AssertThat(ts_node_parent(root), Equals(nullptr)); + AssertThat(ts_node_parent(root).data, Equals(nullptr)); }); }); - describe("next_sibling and prev_sibling", [&]() { + describe("next_sibling() and prev_sibling()", [&]() { it("returns the node's next and previous siblings", [&]() { - TSNode *array = ts_node_child(root, 0); - TSNode *number1 = ts_node_child(array, 0); - TSNode *number2 = ts_node_child(array, 1); - TSNode *number3 = ts_node_child(array, 2); + TSNode array = ts_node_child(root, 0); + TSNode number1 = ts_node_child(array, 0); + TSNode number2 = ts_node_child(array, 1); + TSNode number3 = ts_node_child(array, 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(array); - ts_node_release(number1); - ts_node_release(number2); - ts_node_release(number3); + AssertThat(ts_node_next_sibling(number1), Equals(number2)); + AssertThat(ts_node_next_sibling(number2), Equals(number3)); + AssertThat(ts_node_prev_sibling(number3), Equals(number2)); + AssertThat(ts_node_prev_sibling(number2), Equals(number1)); }); it("returns null when the node has no parent", [&]() { - AssertThat(ts_node_next_sibling(root), Equals(nullptr)); - AssertThat(ts_node_prev_sibling(root), Equals(nullptr)); + TSNode array = ts_node_child(root, 0); + AssertThat(ts_node_next_sibling(root).data, Equals(nullptr)); + AssertThat(ts_node_prev_sibling(root).data, Equals(nullptr)); + AssertThat(ts_node_next_sibling(array).data, Equals(nullptr)); + AssertThat(ts_node_prev_sibling(array).data, Equals(nullptr)); }); }); - describe("find_for_range", [&]() { + describe("find_for_range(start, end)", [&]() { describe("when there is a leaf node that spans the given range exactly", [&]() { it("returns that leaf node", [&]() { - TSNode *leaf = ts_node_find_for_range(root, 16, 18); - AssertThat(ts_node_name(leaf), Equals("string")); + TSNode leaf = ts_node_find_for_range(root, 16, 18); + AssertThat(ts_node_name(leaf, document), Equals("string")); AssertThat(ts_node_size(leaf).bytes, Equals(3)); AssertThat(ts_node_pos(leaf).bytes, Equals(16)); - ts_node_release(leaf); }); }); describe("when there is a leaf node that extends beyond the given range", [&]() { it("returns that leaf node", [&]() { - TSNode *leaf = ts_node_find_for_range(root, 16, 17); - AssertThat(ts_node_name(leaf), Equals("string")); + TSNode leaf = ts_node_find_for_range(root, 16, 17); + AssertThat(ts_node_name(leaf, document), Equals("string")); AssertThat(ts_node_size(leaf).bytes, Equals(3)); AssertThat(ts_node_pos(leaf).bytes, Equals(16)); - ts_node_release(leaf); leaf = ts_node_find_for_range(root, 17, 18); - AssertThat(ts_node_name(leaf), Equals("string")); + AssertThat(ts_node_name(leaf, document), Equals("string")); AssertThat(ts_node_size(leaf).bytes, Equals(3)); AssertThat(ts_node_pos(leaf).bytes, Equals(16)); - ts_node_release(leaf); }); }); describe("when there is no leaf node that spans the given range", [&]() { it("returns the smallest node that does span the range", [&]() { - TSNode *node = ts_node_find_for_range(root, 16, 19); - AssertThat(ts_node_name(node), Equals("object")); + TSNode node = ts_node_find_for_range(root, 16, 19); + AssertThat(ts_node_name(node, document), Equals("object")); AssertThat(ts_node_size(node).bytes, Equals(11)); AssertThat(ts_node_pos(node).bytes, Equals(15)); - ts_node_release(node); }); }); }); - describe("find_for_pos", [&]() { + describe("find_for_pos(position)", [&]() { it("finds the smallest node that spans the given position", [&]() { - TSNode *node = ts_node_find_for_pos(root, 10); - AssertThat(ts_node_name(node), Equals("false")); + TSNode node = ts_node_find_for_pos(root, 10); + AssertThat(ts_node_name(node, document), Equals("false")); AssertThat(ts_node_pos(node).bytes, Equals(8)); AssertThat(ts_node_size(node).bytes, Equals(5)); - ts_node_release(node); }); }); }); END_TEST + +bool operator==(const TSNode &left, const TSNode &right) { + return ts_node_eq(left, right); +} diff --git a/spec/runtime/parser_spec.cc b/spec/runtime/parser_spec.cc index 4263836c..034967bb 100644 --- a/spec/runtime/parser_spec.cc +++ b/spec/runtime/parser_spec.cc @@ -11,7 +11,7 @@ START_TEST describe("Parser", [&]() { TSDocument *doc; SpyInput *input; - TSNode *root; + TSNode root; size_t chunk_size; before_each([&]() { @@ -75,23 +75,19 @@ describe("Parser", [&]() { it("computes the error node's size and position correctly", [&]() { set_text(" [123, @@@@@, true]"); - AssertThat(ts_node_string(root), Equals( + AssertThat(ts_node_string(root, doc), Equals( "(DOCUMENT (array (number) (ERROR (UNEXPECTED '@')) (true)))")); - TSNode *array = ts_node_child(root, 0); - TSNode *error = ts_node_child(array, 1); - TSNode *last = ts_node_child(array, 2); + TSNode array = ts_node_child(root, 0); + TSNode error = ts_node_child(array, 1); + TSNode last = ts_node_child(array, 2); - AssertThat(ts_node_name(error), Equals("ERROR")); + AssertThat(ts_node_name(error, doc), Equals("ERROR")); AssertThat(ts_node_pos(error).bytes, Equals(strlen(" [123, "))) AssertThat(ts_node_size(error).bytes, Equals(strlen("@@@@@"))) - AssertThat(ts_node_name(last), Equals("true")); + AssertThat(ts_node_name(last, doc), Equals("true")); AssertThat(ts_node_pos(last).bytes, Equals(strlen(" [123, @@@@@, "))) - - ts_node_release(last); - ts_node_release(error); - ts_node_release(array); }); }); @@ -99,23 +95,19 @@ describe("Parser", [&]() { it("computes the error node's size and position correctly", [&]() { set_text(" [123, faaaaalse, true]"); - AssertThat(ts_node_string(root), Equals( + AssertThat(ts_node_string(root, doc), Equals( "(DOCUMENT (array (number) (ERROR (UNEXPECTED 'a')) (true)))")); - TSNode *array = ts_node_child(root, 0); - TSNode *error = ts_node_child(array, 1); - TSNode *last = ts_node_child(array, 2); + TSNode array = ts_node_child(root, 0); + TSNode error = ts_node_child(array, 1); + TSNode last = ts_node_child(array, 2); - AssertThat(ts_node_name(error), Equals("ERROR")); + AssertThat(ts_node_name(error, doc), Equals("ERROR")); AssertThat(ts_node_pos(error).bytes, Equals(strlen(" [123, "))) AssertThat(ts_node_size(error).bytes, Equals(strlen("faaaaalse"))) - AssertThat(ts_node_name(last), Equals("true")); + AssertThat(ts_node_name(last, doc), Equals("true")); AssertThat(ts_node_pos(last).bytes, Equals(strlen(" [123, faaaaalse, "))); - - ts_node_release(last); - ts_node_release(error); - ts_node_release(array); }); }); @@ -123,23 +115,19 @@ describe("Parser", [&]() { it("computes the error node's size and position correctly", [&]() { set_text(" [123, true false, true]"); - AssertThat(ts_node_string(root), Equals( + AssertThat(ts_node_string(root, doc), Equals( "(DOCUMENT (array (number) (ERROR (true) (UNEXPECTED 'f') (false)) (true)))")); - TSNode *array = ts_node_child(root, 0); - TSNode *error = ts_node_child(array, 1); - TSNode *last = ts_node_child(array, 2); + TSNode array = ts_node_child(root, 0); + TSNode error = ts_node_child(array, 1); + TSNode last = ts_node_child(array, 2); - AssertThat(ts_node_name(error), Equals("ERROR")); + AssertThat(ts_node_name(error, doc), Equals("ERROR")); AssertThat(ts_node_pos(error).bytes, Equals(strlen(" [123, "))); AssertThat(ts_node_size(error).bytes, Equals(strlen("true false"))); - AssertThat(ts_node_name(last), Equals("true")); + AssertThat(ts_node_name(last, doc), Equals("true")); AssertThat(ts_node_pos(last).bytes, Equals(strlen(" [123, true false, "))); - - ts_node_release(last); - ts_node_release(error); - ts_node_release(array); }); }); @@ -147,23 +135,19 @@ describe("Parser", [&]() { it("computes the error node's size and position correctly", [&]() { set_text(" [123, , true]"); - AssertThat(ts_node_string(root), Equals( + AssertThat(ts_node_string(root, doc), Equals( "(DOCUMENT (array (number) (ERROR (UNEXPECTED ',')) (true)))")); - TSNode *array = ts_node_child(root, 0); - TSNode *error = ts_node_child(array, 1); - TSNode *last = ts_node_child(array, 2); + TSNode array = ts_node_child(root, 0); + TSNode error = ts_node_child(array, 1); + TSNode last = ts_node_child(array, 2); - AssertThat(ts_node_name(error), Equals("ERROR")); + AssertThat(ts_node_name(error, doc), Equals("ERROR")); AssertThat(ts_node_pos(error).bytes, Equals(strlen(" [123, "))); AssertThat(ts_node_size(error).bytes, Equals(0)) - AssertThat(ts_node_name(last), Equals("true")); + AssertThat(ts_node_name(last, doc), Equals("true")); AssertThat(ts_node_pos(last).bytes, Equals(strlen(" [123, , "))); - - ts_node_release(last); - ts_node_release(error); - ts_node_release(array); }); }); }); @@ -179,7 +163,7 @@ describe("Parser", [&]() { it("is incorporated into the tree", [&]() { set_text("fn()\n"); - AssertThat(ts_node_string(root), Equals( + AssertThat(ts_node_string(root, doc), Equals( "(DOCUMENT (expression_statement (function_call (identifier))))")); }); }); @@ -190,7 +174,7 @@ describe("Parser", [&]() { "fn()\n" " .otherFn();"); - AssertThat(ts_node_string(root), Equals( + AssertThat(ts_node_string(root, doc), Equals( "(DOCUMENT " "(expression_statement (function_call " "(member_access (function_call (identifier)) (identifier)))))")); @@ -205,7 +189,7 @@ describe("Parser", [&]() { "\n\n" ".otherFn();"); - AssertThat(ts_node_string(root), Equals( + AssertThat(ts_node_string(root, doc), Equals( "(DOCUMENT " "(expression_statement (function_call " "(member_access (function_call (identifier)) " @@ -225,7 +209,7 @@ describe("Parser", [&]() { before_each([&]() { set_text("x ^ (100 + abc)"); - AssertThat(ts_node_string(root), Equals( + AssertThat(ts_node_string(root, doc), Equals( "(DOCUMENT (exponent " "(variable) " "(group (sum (number) (variable)))))")); @@ -234,7 +218,7 @@ describe("Parser", [&]() { }); it("updates the parse tree", [&]() { - AssertThat(ts_node_string(root), Equals( + AssertThat(ts_node_string(root, doc), Equals( "(DOCUMENT (exponent " "(variable) " "(group (sum (number) (product (variable) (number))))))")); @@ -251,7 +235,7 @@ describe("Parser", [&]() { set_text("123 * 456 ^ (10 + x)"); - AssertThat(ts_node_string(root), Equals( + AssertThat(ts_node_string(root, doc), Equals( "(DOCUMENT (product " "(number) " "(exponent (number) (group (sum (number) (variable))))))")); @@ -260,7 +244,7 @@ describe("Parser", [&]() { }); it("updates the parse tree", [&]() { - AssertThat(ts_node_string(root), Equals( + AssertThat(ts_node_string(root, doc), Equals( "(DOCUMENT (sum " "(number) " "(product " @@ -279,18 +263,18 @@ describe("Parser", [&]() { set_text("var x = y;"); - AssertThat(ts_node_string(root), Equals( + AssertThat(ts_node_string(root, doc), Equals( "(DOCUMENT (var_declaration (var_assignment " "(identifier) (identifier))))")); insert_text(strlen("var x = y"), " *"); - AssertThat(ts_node_string(root), Equals( + AssertThat(ts_node_string(root, doc), Equals( "(DOCUMENT (var_declaration (ERROR (identifier) (identifier) (UNEXPECTED ';'))))")); insert_text(strlen("var x = y *"), " z"); - AssertThat(ts_node_string(root), Equals( + AssertThat(ts_node_string(root, doc), Equals( "(DOCUMENT (var_declaration (var_assignment " "(identifier) (math_op (identifier) (identifier)))))")); }); @@ -300,20 +284,19 @@ describe("Parser", [&]() { before_each([&]() { set_text("abc * 123"); - AssertThat(ts_node_string(root), Equals( + AssertThat(ts_node_string(root, doc), Equals( "(DOCUMENT (product (variable) (number)))")); insert_text(strlen("ab"), "XYZ"); }); it("updates the parse tree", [&]() { - AssertThat(ts_node_string(root), Equals( + AssertThat(ts_node_string(root, doc), Equals( "(DOCUMENT (product (variable) (number)))")); - TSNode *node = ts_node_find_for_pos(root, 1); - AssertThat(ts_node_name(node), Equals("variable")); + TSNode node = ts_node_find_for_pos(root, 1); + AssertThat(ts_node_name(node, doc), Equals("variable")); AssertThat(ts_node_size(node).bytes, Equals(strlen("abXYZc"))); - ts_node_release(node); }); }); @@ -321,20 +304,19 @@ describe("Parser", [&]() { before_each([&]() { set_text("abc * 123"); - AssertThat(ts_node_string(root), Equals( + AssertThat(ts_node_string(root, doc), Equals( "(DOCUMENT (product (variable) (number)))")); insert_text(strlen("abc"), "XYZ"); }); it("updates the parse tree", [&]() { - AssertThat(ts_node_string(root), Equals( + AssertThat(ts_node_string(root, doc), Equals( "(DOCUMENT (product (variable) (number)))")); - TSNode *node = ts_node_find_for_pos(root, 1); - AssertThat(ts_node_name(node), Equals("variable")); + TSNode node = ts_node_find_for_pos(root, 1); + AssertThat(ts_node_name(node, doc), Equals("variable")); AssertThat(ts_node_size(node).bytes, Equals(strlen("abcXYZ"))); - ts_node_release(node); }); }); @@ -343,7 +325,7 @@ describe("Parser", [&]() { // αβδ + 1 set_text("\u03b1\u03b2\u03b4 + 1"); - AssertThat(ts_node_string(root), Equals( + AssertThat(ts_node_string(root, doc), Equals( "(DOCUMENT (sum (variable) (number)))")); // αβδ + ψ1 @@ -351,7 +333,7 @@ describe("Parser", [&]() { }); it("inserts the text according to the UTF8 character index", [&]() { - AssertThat(ts_node_string(root), Equals( + AssertThat(ts_node_string(root, doc), Equals( "(DOCUMENT (sum (variable) (variable)))")); }); }); @@ -362,7 +344,7 @@ describe("Parser", [&]() { "# a-comment\n" "abc"); - AssertThat(ts_node_string(root), Equals( + AssertThat(ts_node_string(root, doc), Equals( "(DOCUMENT (product (number) (comment) (variable)))")); insert_text( @@ -373,7 +355,7 @@ describe("Parser", [&]() { }); it("updates the parse tree", [&]() { - AssertThat(ts_node_string(root), Equals( + AssertThat(ts_node_string(root, doc), Equals( "(DOCUMENT (product (number) (comment) (variable)))")); }); }); @@ -384,14 +366,14 @@ describe("Parser", [&]() { before_each([&]() { set_text("123 * 456"); - AssertThat(ts_node_string(root), Equals( + AssertThat(ts_node_string(root, doc), Equals( "(DOCUMENT (product (number) (number)))")); delete_text(strlen("123 "), 2); }); it("updates the parse tree, creating an error", [&]() { - AssertThat(ts_node_string(root), Equals( + AssertThat(ts_node_string(root, doc), Equals( "(DOCUMENT (number) (ERROR (UNEXPECTED '4') (number)))")); }); }); @@ -403,13 +385,13 @@ describe("Parser", [&]() { set_text("{ x: (b.c) };"); - AssertThat(ts_node_string(root), Equals( + AssertThat(ts_node_string(root, doc), Equals( "(DOCUMENT (expression_statement (object (pair " "(identifier) (expression (member_access (identifier) (identifier)))))))")); replace_text(strlen("{ x: "), strlen("(b.c)"), "b.c"); - AssertThat(ts_node_string(root), Equals( + AssertThat(ts_node_string(root, doc), Equals( "(DOCUMENT (expression_statement (object (pair " "(identifier) (member_access (identifier) (identifier))))))")); }); @@ -425,16 +407,13 @@ describe("Parser", [&]() { it("terminates them at the end of the document", [&]() { set_text("x # this is a comment"); - AssertThat(ts_node_string(root), Equals("(DOCUMENT " + AssertThat(ts_node_string(root, doc), Equals("(DOCUMENT " "(expression (variable) (comment)))")); - TSNode *expression = ts_node_child(root, 0); - TSNode *comment = ts_node_child(expression, 1); + TSNode expression = ts_node_child(root, 0); + TSNode comment = ts_node_child(expression, 1); AssertThat(ts_node_size(comment).bytes, Equals(strlen("# this is a comment"))); - - ts_node_release(expression); - ts_node_release(comment); }); }); @@ -442,7 +421,7 @@ describe("Parser", [&]() { // x # ΩΩΩ — ΔΔ set_text("x # \u03A9\u03A9\u03A9 \u2014 \u0394\u0394"); - AssertThat(ts_node_string(root), Equals("(DOCUMENT " + AssertThat(ts_node_string(root, doc), Equals("(DOCUMENT " "(expression (variable) (comment)))")); AssertThat(ts_node_size(root).chars, Equals(strlen("x # OOO - DD"))); diff --git a/src/runtime/document.c b/src/runtime/document.c index aa50d9a0..f8989ef9 100644 --- a/src/runtime/document.c +++ b/src/runtime/document.c @@ -1,13 +1,9 @@ #include "tree_sitter/parser.h" #include "runtime/node.h" +#include "runtime/length.h" #include "runtime/parser.h" #include "runtime/string_input.h" - -struct TSDocument { - TSParser parser; - TSInput input; - TSNode *node; -}; +#include "runtime/document.h" TSDocument *ts_document_make() { TSDocument *document = calloc(sizeof(TSDocument), 1); @@ -19,19 +15,18 @@ void ts_document_free(TSDocument *document) { ts_parser_destroy(&document->parser); if (document->input.release_fn) document->input.release_fn(document->input.data); - if (document->node) - ts_node_release(document->node); + if (document->tree) + ts_tree_release(document->tree); free(document); } static void reparse(TSDocument *document, TSInputEdit *edit) { if (document->input.read_fn && document->parser.language) { - const TSTree *tree = - ts_parser_parse(&document->parser, document->input, edit); - if (document->node) - ts_node_release(document->node); - document->node = - ts_node_make_root(tree, document->parser.language->symbol_names); + TSTree *tree = ts_parser_parse(&document->parser, document->input, edit); + if (document->tree) + ts_tree_release(document->tree); + document->tree = tree; + ts_tree_retain(tree); } } @@ -66,6 +61,9 @@ void ts_document_set_input_string(TSDocument *document, const char *text) { ts_document_set_input(document, ts_string_input_make(text)); } -TSNode *ts_document_root_node(const TSDocument *document) { - return document->node; +TSNode ts_document_root_node(const TSDocument *document) { + if (document->tree) + return ts_node_make(document->tree, document->tree->padding); + else + return ts_node_null(); } diff --git a/src/runtime/document.h b/src/runtime/document.h new file mode 100644 index 00000000..b137d076 --- /dev/null +++ b/src/runtime/document.h @@ -0,0 +1,14 @@ +#ifndef RUNTIME_DOCUMENT_H_ +#define RUNTIME_DOCUMENT_H_ + +#include "tree_sitter/parser.h" +#include "runtime/parser.h" +#include "runtime/tree.h" + +struct TSDocument { + TSParser parser; + TSInput input; + TSTree *tree; +}; + +#endif diff --git a/src/runtime/node.c b/src/runtime/node.c index 785d566f..af0abf75 100644 --- a/src/runtime/node.c +++ b/src/runtime/node.c @@ -2,105 +2,129 @@ #include "runtime/node.h" #include "runtime/length.h" #include "runtime/tree.h" +#include "runtime/document.h" -TSNode *ts_node_make(const TSTree *tree, TSNode *parent, size_t index, - TSLength position, const char **names) { - if (parent) - ts_node_retain(parent); - TSNode *result = malloc(sizeof(TSNode)); - *result = (TSNode){ - .ref_count = 1, - .parent = parent, - .index = index, - .content = tree, - .position = position, - .names = names, +TSNode ts_node_make(const TSTree *tree, TSLength position) { + return (TSNode){.data = tree, .position = position }; +} + +static inline const TSTree *get_tree(TSNode tree) { + return tree.data; +} + +TSLength ts_node_pos(TSNode tree) { + return tree.position; +} + +TSLength ts_node_size(TSNode tree) { + return get_tree(tree)->size; +} + +bool ts_node_eq(TSNode left, TSNode right) { + return ts_tree_eq(get_tree(left), get_tree(right)) && + ts_length_eq(left.position, right.position); +} + +const char *ts_node_name(TSNode tree, const TSDocument *document) { + return document->parser.language->symbol_names[get_tree(tree)->symbol]; +} + +const char *ts_node_string(TSNode tree, const TSDocument *document) { + return ts_tree_string(get_tree(tree), document->parser.language->symbol_names); +} + +typedef struct { + TSNode ref; + size_t index; +} ParentWithIndex; + +static inline ParentWithIndex ts_node_parent_with_index(TSNode ref) { + const TSTree *tree = get_tree(ref); + size_t index = 0; + TSLength position = ts_length_sub(ref.position, tree->padding); + + do { + TSTree *parent = tree->parent; + if (!parent) + return (ParentWithIndex){ ts_node_null(), 0 }; + + for (size_t i = 0; i < parent->child_count; i++) { + 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; + } + position = ts_length_sub(position, ts_tree_total_size(child)); + } + tree = parent; + } while (!ts_tree_is_visible(tree)); + + return (ParentWithIndex){ + ts_node_make(tree, ts_length_add(position, tree->padding)), index }; - return result; } -TSNode *ts_node_make_root(const TSTree *tree, const char **names) { - return ts_node_make(tree, NULL, 0, tree->padding, names); +TSNode ts_node_parent(TSNode ref) { + return ts_node_parent_with_index(ref).ref; } -void ts_node_retain(TSNode *node) { node->ref_count++; } - -void ts_node_release(TSNode *node) { - node->ref_count--; - if (node->ref_count == 0) { - if (node->parent) - ts_node_release(node->parent); - free(node); - } -} - -TSLength ts_node_pos(const TSNode *node) { return node->position; } - -TSLength ts_node_size(const TSNode *node) { return node->content->size; } - -bool ts_node_eq(const TSNode *left, const TSNode *right) { - return ts_tree_eq(left->content, right->content); -} - -const char *ts_node_name(const TSNode *node) { - return node->names[node->content->symbol]; -} - -const char *ts_node_string(const TSNode *node) { - return ts_tree_string(node->content, node->names); -} - -TSNode *ts_node_parent(TSNode *child) { return child->parent; } - -TSNode *ts_node_prev_sibling(TSNode *child) { - if (child->parent) - return ts_node_child(child->parent, child->index - 1); +TSNode ts_node_prev_sibling(TSNode ref) { + ParentWithIndex parent = ts_node_parent_with_index(ref); + if (parent.ref.data && parent.index > 0) + return ts_node_child(parent.ref, parent.index - 1); else - return NULL; + return ts_node_null(); } -TSNode *ts_node_next_sibling(TSNode *child) { - if (child->parent) - return ts_node_child(child->parent, child->index + 1); +TSNode ts_node_next_sibling(TSNode ref) { + ParentWithIndex parent = ts_node_parent_with_index(ref); + if (parent.ref.data) + return ts_node_child(parent.ref, parent.index + 1); else - return NULL; + return ts_node_null(); } -size_t ts_node_child_count(const TSNode *parent) { +size_t ts_node_child_count(TSNode parent) { size_t result; - ts_tree_visible_children(parent->content, &result); + ts_tree_visible_children(get_tree(parent), &result); return result; } -TSNode *ts_node_child(TSNode *parent, size_t i) { +TSNode ts_node_child(TSNode ref, size_t i) { size_t count; - TSTreeChild *children = ts_tree_visible_children(parent->content, &count); + TSTreeChild *children = ts_tree_visible_children(get_tree(ref), &count); if (i >= count) - return NULL; - TSLength pos = ts_length_add(parent->position, children[i].offset); - return ts_node_make(children[i].tree, parent, i, pos, parent->names); + return ts_node_null(); + TSLength position = ts_length_add(ref.position, children[i].offset); + return ts_node_make(children[i].tree, position); } -TSNode *ts_node_find_for_range(TSNode *parent, size_t min, size_t max) { - size_t count; - TSTreeChild *children = ts_tree_visible_children(parent->content, &count); - for (size_t i = 0; i < count; i++) { - TSTreeChild child = children[i]; - TSLength pos = ts_length_add(parent->position, child.offset); - if (pos.chars > min) - break; - if (pos.chars + child.tree->size.chars > max) { - TSNode *node = ts_node_make(child.tree, parent, i, pos, parent->names); - TSNode *result = ts_node_find_for_range(node, min, max); - ts_node_release(node); - return result; +TSNode ts_node_find_for_range(TSNode ref, 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(ref), &count); + + for (size_t i = 0; i < count; i++) { + TSTreeChild child = children[i]; + TSLength position = ts_length_add(ref.position, child.offset); + if (position.chars > min) + break; + if (position.chars + child.tree->size.chars > max) { + ref = ts_node_make(child.tree, position); + did_descend = true; + } } } - - ts_node_retain(parent); - return parent; + return ref; } -TSNode *ts_node_find_for_pos(TSNode *parent, size_t position) { - return ts_node_find_for_range(parent, position, position); +TSNode ts_node_find_for_pos(TSNode ref, size_t position) { + return ts_node_find_for_range(ref, position, position); } diff --git a/src/runtime/node.h b/src/runtime/node.h index 467b89a3..c9990df0 100644 --- a/src/runtime/node.h +++ b/src/runtime/node.h @@ -2,19 +2,13 @@ #define RUNTIME_NODE_H_ #include "tree_sitter/parser.h" +#include "runtime/length.h" #include "runtime/tree.h" -struct TSNode { - size_t ref_count; - size_t index; - TSLength position; - const TSTree *content; - struct TSNode *parent; - const char **names; -}; +TSNode ts_node_make(const TSTree *, TSLength); -TSNode *ts_node_make(const TSTree *tree, TSNode *parent, size_t index, - TSLength position, const char **names); -TSNode *ts_node_make_root(const TSTree *tree, const char **names); +static inline TSNode ts_node_null() { + return (TSNode){.data = NULL, .position = ts_length_zero() }; +} #endif diff --git a/src/runtime/parser.c b/src/runtime/parser.c index 167f7c87..60668f80 100644 --- a/src/runtime/parser.c +++ b/src/runtime/parser.c @@ -431,8 +431,7 @@ ParserNextResult ts_parser_next(TSParser *parser, int head_to_advance) { return result; } -const TSTree *ts_parser_parse(TSParser *parser, TSInput input, - TSInputEdit *edit) { +TSTree *ts_parser_parse(TSParser *parser, TSInput input, TSInputEdit *edit) { TSLength position; if (edit) { DEBUG("edit pos:%lu, inserted:%lu, deleted:%lu", edit->position, diff --git a/src/runtime/parser.h b/src/runtime/parser.h index 1fe25929..3e408129 100644 --- a/src/runtime/parser.h +++ b/src/runtime/parser.h @@ -21,7 +21,7 @@ TSParser ts_parser_make(); void ts_parser_destroy(TSParser *); TSDebugger ts_parser_get_debugger(const TSParser *); void ts_parser_set_debugger(TSParser *, TSDebugger); -const TSTree *ts_parser_parse(TSParser *, TSInput, TSInputEdit *); +TSTree *ts_parser_parse(TSParser *, TSInput, TSInputEdit *); #ifdef __cplusplus } diff --git a/src/runtime/tree.c b/src/runtime/tree.c index 4cdd2fd6..de583265 100644 --- a/src/runtime/tree.c +++ b/src/runtime/tree.c @@ -64,7 +64,7 @@ TSTree *ts_tree_make_node(TSSymbol symbol, size_t child_count, } else { if (is_hidden) options |= TSTreeOptionsHidden; - if (child_count == 1 && + if (child_count == 1 && symbol != ts_builtin_sym_document && (ts_tree_is_visible(children[0]) || ts_tree_is_wrapper(children[0]))) options |= (TSTreeOptionsWrapper | TSTreeOptionsHidden); if (child_count > 0) { @@ -82,6 +82,7 @@ TSTree *ts_tree_make_node(TSSymbol symbol, size_t child_count, TSTree *result = malloc(sizeof(TSTree) + (visible_child_count * sizeof(TSTreeChild))); *result = (TSTree){.ref_count = 1, + .parent = NULL, .symbol = symbol, .children = children, .child_count = child_count, @@ -98,6 +99,7 @@ TSTree *ts_tree_make_node(TSSymbol symbol, size_t child_count, 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 (i > 0) offset = ts_length_add(offset, child->padding); diff --git a/src/runtime/tree.h b/src/runtime/tree.h index 9b39e710..b66ad9b9 100644 --- a/src/runtime/tree.h +++ b/src/runtime/tree.h @@ -17,10 +17,7 @@ typedef enum { } TSTreeOptions; struct TSTree { - TSSymbol symbol; - TSTreeOptions options; - TSLength padding; - TSLength size; + struct TSTree *parent; size_t child_count; union { struct { @@ -29,6 +26,10 @@ struct TSTree { }; char lookahead_char; }; + TSLength padding; + TSLength size; + TSSymbol symbol; + TSTreeOptions options; unsigned short int ref_count; };