Add ts_node_edit API

This commit is contained in:
Max Brunsfeld 2018-07-11 16:17:46 -07:00
parent 308016b776
commit 9e8bec458d
6 changed files with 132 additions and 2 deletions

View file

@ -131,6 +131,7 @@ TSNode ts_node_descendant_for_byte_range(TSNode, uint32_t, uint32_t);
TSNode ts_node_named_descendant_for_byte_range(TSNode, uint32_t, uint32_t);
TSNode ts_node_descendant_for_point_range(TSNode, TSPoint, TSPoint);
TSNode ts_node_named_descendant_for_point_range(TSNode, TSPoint, TSPoint);
void ts_node_edit(TSNode *, const TSInputEdit *);
TSTreeCursor ts_tree_cursor_new(TSNode);
void ts_tree_cursor_delete(TSTreeCursor *);

View file

@ -494,3 +494,20 @@ TSNode ts_node_named_descendant_for_point_range(TSNode self, TSPoint min,
TSPoint max) {
return ts_node__descendant_for_point_range(self, min, max, false);
}
void ts_node_edit(TSNode *self, const TSInputEdit *edit) {
uint32_t start_byte = ts_node_start_byte(*self);
TSPoint start_point = ts_node_start_point(*self);
if (start_byte >= edit->old_end_byte) {
start_byte = edit->new_end_byte + (start_byte - edit->old_end_byte);
start_point = point_add(edit->new_end_point, point_sub(start_point, edit->old_end_point));
} else if (start_byte > edit->start_byte) {
start_byte = edit->new_end_byte;
start_point = edit->new_end_point;
}
self->context[0] = start_byte;
self->context[1] = start_point.row;
self->context[2] = start_point.column;
}

View file

@ -7,6 +7,16 @@
#include "compiler/lexical_grammar.h"
#include "compiler/build_tables/parse_item.h"
#include "compiler/build_tables/lex_item.h"
#include "helpers/point_helpers.h"
ostream &operator<<(ostream &stream, const TSInputEdit &edit) {
return stream << "{TSInputEdit start_byte: " << edit.start_byte <<
", old_end_byte: " << edit.old_end_byte <<
", new_end_byte: " << edit.new_end_byte <<
", start_point: " << edit.start_point <<
", old_end_point: " << edit.old_end_point <<
", new_end_point: " << edit.new_end_point << "}";
}
namespace tree_sitter {

View file

@ -7,6 +7,7 @@
#include <map>
#include <unordered_set>
#include <vector>
#include "tree_sitter/runtime.h"
#include "compiler/grammar.h"
#include "compiler/prepare_grammar/interned_grammar.h"
#include "compiler/prepare_grammar/initial_syntax_grammar.h"
@ -91,6 +92,8 @@ inline std::ostream& operator<<(std::ostream &stream, const std::pair<T1, T2> &p
} // namespace std
std::ostream &operator<<(std::ostream &, const TSInputEdit &);
namespace tree_sitter {
using std::ostream;

View file

@ -46,7 +46,10 @@ ostream &operator<<(ostream &stream, const TSNode &node) {
}
bool operator==(const TSNode &left, const TSNode &right) {
return ts_node_eq(left, right);
return
left.id == right.id &&
ts_node_start_byte(left) == ts_node_start_byte(right) &&
ts_node_start_point(left) == ts_node_start_point(right);
}
bool operator==(const std::vector<const Subtree *> &vec, const SubtreeArray &array) {

View file

@ -1,4 +1,3 @@
#include "test_helper.h"
#include "runtime/alloc.h"
#include "helpers/tree_helpers.h"
@ -6,6 +5,8 @@
#include "helpers/load_language.h"
#include "helpers/record_alloc.h"
#include "helpers/stream_methods.h"
#include "helpers/random_helpers.h"
#include "helpers/spy_input.h"
START_TEST
@ -556,6 +557,101 @@ describe("Node", [&]() {
AssertThat(ts_node_start_point(array_node), Equals<TSPoint>({7, 0}));
});
});
describe("edit(edit)", [&]() {
vector<pair<string, TSInputEdit>> test_table = {
{
"insert 5 lines at the beginning",
{
0, 0, 5,
{0, 0}, {0, 0}, {5, 0}
},
},
{
"delete first 5 lines",
{
0, (uint32_t)object_index, 0,
{0, 0}, {5, 2}, {0, 0}
},
},
{
"replace entire text",
{
0, (uint32_t)json_string.size(), 5,
{0, 0}, {9, 0}, {0, 5}
}
}
};
auto get_all_nodes = [&]() {
vector<TSNode> result;
bool visited_children = false;
TSTreeCursor cursor = ts_tree_cursor_new(ts_tree_root_node(tree));
while (true) {
result.push_back(ts_tree_cursor_current_node(&cursor));
if (!visited_children && ts_tree_cursor_goto_first_child(&cursor)) continue;
if (ts_tree_cursor_goto_next_sibling(&cursor)) {
visited_children = false;
} else if (ts_tree_cursor_goto_parent(&cursor)) {
visited_children = true;
} else {
break;
}
}
ts_tree_cursor_delete(&cursor);
return result;
};
for (auto &entry : test_table) {
const string &description = entry.first;
const TSInputEdit &edit = entry.second;
it(("updates the node's start position according to edit - " + description).c_str(), [&]() {
auto nodes_before = get_all_nodes();
ts_tree_edit(tree, &edit);
for (TSNode &node : nodes_before) {
ts_node_edit(&node, &edit);
}
auto nodes_after = get_all_nodes();
for (unsigned i = 0; i < nodes_before.size(); i++) {
TSNode &node_before = nodes_before[i];
TSNode &node_after = nodes_after[i];
AssertThat(node_before, Equals(node_after));
}
});
}
it("updates the node's start position according to edit - random edits", [&]() {
SpyInput input(json_string, 3);
for (unsigned i = 0; i < 10; i++) {
auto nodes_before = get_all_nodes();
size_t edit_start = default_generator(input.content.size());
size_t deletion_size = default_generator(2) ? 0 : default_generator(input.content.size() - edit_start);
string inserted_text = default_generator.words(default_generator(4) + 1);
TSInputEdit edit = input.replace(edit_start, deletion_size, inserted_text);
ts_tree_edit(tree, &edit);
for (TSNode &node : nodes_before) {
ts_node_edit(&node, &edit);
}
auto nodes_after = get_all_nodes();
for (unsigned i = 0; i < nodes_before.size(); i++) {
TSNode &node_before = nodes_before[i];
TSNode &node_after = nodes_after[i];
AssertThat(node_before, Equals(node_after));
}
}
});
});
});
describe("TreeCursor", [&]() {