2018-05-09 16:38:56 -07:00
|
|
|
#include "tree_sitter/runtime.h"
|
|
|
|
|
#include "runtime/alloc.h"
|
|
|
|
|
#include "runtime/tree_cursor.h"
|
|
|
|
|
#include "runtime/language.h"
|
2018-05-10 22:22:37 -07:00
|
|
|
#include "runtime/tree.h"
|
2018-05-09 16:38:56 -07:00
|
|
|
|
2018-05-10 22:22:37 -07:00
|
|
|
TSTreeCursor *ts_tree_cursor_new(const TSTree *tree) {
|
2018-05-09 16:38:56 -07:00
|
|
|
TSTreeCursor *self = ts_malloc(sizeof(TSTreeCursor));
|
2018-05-10 22:22:37 -07:00
|
|
|
ts_tree_cursor_init(self, tree);
|
|
|
|
|
return self;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void ts_tree_cursor_init(TSTreeCursor *self, const TSTree *tree) {
|
|
|
|
|
self->tree = tree;
|
2018-05-09 16:38:56 -07:00
|
|
|
array_init(&self->stack);
|
|
|
|
|
array_push(&self->stack, ((TreeCursorEntry) {
|
2018-05-10 22:22:37 -07:00
|
|
|
.subtree = tree->root,
|
2018-05-09 16:38:56 -07:00
|
|
|
.position = length_zero(),
|
|
|
|
|
.child_index = 0,
|
|
|
|
|
.structural_child_index = 0,
|
|
|
|
|
}));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void ts_tree_cursor_delete(TSTreeCursor *self) {
|
|
|
|
|
array_delete(&self->stack);
|
|
|
|
|
ts_free(self);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool ts_tree_cursor_goto_first_child(TSTreeCursor *self) {
|
|
|
|
|
TreeCursorEntry *last_entry = array_back(&self->stack);
|
2018-05-11 15:06:13 -07:00
|
|
|
const Subtree *tree = last_entry->subtree;
|
2018-05-09 16:38:56 -07:00
|
|
|
Length position = last_entry->position;
|
|
|
|
|
|
|
|
|
|
bool did_descend;
|
|
|
|
|
do {
|
|
|
|
|
did_descend = false;
|
|
|
|
|
|
|
|
|
|
uint32_t structural_child_index = 0;
|
|
|
|
|
for (uint32_t i = 0; i < tree->children.size; i++) {
|
2018-05-11 15:06:13 -07:00
|
|
|
const Subtree *child = tree->children.contents[i];
|
2018-05-09 16:38:56 -07:00
|
|
|
if (child->visible || child->visible_child_count > 0) {
|
|
|
|
|
array_push(&self->stack, ((TreeCursorEntry) {
|
2018-05-10 22:22:37 -07:00
|
|
|
.subtree = child,
|
2018-05-09 16:38:56 -07:00
|
|
|
.child_index = i,
|
|
|
|
|
.structural_child_index = structural_child_index,
|
|
|
|
|
.position = position,
|
|
|
|
|
}));
|
|
|
|
|
|
|
|
|
|
if (child->visible) {
|
|
|
|
|
return true;
|
|
|
|
|
} else {
|
|
|
|
|
tree = child;
|
|
|
|
|
did_descend = true;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (!child->extra) structural_child_index++;
|
2018-05-10 15:11:14 -07:00
|
|
|
position = length_add(position, ts_subtree_total_size(child));
|
2018-05-09 16:38:56 -07:00
|
|
|
}
|
|
|
|
|
} while (did_descend);
|
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2018-05-16 13:50:53 -07:00
|
|
|
int64_t ts_tree_cursor_goto_first_child_for_byte(TSTreeCursor *self, uint32_t goal_byte) {
|
|
|
|
|
uint32_t initial_size = self->stack.size;
|
|
|
|
|
TreeCursorEntry *last_entry = array_back(&self->stack);
|
|
|
|
|
const Subtree *tree = last_entry->subtree;
|
|
|
|
|
Length position = last_entry->position;
|
|
|
|
|
uint32_t visible_child_index = 0;
|
|
|
|
|
|
|
|
|
|
bool did_descend;
|
|
|
|
|
do {
|
|
|
|
|
did_descend = false;
|
|
|
|
|
|
|
|
|
|
uint32_t structural_child_index = 0;
|
|
|
|
|
for (uint32_t i = 0; i < tree->children.size; i++) {
|
|
|
|
|
const Subtree *child = tree->children.contents[i];
|
|
|
|
|
Length next_position = length_add(position, ts_subtree_total_size(child));
|
|
|
|
|
bool at_goal = next_position.bytes > goal_byte;
|
|
|
|
|
|
|
|
|
|
if (at_goal) {
|
|
|
|
|
if (child->visible || child->visible_child_count > 0) {
|
|
|
|
|
array_push(&self->stack, ((TreeCursorEntry) {
|
|
|
|
|
.subtree = child,
|
|
|
|
|
.child_index = i,
|
|
|
|
|
.structural_child_index = structural_child_index,
|
|
|
|
|
.position = position,
|
|
|
|
|
}));
|
|
|
|
|
|
|
|
|
|
if (child->visible) {
|
|
|
|
|
return visible_child_index;
|
|
|
|
|
} else {
|
|
|
|
|
tree = child;
|
|
|
|
|
did_descend = true;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
if (child->visible) {
|
|
|
|
|
visible_child_index++;
|
|
|
|
|
} else {
|
|
|
|
|
visible_child_index += child->visible_child_count;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!child->extra) structural_child_index++;
|
|
|
|
|
position = next_position;
|
|
|
|
|
}
|
|
|
|
|
} while (did_descend);
|
|
|
|
|
|
|
|
|
|
self->stack.size = initial_size;
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
2018-05-09 16:38:56 -07:00
|
|
|
bool ts_tree_cursor_goto_next_sibling(TSTreeCursor *self) {
|
|
|
|
|
TreeCursorEntry *child_entry = array_back(&self->stack);
|
|
|
|
|
|
|
|
|
|
for (unsigned i = self->stack.size - 2; i + 1 > 0; i--) {
|
|
|
|
|
TreeCursorEntry *parent_entry = &self->stack.contents[i];
|
|
|
|
|
|
2018-05-11 15:06:13 -07:00
|
|
|
const Subtree *parent = parent_entry->subtree;
|
2018-05-09 16:38:56 -07:00
|
|
|
uint32_t child_index = child_entry->child_index;
|
|
|
|
|
uint32_t structural_child_index = child_entry->structural_child_index;
|
|
|
|
|
Length position = child_entry->position;
|
2018-05-11 15:06:13 -07:00
|
|
|
const Subtree *child = parent->children.contents[child_index];
|
2018-05-09 16:38:56 -07:00
|
|
|
|
|
|
|
|
while (++child_index < parent->children.size) {
|
|
|
|
|
if (!child->extra) structural_child_index++;
|
2018-05-10 15:11:14 -07:00
|
|
|
position = length_add(position, ts_subtree_total_size(child));
|
2018-05-09 16:38:56 -07:00
|
|
|
child = parent->children.contents[child_index];
|
|
|
|
|
|
|
|
|
|
if (child->visible || child->visible_child_count > 0) {
|
|
|
|
|
self->stack.contents[i + 1] = (TreeCursorEntry) {
|
2018-05-10 22:22:37 -07:00
|
|
|
.subtree = child,
|
2018-05-09 16:38:56 -07:00
|
|
|
.child_index = child_index,
|
|
|
|
|
.structural_child_index = structural_child_index,
|
|
|
|
|
.position = position,
|
|
|
|
|
};
|
|
|
|
|
self->stack.size = i + 2;
|
|
|
|
|
|
|
|
|
|
if (child->visible) {
|
|
|
|
|
return true;
|
|
|
|
|
} else {
|
|
|
|
|
ts_tree_cursor_goto_first_child(self);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
child_entry = parent_entry;
|
|
|
|
|
if (parent->visible) break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool ts_tree_cursor_goto_parent(TSTreeCursor *self) {
|
|
|
|
|
for (unsigned i = self->stack.size - 2; i + 1 > 0; i--) {
|
|
|
|
|
TreeCursorEntry *entry = &self->stack.contents[i];
|
2018-05-10 22:22:37 -07:00
|
|
|
if (entry->subtree->visible) {
|
2018-05-09 16:38:56 -07:00
|
|
|
self->stack.size = i + 1;
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TSNode ts_tree_cursor_current_node(TSTreeCursor *self) {
|
|
|
|
|
TreeCursorEntry *last_entry = array_back(&self->stack);
|
|
|
|
|
TSSymbol alias_symbol = 0;
|
|
|
|
|
if (self->stack.size > 1) {
|
|
|
|
|
TreeCursorEntry *parent_entry = &self->stack.contents[self->stack.size - 2];
|
|
|
|
|
const TSSymbol *alias_sequence = ts_language_alias_sequence(
|
2018-05-10 22:22:37 -07:00
|
|
|
self->tree->language,
|
|
|
|
|
parent_entry->subtree->alias_sequence_id
|
2018-05-09 16:38:56 -07:00
|
|
|
);
|
|
|
|
|
if (alias_sequence) {
|
|
|
|
|
alias_symbol = alias_sequence[last_entry->structural_child_index];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return (TSNode) {
|
2018-05-10 22:22:37 -07:00
|
|
|
.tree = self->tree,
|
|
|
|
|
.subtree = last_entry->subtree,
|
2018-05-09 16:38:56 -07:00
|
|
|
.position = last_entry->position.extent,
|
|
|
|
|
.byte = last_entry->position.bytes,
|
|
|
|
|
.alias_symbol = alias_symbol,
|
|
|
|
|
};
|
|
|
|
|
}
|