aboutsummaryrefslogtreecommitdiff
path: root/src/tree_sitter/reusable_node.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/tree_sitter/reusable_node.h')
-rw-r--r--src/tree_sitter/reusable_node.h88
1 files changed, 88 insertions, 0 deletions
diff --git a/src/tree_sitter/reusable_node.h b/src/tree_sitter/reusable_node.h
new file mode 100644
index 0000000000..9cba951909
--- /dev/null
+++ b/src/tree_sitter/reusable_node.h
@@ -0,0 +1,88 @@
+#include "./subtree.h"
+
+typedef struct {
+ Subtree tree;
+ uint32_t child_index;
+ uint32_t byte_offset;
+} StackEntry;
+
+typedef struct {
+ Array(StackEntry) stack;
+ Subtree last_external_token;
+} ReusableNode;
+
+static inline ReusableNode reusable_node_new(void) {
+ return (ReusableNode) {array_new(), NULL_SUBTREE};
+}
+
+static inline void reusable_node_clear(ReusableNode *self) {
+ array_clear(&self->stack);
+ self->last_external_token = NULL_SUBTREE;
+}
+
+static inline void reusable_node_reset(ReusableNode *self, Subtree tree) {
+ reusable_node_clear(self);
+ array_push(&self->stack, ((StackEntry) {
+ .tree = tree,
+ .child_index = 0,
+ .byte_offset = 0,
+ }));
+}
+
+static inline Subtree reusable_node_tree(ReusableNode *self) {
+ return self->stack.size > 0
+ ? self->stack.contents[self->stack.size - 1].tree
+ : NULL_SUBTREE;
+}
+
+static inline uint32_t reusable_node_byte_offset(ReusableNode *self) {
+ return self->stack.size > 0
+ ? self->stack.contents[self->stack.size - 1].byte_offset
+ : UINT32_MAX;
+}
+
+static inline void reusable_node_delete(ReusableNode *self) {
+ array_delete(&self->stack);
+}
+
+static inline void reusable_node_advance(ReusableNode *self) {
+ StackEntry last_entry = *array_back(&self->stack);
+ uint32_t byte_offset = last_entry.byte_offset + ts_subtree_total_bytes(last_entry.tree);
+ if (ts_subtree_has_external_tokens(last_entry.tree)) {
+ self->last_external_token = ts_subtree_last_external_token(last_entry.tree);
+ }
+
+ Subtree tree;
+ uint32_t next_index;
+ do {
+ StackEntry popped_entry = array_pop(&self->stack);
+ next_index = popped_entry.child_index + 1;
+ if (self->stack.size == 0) return;
+ tree = array_back(&self->stack)->tree;
+ } while (ts_subtree_child_count(tree) <= next_index);
+
+ array_push(&self->stack, ((StackEntry) {
+ .tree = tree.ptr->children[next_index],
+ .child_index = next_index,
+ .byte_offset = byte_offset,
+ }));
+}
+
+static inline bool reusable_node_descend(ReusableNode *self) {
+ StackEntry last_entry = *array_back(&self->stack);
+ if (ts_subtree_child_count(last_entry.tree) > 0) {
+ array_push(&self->stack, ((StackEntry) {
+ .tree = last_entry.tree.ptr->children[0],
+ .child_index = 0,
+ .byte_offset = last_entry.byte_offset,
+ }));
+ return true;
+ } else {
+ return false;
+ }
+}
+
+static inline void reusable_node_advance_past_leaf(ReusableNode *self) {
+ while (reusable_node_descend(self)) {}
+ reusable_node_advance(self);
+}