2014-03-13 00:43:23 -07:00
|
|
|
#include "tree_sitter/runtime.h"
|
2014-05-09 13:32:12 -07:00
|
|
|
#include "tree_sitter/parser/stack.h"
|
2014-03-13 00:43:23 -07:00
|
|
|
#include <string.h>
|
|
|
|
|
|
2014-05-09 13:32:12 -07:00
|
|
|
static size_t INITIAL_STACK_SIZE = 100;
|
|
|
|
|
static ts_state_id INITIAL_STATE = 0;
|
2014-03-13 00:43:23 -07:00
|
|
|
|
|
|
|
|
ts_stack ts_stack_make() {
|
|
|
|
|
ts_stack result = {
|
|
|
|
|
.entries = calloc(INITIAL_STACK_SIZE, sizeof(*result.entries)),
|
|
|
|
|
.size = 0,
|
|
|
|
|
};
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
2014-06-03 13:19:49 -07:00
|
|
|
void ts_stack_delete(ts_stack *stack) {
|
|
|
|
|
ts_stack_shrink(stack, 0);
|
|
|
|
|
free(stack->entries);
|
|
|
|
|
}
|
|
|
|
|
|
2014-05-09 13:32:12 -07:00
|
|
|
ts_state_id ts_stack_top_state(const ts_stack *stack) {
|
2014-03-15 16:55:25 -07:00
|
|
|
if (stack->size == 0) return INITIAL_STATE;
|
2014-03-13 00:43:23 -07:00
|
|
|
return stack->entries[stack->size - 1].state;
|
|
|
|
|
}
|
|
|
|
|
|
2014-03-18 13:23:21 -07:00
|
|
|
ts_tree * ts_stack_top_node(const ts_stack *stack) {
|
|
|
|
|
if (stack->size == 0) return NULL;
|
|
|
|
|
return stack->entries[stack->size - 1].node;
|
|
|
|
|
}
|
|
|
|
|
|
2014-05-09 13:32:12 -07:00
|
|
|
void ts_stack_push(ts_stack *stack, ts_state_id state, ts_tree *node) {
|
2014-03-13 00:43:23 -07:00
|
|
|
stack->entries[stack->size].state = state;
|
|
|
|
|
stack->entries[stack->size].node = node;
|
|
|
|
|
stack->size++;
|
2014-06-03 13:19:49 -07:00
|
|
|
ts_tree_retain(node);
|
2014-03-13 00:43:23 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void ts_stack_shrink(ts_stack *stack, size_t new_size) {
|
|
|
|
|
for (size_t i = new_size; i < stack->size; i++)
|
|
|
|
|
ts_tree_release(stack->entries[i].node);
|
|
|
|
|
stack->size = new_size;
|
|
|
|
|
}
|
|
|
|
|
|
2014-03-21 13:02:25 -07:00
|
|
|
size_t ts_stack_right_position(const ts_stack *stack) {
|
|
|
|
|
size_t result = 0;
|
|
|
|
|
for (size_t i = 0; i < stack->size; i++) {
|
|
|
|
|
ts_tree *node = stack->entries[i].node;
|
2014-03-24 00:34:13 -07:00
|
|
|
result += ts_tree_total_size(node);
|
2014-03-21 13:02:25 -07:00
|
|
|
}
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
2014-05-06 12:54:04 -07:00
|
|
|
ts_tree * ts_stack_reduce(ts_stack *stack,
|
|
|
|
|
ts_symbol symbol,
|
2014-05-09 12:46:36 -07:00
|
|
|
size_t immediate_child_count,
|
2014-05-06 12:54:04 -07:00
|
|
|
const int *hidden_symbol_flags,
|
|
|
|
|
const int *ubiquitous_symbol_flags) {
|
|
|
|
|
|
|
|
|
|
// First, walk down the stack to determine which symbols will be reduced.
|
|
|
|
|
// The child node count is known ahead of time, but some of the
|
|
|
|
|
// nodes at the top of the stack might be hidden nodes, in which
|
|
|
|
|
// case we 'collapse' them. Some may also be ubiquitous tokens,
|
|
|
|
|
// which don't count towards the child node count.
|
|
|
|
|
static int collapse_flags[100];
|
2014-03-24 00:36:47 -07:00
|
|
|
int child_count = 0;
|
2014-05-09 12:46:36 -07:00
|
|
|
for (size_t i = 0; i < immediate_child_count; i++) {
|
2014-05-08 13:27:48 -07:00
|
|
|
size_t stack_index = stack->size - 1 - i;
|
|
|
|
|
ts_tree *child = stack->entries[stack_index].node;
|
2014-03-26 00:10:59 -07:00
|
|
|
size_t grandchild_count;
|
|
|
|
|
ts_tree **grandchildren = ts_tree_children(child, &grandchild_count);
|
2014-05-08 13:27:48 -07:00
|
|
|
ts_symbol child_symbol = ts_tree_symbol(child);
|
2014-05-06 12:54:04 -07:00
|
|
|
|
|
|
|
|
collapse_flags[i] = (
|
2014-05-08 13:27:48 -07:00
|
|
|
hidden_symbol_flags[child_symbol] ||
|
2014-03-26 00:10:59 -07:00
|
|
|
(grandchild_count == 1 && ts_tree_size(child) == ts_tree_size(grandchildren[0]))
|
|
|
|
|
);
|
2014-05-06 12:54:04 -07:00
|
|
|
|
2014-05-08 13:27:48 -07:00
|
|
|
child_count += collapse_flags[i] ? grandchild_count : 1;
|
|
|
|
|
|
2014-05-09 12:46:36 -07:00
|
|
|
if (ubiquitous_symbol_flags && ubiquitous_symbol_flags[child_symbol])
|
2014-05-08 13:27:48 -07:00
|
|
|
immediate_child_count++;
|
2014-03-24 00:36:47 -07:00
|
|
|
}
|
|
|
|
|
|
2014-05-06 12:54:04 -07:00
|
|
|
// Walk down the stack again, building up the array of children.
|
|
|
|
|
// Though we collapse the hidden child nodes, we also need to
|
|
|
|
|
// keep track of the actual immediate children so that we can
|
|
|
|
|
// later collapse the stack again when the document is edited.
|
|
|
|
|
// We store the children and immediate children in the same array,
|
|
|
|
|
// to reduce allocations.
|
|
|
|
|
size_t child_index = child_count;
|
2014-03-24 00:36:47 -07:00
|
|
|
ts_tree **children = malloc((child_count + immediate_child_count) * sizeof(ts_tree *));
|
|
|
|
|
ts_tree **immediate_children = children + child_count;
|
2014-03-24 09:14:29 -07:00
|
|
|
|
2014-05-09 12:46:36 -07:00
|
|
|
for (size_t i = 0; i < immediate_child_count; i++) {
|
2014-05-06 12:54:04 -07:00
|
|
|
ts_tree *child = stack->entries[stack->size - 1 - i].node;
|
|
|
|
|
immediate_children[immediate_child_count - 1 - i] = child;
|
2014-03-24 00:36:47 -07:00
|
|
|
|
2014-05-06 12:54:04 -07:00
|
|
|
if (collapse_flags[i]) {
|
2014-03-24 00:36:47 -07:00
|
|
|
size_t grandchild_count;
|
2014-05-06 12:54:04 -07:00
|
|
|
ts_tree **grandchildren = ts_tree_children(child, &grandchild_count);
|
|
|
|
|
child_index -= grandchild_count;
|
2014-03-24 00:36:47 -07:00
|
|
|
memcpy(children + child_index, grandchildren, (grandchild_count * sizeof(ts_tree *)));
|
|
|
|
|
} else {
|
2014-05-06 12:54:04 -07:00
|
|
|
child_index--;
|
2014-03-24 00:36:47 -07:00
|
|
|
children[child_index] = child;
|
2014-05-06 12:54:04 -07:00
|
|
|
}
|
2014-03-13 00:43:23 -07:00
|
|
|
}
|
|
|
|
|
|
2014-06-02 13:32:36 -07:00
|
|
|
ts_tree *lookahead = ts_tree_make_node(symbol, child_count, immediate_child_count, children);
|
2014-05-06 12:54:04 -07:00
|
|
|
ts_stack_shrink(stack, stack->size - immediate_child_count);
|
2014-03-13 00:43:23 -07:00
|
|
|
return lookahead;
|
|
|
|
|
}
|