Make ts_tree_edit return a new tree rather than mutating its argument

Co-Authored-By: Rick Winfrey <rewinfrey@github.com>
This commit is contained in:
Max Brunsfeld 2018-05-10 12:23:05 -07:00
parent df79ff5997
commit 09e663c7d1
4 changed files with 59 additions and 37 deletions

View file

@ -97,7 +97,7 @@ void ts_document_edit(TSDocument *self, TSInputEdit edit) {
if (edit.bytes_removed > max_bytes - edit.start_byte)
edit.bytes_removed = max_bytes - edit.start_byte;
ts_tree_edit(self->tree, &edit);
self->tree = ts_tree_edit(self->tree, &edit, &self->parser.tree_pool);
if (self->parser.print_debugging_graphs) {
ts_tree_print_dot_graph(self->tree, self->parser.language, stderr);

View file

@ -58,8 +58,9 @@ bool ts_tree_array_copy(TreeArray self, TreeArray *dest) {
if (self.capacity > 0) {
contents = ts_calloc(self.capacity, sizeof(Tree *));
memcpy(contents, self.contents, self.size * sizeof(Tree *));
for (uint32_t i = 0; i < self.size; i++)
for (uint32_t i = 0; i < self.size; i++) {
ts_tree_retain(contents[i]);
}
}
dest->size = self.size;
@ -172,10 +173,23 @@ Tree *ts_tree_make_error(TreePool *pool, Length size, Length padding, int32_t lo
Tree *ts_tree_make_copy(TreePool *pool, Tree *self) {
Tree *result = ts_tree_pool_allocate(pool);
*result = *self;
if (result->children.size > 0) {
ts_tree_array_copy(self->children, &result->children);
}
result->ref_count = 1;
return result;
}
static Tree *ts_tree_make_mut(TreePool *pool, Tree *self) {
if (self->ref_count == 1) {
return self;
} else {
Tree *result = ts_tree_make_copy(pool, self);
ts_tree_release(pool, self);
return result;
}
}
static void ts_tree__compress(Tree *self, unsigned count, const TSLanguage *language, TreeArray *stack) {
unsigned initial_stack_size = stack->size;
@ -438,42 +452,48 @@ int ts_tree_compare(const Tree *left, const Tree *right) {
return 0;
}
void ts_tree_invalidate_lookahead(Tree *self, uint32_t edit_byte_offset) {
if (edit_byte_offset >= self->bytes_scanned) return;
self->has_changes = true;
if (self->children.size > 0) {
Tree *ts_tree_invalidate_lookahead(Tree *self, uint32_t edit_byte_offset, TreePool *pool) {
if (edit_byte_offset >= self->bytes_scanned) return self;
Tree *result = ts_tree_make_mut(pool, self);
result->has_changes = true;
if (result->children.size > 0) {
uint32_t child_start_byte = 0;
for (uint32_t i = 0; i < self->children.size; i++) {
Tree *child = self->children.contents[i];
for (uint32_t i = 0; i < result->children.size; i++) {
Tree **child = &result->children.contents[i];
if (child_start_byte > edit_byte_offset) break;
ts_tree_invalidate_lookahead(child, edit_byte_offset - child_start_byte);
child_start_byte += ts_tree_total_bytes(child);
*child = ts_tree_invalidate_lookahead(*child, edit_byte_offset - child_start_byte, pool);
child_start_byte += ts_tree_total_bytes(*child);
}
}
return result;
}
void ts_tree__edit(Tree *self, Edit edit) {
Tree *ts_tree__edit(Tree *self, Edit edit, TreePool *pool) {
Length new_end = length_add(edit.start, edit.added);
Length old_end = length_add(edit.start, edit.removed);
self->has_changes = true;
Tree *result = ts_tree_make_mut(pool, self);
result->has_changes = true;
if (old_end.bytes <= self->padding.bytes) {
self->padding = length_add(new_end, length_sub(self->padding, old_end));
} else if (edit.start.bytes < self->padding.bytes) {
self->size = length_sub(self->size, length_sub(old_end, self->padding));
self->padding = new_end;
} else if (edit.start.bytes == self->padding.bytes && edit.removed.bytes == 0) {
self->padding = length_add(self->padding, edit.added);
if (old_end.bytes <= result->padding.bytes) {
result->padding = length_add(new_end, length_sub(result->padding, old_end));
} else if (edit.start.bytes < result->padding.bytes) {
result->size = length_sub(result->size, length_sub(old_end, result->padding));
result->padding = new_end;
} else if (edit.start.bytes == result->padding.bytes && edit.removed.bytes == 0) {
result->padding = length_add(result->padding, edit.added);
} else {
Length new_total_size = length_add(new_end, length_sub(ts_tree_total_size(self), old_end));
self->size = length_sub(new_total_size, self->padding);
Length new_total_size = length_add(new_end, length_sub(ts_tree_total_size(result), old_end));
result->size = length_sub(new_total_size, result->padding);
}
Length child_left, child_right = length_zero();
for (uint32_t i = 0; i < self->children.size; i++) {
Tree *child = self->children.contents[i];
Length child_size = ts_tree_total_size(child);
for (uint32_t i = 0; i < result->children.size; i++) {
Tree **child = &result->children.contents[i];
Length child_size = ts_tree_total_size(*child);
child_left = child_right;
child_right = length_add(child_left, child_size);
@ -499,19 +519,21 @@ void ts_tree__edit(Tree *self, Edit edit) {
edit.added = length_zero();
edit.removed = length_sub(edit.removed, child_edit.removed);
ts_tree__edit(child, child_edit);
*child = ts_tree__edit(*child, child_edit, pool);
} else if (child_left.bytes <= edit.start.bytes) {
ts_tree_invalidate_lookahead(child, edit.start.bytes - child_left.bytes);
*child = ts_tree_invalidate_lookahead(*child, edit.start.bytes - child_left.bytes, pool);
}
}
return result;
}
void ts_tree_edit(Tree *self, const TSInputEdit *edit) {
ts_tree__edit(self, (Edit) {
Tree *ts_tree_edit(Tree *self, const TSInputEdit *edit, TreePool *pool) {
return ts_tree__edit(self, (Edit) {
.start = {edit->start_byte, edit->start_point},
.added = {edit->bytes_added, edit->extent_added},
.removed = {edit->bytes_removed, edit->extent_removed},
});
}, pool);
}
Tree *ts_tree_last_external_token(Tree *tree) {

View file

@ -100,7 +100,7 @@ bool ts_tree_eq(const Tree *tree1, const Tree *tree2);
int ts_tree_compare(const Tree *tree1, const Tree *tree2);
void ts_tree_set_children(Tree *, TreeArray *, const TSLanguage *);
void ts_tree_balance(Tree *, TreePool *, const TSLanguage *);
void ts_tree_edit(Tree *, const TSInputEdit *edit);
Tree *ts_tree_edit(Tree *, const TSInputEdit *edit, TreePool *);
char *ts_tree_string(const Tree *, const TSLanguage *, bool include_all);
void ts_tree_print_dot_graph(const Tree *, const TSLanguage *, FILE *);
Tree *ts_tree_last_external_token(Tree *);

View file

@ -178,7 +178,7 @@ describe("Tree", []() {
});
describe("edit", [&]() {
Tree *tree = nullptr;
Tree *tree;
before_each([&]() {
tree = ts_tree_make_node(&pool, symbol1, tree_array({
@ -204,7 +204,7 @@ describe("Tree", []() {
edit.start_point = {0, 1};
edit.extent_removed = {0, 0};
edit.extent_added = {0, 1};
ts_tree_edit(tree, &edit);
tree = ts_tree_edit(tree, &edit, &pool);
assert_consistent(tree);
AssertThat(tree->has_changes, IsTrue());
@ -230,7 +230,7 @@ describe("Tree", []() {
edit.start_point = {0, 1};
edit.extent_removed = {0, 3};
edit.extent_added = {0, 4};
ts_tree_edit(tree, &edit);
tree = ts_tree_edit(tree, &edit, &pool);
assert_consistent(tree);
AssertThat(tree->has_changes, IsTrue());
@ -252,7 +252,7 @@ describe("Tree", []() {
edit.start_point = {0, 2};
edit.extent_removed = {0, 0};
edit.extent_added = {0, 2};
ts_tree_edit(tree, &edit);
tree = ts_tree_edit(tree, &edit, &pool);
assert_consistent(tree);
AssertThat(tree->has_changes, IsTrue());
@ -276,7 +276,7 @@ describe("Tree", []() {
edit.start_point = {0, 2};
edit.extent_removed = {0, 2};
edit.extent_added = {0, 5};
ts_tree_edit(tree, &edit);
tree = ts_tree_edit(tree, &edit, &pool);
assert_consistent(tree);
AssertThat(tree->has_changes, IsTrue());
@ -300,7 +300,7 @@ describe("Tree", []() {
edit.start_point = {0, 1};
edit.extent_removed = {0, 10};
edit.extent_added = {0, 3};
ts_tree_edit(tree, &edit);
tree = ts_tree_edit(tree, &edit, &pool);
assert_consistent(tree);
AssertThat(tree->has_changes, IsTrue());
@ -332,7 +332,7 @@ describe("Tree", []() {
edit.start_point = {0, 6};
edit.extent_removed = {0, 1};
edit.extent_added = {0, 1};
ts_tree_edit(tree, &edit);
tree = ts_tree_edit(tree, &edit, &pool);
assert_consistent(tree);
AssertThat(tree->children.contents[0]->has_changes, IsTrue());