Add ts_tree_edit function

This commit is contained in:
Max Brunsfeld 2015-09-15 16:00:16 -07:00
parent 296d8cc1e8
commit 0467d190fe
5 changed files with 234 additions and 42 deletions

View file

@ -8,6 +8,10 @@ static inline TSLength ts_length_add(TSLength len1, TSLength len2) {
TSLength result;
result.bytes = len1.bytes + len2.bytes;
result.chars = len1.chars + len2.chars;
if ((len1.chars > 0 && len1.bytes == 0) || (len2.chars > 0 && len2.bytes == 0))
result.bytes = 0;
return result;
}
@ -15,6 +19,10 @@ static inline TSLength ts_length_sub(TSLength len1, TSLength len2) {
TSLength result;
result.bytes = len1.bytes - len2.bytes;
result.chars = len1.chars - len2.chars;
if ((len1.chars > 0 && len1.bytes == 0) || (len2.chars > 0 && len2.bytes == 0))
result.bytes = 0;
return result;
}

View file

@ -81,7 +81,7 @@ static TSTree *ts_lexer__accept(TSLexer *lexer, TSSymbol symbol,
return ts_tree_make_error(size, padding, lexer->lookahead);
} else {
DEBUG("accept_token sym:%s", symbol_name);
return ts_tree_make_leaf(symbol, size, padding, node_type);
return ts_tree_make_leaf(symbol, padding, size, node_type);
}
}

View file

@ -6,7 +6,7 @@
#include "runtime/tree.h"
#include "runtime/length.h"
TSTree *ts_tree_make_leaf(TSSymbol sym, TSLength size, TSLength padding,
TSTree *ts_tree_make_leaf(TSSymbol sym, TSLength padding, TSLength size,
TSNodeType node_type) {
TSTree *result = malloc(sizeof(TSTree));
*result = (TSTree){
@ -31,7 +31,7 @@ TSTree *ts_tree_make_leaf(TSSymbol sym, TSLength size, TSLength padding,
TSTree *ts_tree_make_error(TSLength size, TSLength padding, char lookahead_char) {
TSTree *result =
ts_tree_make_leaf(ts_builtin_sym_error, size, padding, TSNodeTypeNamed);
ts_tree_make_leaf(ts_builtin_sym_error, padding, size, TSNodeTypeNamed);
result->lookahead_char = lookahead_char;
return result;
}
@ -194,3 +194,71 @@ void ts_tree_prepend_children(TSTree *tree, size_t count, TSTree **children) {
ts_tree__set_children(tree, new_children, new_child_count);
}
static inline long min(long a, long b) {
return a <= b ? a : b;
}
void ts_tree_edit(TSTree *tree, TSInputEdit edit) {
size_t start = edit.position;
size_t old_end = edit.position + edit.chars_removed;
size_t new_end = edit.position + edit.chars_inserted;
assert(start >= 0);
assert(old_end <= ts_tree_total_size(tree).chars);
tree->options.has_changes = true;
if (start < tree->padding.chars) {
tree->padding.bytes = 0;
long remaining_padding = tree->padding.chars - old_end;
if (remaining_padding >= 0) {
tree->padding.chars = new_end + remaining_padding;
} else {
tree->padding.chars = new_end;
tree->size.chars += remaining_padding;
tree->size.bytes = 0;
}
} else if (start == tree->padding.chars && edit.chars_removed == 0) {
tree->padding.bytes = 0;
tree->padding.chars += edit.chars_inserted;
} else {
tree->size.bytes = 0;
tree->size.chars += (edit.chars_inserted - edit.chars_removed);
}
bool found_first_child = false;
long remainder_to_delete = edit.chars_removed - edit.chars_inserted;
size_t child_left = 0, child_right = 0;
for (size_t i = 0; i < tree->child_count; i++) {
TSTree *child = tree->children[i];
size_t child_size = ts_tree_total_size(child).chars;
child_left = child_right;
child_right += child_size;
if (!found_first_child) {
if (child_right >= start) {
found_first_child = true;
size_t chars_removed = min(edit.chars_removed, child_right - start);
remainder_to_delete -= (chars_removed - edit.chars_inserted);
ts_tree_edit(child, (TSInputEdit){
.position = start - child_left,
.chars_inserted = edit.chars_inserted,
.chars_removed = chars_removed,
});
}
} else {
if (remainder_to_delete > 0) {
size_t chars_removed = min(remainder_to_delete, child_size);
remainder_to_delete -= chars_removed;
ts_tree_edit(child, (TSInputEdit){
.position = 0,
.chars_inserted = 0,
.chars_removed = chars_removed,
});
} else {
break;
}
}
}
}

View file

@ -29,6 +29,7 @@ struct TSTree {
bool extra : 1;
bool fragile_left : 1;
bool fragile_right : 1;
bool has_changes : 1;
} options;
unsigned short int ref_count;
};
@ -76,6 +77,7 @@ char *ts_tree_string(const TSTree *tree, const char **names);
char *ts_tree_error_string(const TSTree *tree, const char **names);
TSLength ts_tree_total_size(const TSTree *tree);
void ts_tree_prepend_children(TSTree *, size_t, TSTree **);
void ts_tree_edit(TSTree *, TSInputEdit);
static inline bool ts_tree_is_empty(TSTree *tree) {
return ts_tree_total_size(tree).bytes == 0;