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}