Fix bug in ts_tree_cursor_goto_descendant

This commit is contained in:
Max Brunsfeld 2023-06-12 14:45:30 -07:00
parent 6b16a9687b
commit 3375527a89
3 changed files with 36 additions and 11 deletions

View file

@ -405,6 +405,28 @@ fn test_node_descendant_count() {
}
}
#[test]
fn test_descendant_count_single_node_tree() {
let mut parser = Parser::new();
parser
.set_language(get_language("embedded-template"))
.unwrap();
let tree = parser.parse("hello", None).unwrap();
let nodes = get_all_nodes(&tree);
assert_eq!(nodes.len(), 2);
assert_eq!(tree.root_node().descendant_count(), 2);
let mut cursor = tree.root_node().walk();
cursor.goto_descendant(0);
assert_eq!(cursor.depth(), 0);
assert_eq!(cursor.node(), nodes[0]);
cursor.goto_descendant(1);
assert_eq!(cursor.depth(), 1);
assert_eq!(cursor.node(), nodes[1]);
}
#[test]
fn test_node_descendant_for_range() {
let tree = parse_json_example();

View file

@ -971,6 +971,7 @@ void ts_subtree__print_dot_graph(const Subtree *self, uint32_t start_offset,
"error-cost: %u\n"
"has-changes: %u\n"
"depends-on-column: %u\n"
"descendant-count: %u\n"
"repeat-depth: %u\n"
"lookahead-bytes: %u",
start_offset, end_offset,
@ -978,6 +979,7 @@ void ts_subtree__print_dot_graph(const Subtree *self, uint32_t start_offset,
ts_subtree_error_cost(*self),
ts_subtree_has_changes(*self),
ts_subtree_depends_on_column(*self),
ts_subtree_visible_descendant_count(*self),
ts_subtree_repeat_depth(*self),
ts_subtree_lookahead_bytes(*self)
);

View file

@ -18,9 +18,9 @@ typedef struct {
static inline bool ts_tree_cursor_is_entry_visible(const TreeCursor *self, uint32_t i) {
TreeCursorEntry *entry = &self->stack.contents[i];
if (ts_subtree_visible(*entry->subtree)) {
if (i == 0 || ts_subtree_visible(*entry->subtree)) {
return true;
} else if (i > 0 && !ts_subtree_extra(*entry->subtree)) {
} else if (!ts_subtree_extra(*entry->subtree)) {
TreeCursorEntry *parent_entry = &self->stack.contents[i - 1];
return ts_language_alias_at(
self->tree->language,
@ -275,12 +275,17 @@ void ts_tree_cursor_goto_descendant(
) {
TreeCursor *self = (TreeCursor *)_self;
// Ascend to the lowest ancestor that contains the goal descendant.
// Ascend to the lowest ancestor that contains the goal node.
for (;;) {
TreeCursorEntry *entry = &self->stack.contents[self->stack.size - 1];
uint32_t i = self->stack.size - 1;
TreeCursorEntry *entry = &self->stack.contents[i];
uint32_t next_descendant_index =
entry->descendant_index +
(ts_tree_cursor_is_entry_visible(self, i) ? 1 : 0) +
ts_subtree_visible_descendant_count(*entry->subtree);
if (
(entry->descendant_index <= goal_descendant_index) &&
(entry->descendant_index + ts_subtree_visible_descendant_count(*entry->subtree) > goal_descendant_index)
(next_descendant_index > goal_descendant_index)
) {
break;
} else if (self->stack.size <= 1) {
@ -290,23 +295,19 @@ void ts_tree_cursor_goto_descendant(
}
}
// Descend to the goal descendant.
// Descend to the goal node.
bool did_descend = true;
do {
did_descend = false;
bool visible;
TreeCursorEntry entry;
CursorChildIterator iterator = ts_tree_cursor_iterate_children(self);
// If the goal descendant is the current node, then we're done.
if (iterator.descendant_index > goal_descendant_index) {
return;
}
while (ts_tree_cursor_child_iterator_next(&iterator, &entry, &visible)) {
uint32_t next_descendant_index = entry.descendant_index + ts_subtree_visible_descendant_count(*entry.subtree);
if (visible) next_descendant_index += 1;
if (next_descendant_index > goal_descendant_index) {
if (iterator.descendant_index > goal_descendant_index) {
array_push(&self->stack, entry);
if (visible && entry.descendant_index == goal_descendant_index) {
return;