1#include "./subtree.h"
2
3typedef struct {
4 Subtree tree;
5 uint32_t child_index;
6 uint32_t byte_offset;
7} StackEntry;
8
9typedef struct {
10 Array(StackEntry) stack;
11 Subtree last_external_token;
12} ReusableNode;
13
14static inline ReusableNode reusable_node_new(void) {
15 return (ReusableNode) {array_new(), NULL_SUBTREE};
16}
17
18static inline void reusable_node_clear(ReusableNode *self) {
19 array_clear(&self->stack);
20 self->last_external_token = NULL_SUBTREE;
21}
22
23static inline Subtree reusable_node_tree(ReusableNode *self) {
24 return self->stack.size > 0
25 ? self->stack.contents[self->stack.size - 1].tree
26 : NULL_SUBTREE;
27}
28
29static inline uint32_t reusable_node_byte_offset(ReusableNode *self) {
30 return self->stack.size > 0
31 ? self->stack.contents[self->stack.size - 1].byte_offset
32 : UINT32_MAX;
33}
34
35static inline void reusable_node_delete(ReusableNode *self) {
36 array_delete(&self->stack);
37}
38
39static inline void reusable_node_advance(ReusableNode *self) {
40 StackEntry last_entry = *array_back(&self->stack);
41 uint32_t byte_offset = last_entry.byte_offset + ts_subtree_total_bytes(last_entry.tree);
42 if (ts_subtree_has_external_tokens(last_entry.tree)) {
43 self->last_external_token = ts_subtree_last_external_token(last_entry.tree);
44 }
45
46 Subtree tree;
47 uint32_t next_index;
48 do {
49 StackEntry popped_entry = array_pop(&self->stack);
50 next_index = popped_entry.child_index + 1;
51 if (self->stack.size == 0) return;
52 tree = array_back(&self->stack)->tree;
53 } while (ts_subtree_child_count(tree) <= next_index);
54
55 array_push(&self->stack, ((StackEntry) {
56 .tree = ts_subtree_children(tree)[next_index],
57 .child_index = next_index,
58 .byte_offset = byte_offset,
59 }));
60}
61
62static inline bool reusable_node_descend(ReusableNode *self) {
63 StackEntry last_entry = *array_back(&self->stack);
64 if (ts_subtree_child_count(last_entry.tree) > 0) {
65 array_push(&self->stack, ((StackEntry) {
66 .tree = ts_subtree_children(last_entry.tree)[0],
67 .child_index = 0,
68 .byte_offset = last_entry.byte_offset,
69 }));
70 return true;
71 } else {
72 return false;
73 }
74}
75
76static inline void reusable_node_advance_past_leaf(ReusableNode *self) {
77 while (reusable_node_descend(self)) {}
78 reusable_node_advance(self);
79}
80
81static inline void reusable_node_reset(ReusableNode *self, Subtree tree) {
82 reusable_node_clear(self);
83 array_push(&self->stack, ((StackEntry) {
84 .tree = tree,
85 .child_index = 0,
86 .byte_offset = 0,
87 }));
88
89 // Never reuse the root node, because it has a non-standard internal structure
90 // due to transformations that are applied when it is accepted: adding the EOF
91 // child and any extra children.
92 if (!reusable_node_descend(self)) {
93 reusable_node_clear(self);
94 }
95}