Start work on removing parent pointers
Co-Authored-By: Rick Winfrey <rewinfrey@github.com>
This commit is contained in:
parent
8300f24fec
commit
973e4a44f0
14 changed files with 410 additions and 324 deletions
|
|
@ -63,8 +63,11 @@ typedef struct {
|
|||
} TSRange;
|
||||
|
||||
typedef struct {
|
||||
const void *data;
|
||||
uint32_t offset[2];
|
||||
const void *subtree;
|
||||
const TSDocument *document;
|
||||
TSPoint position;
|
||||
uint32_t byte;
|
||||
TSSymbol alias_symbol;
|
||||
} TSNode;
|
||||
|
||||
uint32_t ts_node_start_byte(TSNode);
|
||||
|
|
@ -84,7 +87,6 @@ TSNode ts_node_child(TSNode, uint32_t);
|
|||
TSNode ts_node_named_child(TSNode, uint32_t);
|
||||
uint32_t ts_node_child_count(TSNode);
|
||||
uint32_t ts_node_named_child_count(TSNode);
|
||||
uint32_t ts_node_child_index(TSNode);
|
||||
TSNode ts_node_next_sibling(TSNode);
|
||||
TSNode ts_node_next_named_sibling(TSNode);
|
||||
TSNode ts_node_prev_sibling(TSNode);
|
||||
|
|
|
|||
|
|
@ -58,6 +58,9 @@ extern "C" {
|
|||
|
||||
#define array_pop(self) ((self)->contents[--(self)->size])
|
||||
|
||||
#define array_assign(self, other) \
|
||||
array__assign((VoidArray *)(self), (const VoidArray *)(other), array__elem_size(self))
|
||||
|
||||
// Private
|
||||
|
||||
typedef Array(void) VoidArray;
|
||||
|
|
@ -91,6 +94,12 @@ static inline void array__reserve(VoidArray *self, size_t element_size, uint32_t
|
|||
}
|
||||
}
|
||||
|
||||
static inline void array__assign(VoidArray *self, const VoidArray *other, size_t element_size) {
|
||||
array__reserve(self, element_size, other->size);
|
||||
self->size = other->size;
|
||||
memcpy(self->contents, other->contents, self->size * element_size);
|
||||
}
|
||||
|
||||
static inline void array__grow(VoidArray *self, size_t element_size) {
|
||||
if (self->size == self->capacity) {
|
||||
size_t new_capacity = self->capacity * 2;
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
#include "runtime/alloc.h"
|
||||
#include "runtime/node.h"
|
||||
#include "runtime/tree.h"
|
||||
#include "runtime/parser.h"
|
||||
#include "runtime/string_input.h"
|
||||
|
|
@ -171,7 +170,12 @@ void ts_document_invalidate(TSDocument *self) {
|
|||
}
|
||||
|
||||
TSNode ts_document_root_node(const TSDocument *self) {
|
||||
return ts_node_make(self->tree, 0, 0);
|
||||
return (TSNode) {
|
||||
.subtree = self->tree,
|
||||
.document = self,
|
||||
.position = {0, 0},
|
||||
.byte = 0,
|
||||
};
|
||||
}
|
||||
|
||||
uint32_t ts_document_parse_count(const TSDocument *self) {
|
||||
|
|
|
|||
|
|
@ -1,43 +1,91 @@
|
|||
#include <stdbool.h>
|
||||
#include "runtime/node.h"
|
||||
#include "runtime/tree.h"
|
||||
#include "runtime/document.h"
|
||||
#include "runtime/language.h"
|
||||
|
||||
TSNode ts_node_make(const Tree *tree, uint32_t byte, uint32_t row) {
|
||||
return (TSNode){.data = tree, .offset = { byte, row } };
|
||||
}
|
||||
// NodeChildIterator
|
||||
|
||||
/*
|
||||
* Private
|
||||
*/
|
||||
typedef struct {
|
||||
const Tree *parent;
|
||||
const TSDocument *document;
|
||||
Length position;
|
||||
uint32_t child_index;
|
||||
uint32_t structural_child_index;
|
||||
const TSSymbol *alias_sequence;
|
||||
} NodeChildIterator;
|
||||
|
||||
// TSNode - Private
|
||||
|
||||
static inline TSNode ts_node__null() {
|
||||
return ts_node_make(NULL, 0, 0);
|
||||
return (TSNode) {
|
||||
.subtree = NULL,
|
||||
.document = NULL,
|
||||
.position = {0, 0},
|
||||
.byte = 0,
|
||||
};
|
||||
}
|
||||
|
||||
static inline const Tree *ts_node__tree(TSNode self) {
|
||||
return self.data;
|
||||
return self.subtree;
|
||||
}
|
||||
|
||||
static inline uint32_t ts_node__offset_byte(TSNode self) {
|
||||
return self.offset[0];
|
||||
static inline NodeChildIterator ts_node_child_iterator_begin(const TSNode *node) {
|
||||
const Tree *tree = ts_node__tree(*node);
|
||||
const TSSymbol *alias_sequence = ts_language_alias_sequence(
|
||||
node->document->parser.language,
|
||||
tree->alias_sequence_id
|
||||
);
|
||||
return (NodeChildIterator) {
|
||||
.parent = tree,
|
||||
.document = node->document,
|
||||
.position = {node->byte, node->position},
|
||||
.child_index = 0,
|
||||
.structural_child_index = 0,
|
||||
.alias_sequence = alias_sequence,
|
||||
};
|
||||
}
|
||||
|
||||
static inline uint32_t ts_node__offset_row(TSNode self) {
|
||||
return self.offset[1];
|
||||
static inline bool ts_node_child_iterator_next(NodeChildIterator *self, TSNode *result) {
|
||||
if (self->child_index == self->parent->children.size) return false;
|
||||
Tree *child = self->parent->children.contents[self->child_index];
|
||||
TSSymbol alias_symbol = 0;
|
||||
if (!child->extra) {
|
||||
if (self->alias_sequence) {
|
||||
alias_symbol = self->alias_sequence[self->structural_child_index];
|
||||
}
|
||||
self->structural_child_index++;
|
||||
}
|
||||
*result = (TSNode) {
|
||||
.subtree = child,
|
||||
.document = self->document,
|
||||
.position = self->position.extent,
|
||||
.byte = self->position.bytes,
|
||||
.alias_symbol = alias_symbol,
|
||||
};
|
||||
self->position = length_add(self->position, ts_tree_total_size(child));
|
||||
self->child_index++;
|
||||
return true;
|
||||
}
|
||||
|
||||
static inline bool ts_node__is_relevant(TSNode self, bool include_anonymous) {
|
||||
const Tree *tree = ts_node__tree(self);
|
||||
if (include_anonymous) {
|
||||
return tree->context.alias_symbol || tree->visible;
|
||||
return tree->visible || self.alias_symbol;
|
||||
} else {
|
||||
return tree->context.alias_is_named || (tree->visible && tree->named);
|
||||
return (
|
||||
(tree->visible && tree->named) ||
|
||||
(
|
||||
self.alias_symbol &&
|
||||
ts_language_symbol_metadata(
|
||||
self.document->parser.language,
|
||||
self.alias_symbol
|
||||
).named
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
static inline uint32_t ts_node__relevant_child_count(TSNode self,
|
||||
bool include_anonymous) {
|
||||
static inline uint32_t ts_node__relevant_child_count(TSNode self, bool include_anonymous) {
|
||||
const Tree *tree = ts_node__tree(self);
|
||||
if (tree->children.size > 0) {
|
||||
if (include_anonymous) {
|
||||
|
|
@ -50,44 +98,23 @@ static inline uint32_t ts_node__relevant_child_count(TSNode self,
|
|||
}
|
||||
}
|
||||
|
||||
static inline TSNode ts_node__direct_parent(TSNode self, uint32_t *index) {
|
||||
const Tree *tree = ts_node__tree(self);
|
||||
*index = tree->context.index;
|
||||
return ts_node_make(
|
||||
tree->context.parent,
|
||||
ts_node__offset_byte(self) - tree->context.offset.bytes,
|
||||
ts_node__offset_row(self) - tree->context.offset.extent.row
|
||||
);
|
||||
}
|
||||
|
||||
static inline TSNode ts_node__direct_child(TSNode self, uint32_t i) {
|
||||
const Tree *child_tree = ts_node__tree(self)->children.contents[i];
|
||||
return ts_node_make(
|
||||
child_tree,
|
||||
ts_node__offset_byte(self) + child_tree->context.offset.bytes,
|
||||
ts_node__offset_row(self) + child_tree->context.offset.extent.row
|
||||
);
|
||||
}
|
||||
|
||||
static inline TSNode ts_node__child(TSNode self, uint32_t child_index,
|
||||
bool include_anonymous) {
|
||||
static inline TSNode ts_node__child(TSNode self, uint32_t child_index, bool include_anonymous) {
|
||||
TSNode result = self;
|
||||
bool did_descend = true;
|
||||
|
||||
while (did_descend) {
|
||||
did_descend = false;
|
||||
|
||||
TSNode child;
|
||||
uint32_t index = 0;
|
||||
for (uint32_t i = 0; i < ts_node__tree(result)->children.size; i++) {
|
||||
TSNode child = ts_node__direct_child(result, i);
|
||||
NodeChildIterator iterator = ts_node_child_iterator_begin(&result);
|
||||
while (ts_node_child_iterator_next(&iterator, &child)) {
|
||||
if (ts_node__is_relevant(child, include_anonymous)) {
|
||||
if (index == child_index)
|
||||
return child;
|
||||
if (index == child_index) return child;
|
||||
index++;
|
||||
} else {
|
||||
uint32_t grandchild_index = child_index - index;
|
||||
uint32_t grandchild_count =
|
||||
ts_node__relevant_child_count(child, include_anonymous);
|
||||
uint32_t grandchild_count = ts_node__relevant_child_count(child, include_anonymous);
|
||||
if (grandchild_index < grandchild_count) {
|
||||
did_descend = true;
|
||||
result = child;
|
||||
|
|
@ -102,48 +129,80 @@ static inline TSNode ts_node__child(TSNode self, uint32_t child_index,
|
|||
return ts_node__null();
|
||||
}
|
||||
|
||||
static inline TSNode ts_node__prev_sibling(TSNode self, bool include_anonymous) {
|
||||
TSNode result = self;
|
||||
|
||||
do {
|
||||
uint32_t index;
|
||||
result = ts_node__direct_parent(result, &index);
|
||||
if (!result.data)
|
||||
static inline bool ts_node__last_child_before(TSNode self, TSNode target,
|
||||
bool include_anonymous, TSNode *result) {
|
||||
TSNode child;
|
||||
TSNode earlier_child = ts_node__null();
|
||||
bool earlier_child_is_relevant = false;
|
||||
bool found_child_containing_target = false;
|
||||
NodeChildIterator iterator = ts_node_child_iterator_begin(&self);
|
||||
uint32_t target_end_byte = ts_node_end_byte(target);
|
||||
while (ts_node_child_iterator_next(&iterator, &child)) {
|
||||
if (iterator.position.bytes >= target_end_byte) {
|
||||
found_child_containing_target = true;
|
||||
break;
|
||||
|
||||
for (uint32_t i = index - 1; i + 1 > 0; i--) {
|
||||
TSNode child = ts_node__direct_child(result, i);
|
||||
if (ts_node__is_relevant(child, include_anonymous))
|
||||
return child;
|
||||
uint32_t grandchild_count =
|
||||
ts_node__relevant_child_count(child, include_anonymous);
|
||||
if (grandchild_count > 0)
|
||||
return ts_node__child(child, grandchild_count - 1, include_anonymous);
|
||||
}
|
||||
} while (!ts_node__tree(result)->visible);
|
||||
|
||||
return ts_node__null();
|
||||
if (ts_node__is_relevant(child, include_anonymous)) {
|
||||
earlier_child = child;
|
||||
earlier_child_is_relevant = true;
|
||||
} else if (ts_node__relevant_child_count(child, include_anonymous) > 0) {
|
||||
earlier_child = child;
|
||||
earlier_child_is_relevant = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (found_child_containing_target && child.subtree != target.subtree) {
|
||||
if (ts_node__last_child_before(child, target, include_anonymous, result)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (earlier_child_is_relevant) {
|
||||
*result = earlier_child;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (earlier_child.subtree) {
|
||||
return ts_node__last_child_before(earlier_child, target, include_anonymous, result);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static inline TSNode ts_node__prev_sibling(TSNode self, bool include_anonymous) {
|
||||
TSNode result = ts_node__null();
|
||||
TSNode parent = ts_node_parent(self);
|
||||
if (parent.subtree) {
|
||||
ts_node__last_child_before(parent, self, include_anonymous, &result);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static inline TSNode ts_node__next_sibling(TSNode self, bool include_anonymous) {
|
||||
TSNode result = self;
|
||||
TSNode node = ts_node_parent(self);
|
||||
if (!node.subtree) return ts_node__null();
|
||||
uint32_t end_byte = ts_node_end_byte(self);
|
||||
|
||||
do {
|
||||
uint32_t index;
|
||||
result = ts_node__direct_parent(result, &index);
|
||||
if (!result.data)
|
||||
break;
|
||||
bool did_descend = true;
|
||||
while (did_descend) {
|
||||
did_descend = false;
|
||||
|
||||
for (uint32_t i = index + 1; i < ts_node__tree(result)->children.size; i++) {
|
||||
TSNode child = ts_node__direct_child(result, i);
|
||||
if (ts_node__is_relevant(child, include_anonymous))
|
||||
return child;
|
||||
uint32_t grandchild_count =
|
||||
ts_node__relevant_child_count(child, include_anonymous);
|
||||
if (grandchild_count > 0)
|
||||
return ts_node__child(child, 0, include_anonymous);
|
||||
TSNode child;
|
||||
NodeChildIterator iterator = ts_node_child_iterator_begin(&node);
|
||||
while (ts_node_child_iterator_next(&iterator, &child)) {
|
||||
if (iterator.position.bytes > end_byte && child.subtree != self.subtree) {
|
||||
if (ts_node__is_relevant(child, include_anonymous)) {
|
||||
return child;
|
||||
}
|
||||
if (ts_node__relevant_child_count(child, include_anonymous) > 0) {
|
||||
node = child;
|
||||
did_descend = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
} while (!ts_node__tree(result)->visible);
|
||||
}
|
||||
|
||||
return ts_node__null();
|
||||
}
|
||||
|
|
@ -160,8 +219,9 @@ static inline TSNode ts_node__first_child_for_byte(TSNode self, uint32_t goal,
|
|||
while (did_descend) {
|
||||
did_descend = false;
|
||||
|
||||
for (uint32_t i = 0; i < ts_node__tree(node)->children.size; i++) {
|
||||
TSNode child = ts_node__direct_child(node, i);
|
||||
TSNode child;
|
||||
NodeChildIterator iterator = ts_node_child_iterator_begin(&node);
|
||||
while (ts_node_child_iterator_next(&iterator, &child)) {
|
||||
if (ts_node_end_byte(child) > goal) {
|
||||
if (ts_node__is_relevant(child, include_anonymous)) {
|
||||
return child;
|
||||
|
|
@ -187,10 +247,11 @@ static inline TSNode ts_node__descendant_for_byte_range(TSNode self, uint32_t mi
|
|||
while (did_descend) {
|
||||
did_descend = false;
|
||||
|
||||
for (uint32_t i = 0, n = ts_node__tree(node)->children.size; i < n; i++) {
|
||||
TSNode child = ts_node__direct_child(node, i);
|
||||
if (ts_node_end_byte(child) > max) {
|
||||
if (ts_node_start_byte(child) > min) break;
|
||||
TSNode child;
|
||||
NodeChildIterator iterator = ts_node_child_iterator_begin(&node);
|
||||
while (ts_node_child_iterator_next(&iterator, &child)) {
|
||||
if (iterator.position.bytes > max) {
|
||||
if (child.byte > min) break;
|
||||
node = child;
|
||||
if (ts_node__is_relevant(node, include_anonymous)) last_visible_node = node;
|
||||
did_descend = true;
|
||||
|
|
@ -214,10 +275,13 @@ static inline TSNode ts_node__descendant_for_point_range(TSNode self, TSPoint mi
|
|||
while (did_descend) {
|
||||
did_descend = false;
|
||||
|
||||
for (uint32_t i = 0, n = ts_node__tree(node)->children.size; i < n; i++) {
|
||||
TSNode child = ts_node__direct_child(node, i);
|
||||
TSNode child;
|
||||
NodeChildIterator iterator = ts_node_child_iterator_begin(&node);
|
||||
while (ts_node_child_iterator_next(&iterator, &child)) {
|
||||
const Tree *child_tree = ts_node__tree(child);
|
||||
if (i > 0) start_position = point_add(start_position, child_tree->padding.extent);
|
||||
if (iterator.child_index != 1) {
|
||||
start_position = point_add(start_position, child_tree->padding.extent);
|
||||
}
|
||||
end_position = point_add(start_position, child_tree->size.extent);
|
||||
if (point_gt(end_position, max)) {
|
||||
if (point_gt(start_position, min)) break;
|
||||
|
|
@ -233,12 +297,10 @@ static inline TSNode ts_node__descendant_for_point_range(TSNode self, TSPoint mi
|
|||
return last_visible_node;
|
||||
}
|
||||
|
||||
/*
|
||||
* Public
|
||||
*/
|
||||
// TSNode - Public
|
||||
|
||||
uint32_t ts_node_start_byte(TSNode self) {
|
||||
return ts_node__offset_byte(self) + ts_node__tree(self)->padding.bytes;
|
||||
return self.byte + ts_node__tree(self)->padding.bytes;
|
||||
}
|
||||
|
||||
uint32_t ts_node_end_byte(TSNode self) {
|
||||
|
|
@ -246,21 +308,16 @@ uint32_t ts_node_end_byte(TSNode self) {
|
|||
}
|
||||
|
||||
TSPoint ts_node_start_point(TSNode self) {
|
||||
const Tree *tree = ts_node__tree(self);
|
||||
return (TSPoint){ ts_node__offset_row(self) + tree->padding.extent.row,
|
||||
ts_tree_start_column(tree) };
|
||||
return point_add(self.position, ts_node__tree(self)->padding.extent);
|
||||
}
|
||||
|
||||
TSPoint ts_node_end_point(TSNode self) {
|
||||
const Tree *tree = ts_node__tree(self);
|
||||
return (TSPoint){ ts_node__offset_row(self) + tree->padding.extent.row +
|
||||
tree->size.extent.row,
|
||||
ts_tree_end_column(tree) };
|
||||
return point_add(ts_node_start_point(self), ts_node__tree(self)->size.extent);
|
||||
}
|
||||
|
||||
TSSymbol ts_node_symbol(TSNode self) {
|
||||
const Tree *tree = ts_node__tree(self);
|
||||
return tree->context.alias_symbol ? tree->context.alias_symbol : tree->symbol;
|
||||
return self.alias_symbol ? self.alias_symbol : tree->symbol;
|
||||
}
|
||||
|
||||
const char *ts_node_type(TSNode self, const TSDocument *document) {
|
||||
|
|
@ -272,15 +329,17 @@ char *ts_node_string(TSNode self, const TSDocument *document) {
|
|||
}
|
||||
|
||||
bool ts_node_eq(TSNode self, TSNode other) {
|
||||
return
|
||||
return (
|
||||
ts_tree_eq(ts_node__tree(self), ts_node__tree(other)) &&
|
||||
self.offset[0] == other.offset[0] &&
|
||||
self.offset[1] == other.offset[1];
|
||||
self.byte == other.byte
|
||||
);
|
||||
}
|
||||
|
||||
bool ts_node_is_named(TSNode self) {
|
||||
const Tree *tree = ts_node__tree(self);
|
||||
return tree->context.alias_symbol ? tree->context.alias_is_named : tree->named;
|
||||
return self.alias_symbol
|
||||
? ts_language_symbol_metadata(self.document->parser.language, self.alias_symbol).named
|
||||
: tree->named;
|
||||
}
|
||||
|
||||
bool ts_node_is_missing(TSNode self) {
|
||||
|
|
@ -297,35 +356,31 @@ bool ts_node_has_error(TSNode self) {
|
|||
}
|
||||
|
||||
TSNode ts_node_parent(TSNode self) {
|
||||
TSNode result = self;
|
||||
uint32_t index;
|
||||
TSNode node = ts_document_root_node(self.document);
|
||||
uint32_t end_byte = ts_node_end_byte(self);
|
||||
if (node.subtree == self.subtree) return ts_node__null();
|
||||
|
||||
do {
|
||||
result = ts_node__direct_parent(result, &index);
|
||||
if (!result.data)
|
||||
return ts_node__null();
|
||||
} while (!ts_node__tree(result)->visible);
|
||||
TSNode last_visible_node = node;
|
||||
bool did_descend = true;
|
||||
while (did_descend) {
|
||||
did_descend = false;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
uint32_t ts_node_child_index(TSNode self) {
|
||||
const Tree *tree = ts_node__tree(self);
|
||||
uint32_t result = 0;
|
||||
|
||||
for (;;) {
|
||||
const Tree *parent = tree->context.parent;
|
||||
uint32_t index = tree->context.index;
|
||||
if (!parent) return UINT32_MAX;
|
||||
for (uint32_t i = 0; i < index; i++) {
|
||||
Tree *child = parent->children.contents[i];
|
||||
result += child->visible ? 1 : child->visible_child_count;
|
||||
TSNode child;
|
||||
NodeChildIterator iterator = ts_node_child_iterator_begin(&node);
|
||||
while (ts_node_child_iterator_next(&iterator, &child)) {
|
||||
if (child.byte > self.byte || child.subtree == self.subtree) break;
|
||||
if (iterator.position.bytes >= end_byte) {
|
||||
node = child;
|
||||
if (ts_node__is_relevant(child, true)) {
|
||||
last_visible_node = node;
|
||||
}
|
||||
did_descend = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (parent->visible) break;
|
||||
tree = parent;
|
||||
}
|
||||
|
||||
return result;
|
||||
return last_visible_node;
|
||||
}
|
||||
|
||||
TSNode ts_node_child(TSNode self, uint32_t child_index) {
|
||||
|
|
|
|||
|
|
@ -1,8 +0,0 @@
|
|||
#ifndef RUNTIME_NODE_H_
|
||||
#define RUNTIME_NODE_H_
|
||||
|
||||
#include "runtime/tree.h"
|
||||
|
||||
TSNode ts_node_make(const Tree *, uint32_t byte, uint32_t row);
|
||||
|
||||
#endif
|
||||
|
|
@ -119,16 +119,19 @@ static bool parser__breakdown_top_of_stack(Parser *self, StackVersion version) {
|
|||
static void parser__breakdown_lookahead(Parser *self, Tree **lookahead,
|
||||
TSStateId state,
|
||||
ReusableNode *reusable_node) {
|
||||
bool did_break_down = false;
|
||||
while (reusable_node->tree->children.size > 0 && reusable_node->tree->parse_state != state) {
|
||||
LOG("state_mismatch sym:%s", SYM_NAME(reusable_node->tree->symbol));
|
||||
reusable_node_breakdown(reusable_node);
|
||||
did_break_down = true;
|
||||
bool did_descend = false;
|
||||
Tree *tree = reusable_node_tree(reusable_node);
|
||||
while (tree->children.size > 0 && tree->parse_state != state) {
|
||||
LOG("state_mismatch sym:%s", SYM_NAME(tree->symbol));
|
||||
reusable_node_descend(reusable_node);
|
||||
tree = reusable_node_tree(reusable_node);
|
||||
did_descend = true;
|
||||
}
|
||||
|
||||
if (did_break_down) {
|
||||
if (did_descend) {
|
||||
ts_tree_release(&self->tree_pool, *lookahead);
|
||||
ts_tree_retain(*lookahead = reusable_node->tree);
|
||||
*lookahead = tree;
|
||||
ts_tree_retain(*lookahead);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -419,21 +422,22 @@ static Tree *parser__get_lookahead(Parser *self, StackVersion version, TSStateId
|
|||
Tree *last_external_token = ts_stack_last_external_token(self->stack, version);
|
||||
|
||||
Tree *result;
|
||||
while ((result = reusable_node->tree)) {
|
||||
if (reusable_node->byte_index > position.bytes) {
|
||||
while ((result = reusable_node_tree(reusable_node))) {
|
||||
uint32_t byte_offset = reusable_node_byte_offset(reusable_node);
|
||||
if (byte_offset > position.bytes) {
|
||||
LOG("before_reusable_node symbol:%s", SYM_NAME(result->symbol));
|
||||
break;
|
||||
}
|
||||
|
||||
if (reusable_node->byte_index < position.bytes) {
|
||||
if (byte_offset < position.bytes) {
|
||||
LOG("past_reusable_node symbol:%s", SYM_NAME(result->symbol));
|
||||
reusable_node_pop(reusable_node);
|
||||
reusable_node_advance(reusable_node);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!ts_tree_external_token_state_eq(reusable_node->last_external_token, last_external_token)) {
|
||||
LOG("reusable_node_has_different_external_scanner_state symbol:%s", SYM_NAME(result->symbol));
|
||||
reusable_node_pop(reusable_node);
|
||||
reusable_node_advance(reusable_node);
|
||||
continue;
|
||||
}
|
||||
|
||||
|
|
@ -452,8 +456,8 @@ static Tree *parser__get_lookahead(Parser *self, StackVersion version, TSStateId
|
|||
|
||||
if (reason) {
|
||||
LOG("cant_reuse_node_%s tree:%s", reason, SYM_NAME(result->symbol));
|
||||
if (!reusable_node_breakdown(reusable_node)) {
|
||||
reusable_node_pop(reusable_node);
|
||||
if (!reusable_node_descend(reusable_node)) {
|
||||
reusable_node_advance(reusable_node);
|
||||
parser__breakdown_top_of_stack(self, version);
|
||||
*state = ts_stack_state(self->stack, version);
|
||||
}
|
||||
|
|
@ -467,7 +471,7 @@ static Tree *parser__get_lookahead(Parser *self, StackVersion version, TSStateId
|
|||
SYM_NAME(result->symbol),
|
||||
SYM_NAME(result->first_leaf.symbol)
|
||||
);
|
||||
reusable_node_pop_leaf(reusable_node);
|
||||
reusable_node_advance_past_leaf(reusable_node);
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
@ -678,7 +682,7 @@ static void parser__start(Parser *self, TSInput input, Tree *previous_tree) {
|
|||
|
||||
ts_lexer_set_input(&self->lexer, input);
|
||||
ts_stack_clear(self->stack);
|
||||
self->reusable_node = reusable_node_new(previous_tree);
|
||||
reusable_node_reset(&self->reusable_node, previous_tree);
|
||||
self->finished_tree = NULL;
|
||||
self->accept_count = 0;
|
||||
self->in_ambiguity = false;
|
||||
|
|
@ -1106,7 +1110,9 @@ static void parser__advance(Parser *self, StackVersion version, ReusableNode *re
|
|||
}
|
||||
|
||||
parser__shift(self, version, next_state, lookahead, action.params.extra);
|
||||
if (lookahead == reusable_node->tree) reusable_node_pop(reusable_node);
|
||||
if (lookahead == reusable_node_tree(reusable_node)) {
|
||||
reusable_node_advance(reusable_node);
|
||||
}
|
||||
ts_tree_release(&self->tree_pool, lookahead);
|
||||
return;
|
||||
}
|
||||
|
|
@ -1136,7 +1142,9 @@ static void parser__advance(Parser *self, StackVersion version, ReusableNode *re
|
|||
parser__breakdown_lookahead(self, &lookahead, state, reusable_node);
|
||||
}
|
||||
parser__recover(self, version, lookahead);
|
||||
if (lookahead == reusable_node->tree) reusable_node_pop(reusable_node);
|
||||
if (lookahead == reusable_node_tree(reusable_node)) {
|
||||
reusable_node_advance(reusable_node);
|
||||
}
|
||||
ts_tree_release(&self->tree_pool, lookahead);
|
||||
return;
|
||||
}
|
||||
|
|
@ -1255,6 +1263,7 @@ bool parser_init(Parser *self) {
|
|||
ts_tree_pool_init(&self->tree_pool);
|
||||
self->stack = ts_stack_new(&self->tree_pool);
|
||||
self->finished_tree = NULL;
|
||||
self->reusable_node = reusable_node_new();
|
||||
parser__set_cached_token(self, 0, NULL, NULL);
|
||||
return true;
|
||||
}
|
||||
|
|
@ -1277,6 +1286,7 @@ void parser_destroy(Parser *self) {
|
|||
if (self->reduce_actions.contents)
|
||||
array_delete(&self->reduce_actions);
|
||||
ts_tree_pool_delete(&self->tree_pool);
|
||||
reusable_node_delete(&self->reusable_node);
|
||||
parser_set_language(self, NULL);
|
||||
}
|
||||
|
||||
|
|
@ -1285,11 +1295,12 @@ Tree *parser_parse(Parser *self, TSInput input, Tree *old_tree, bool halt_on_err
|
|||
|
||||
StackVersion version = STACK_VERSION_NONE;
|
||||
uint32_t position = 0, last_position = 0;
|
||||
ReusableNode reusable_node;
|
||||
ReusableNode reusable_node = reusable_node_new();
|
||||
reusable_node_assign(&reusable_node, &self->reusable_node);
|
||||
|
||||
do {
|
||||
for (version = 0; version < ts_stack_version_count(self->stack); version++) {
|
||||
reusable_node = self->reusable_node;
|
||||
reusable_node_assign(&reusable_node, &self->reusable_node);
|
||||
|
||||
while (ts_stack_is_active(self->stack, version)) {
|
||||
LOG("process version:%d, version_count:%u, state:%d, row:%u, col:%u",
|
||||
|
|
@ -1309,7 +1320,7 @@ Tree *parser_parse(Parser *self, TSInput input, Tree *old_tree, bool halt_on_err
|
|||
}
|
||||
}
|
||||
|
||||
self->reusable_node = reusable_node;
|
||||
reusable_node_assign(&self->reusable_node, &reusable_node);
|
||||
|
||||
unsigned min_error_cost = parser__condense_stack(self);
|
||||
if (self->finished_tree && self->finished_tree->error_cost < min_error_cost) {
|
||||
|
|
@ -1322,6 +1333,7 @@ Tree *parser_parse(Parser *self, TSInput input, Tree *old_tree, bool halt_on_err
|
|||
self->in_ambiguity = version > 1;
|
||||
} while (version != 0);
|
||||
|
||||
reusable_node_delete(&reusable_node);
|
||||
ts_stack_clear(self->stack);
|
||||
parser__set_cached_token(self, 0, NULL, NULL);
|
||||
ts_tree_assign_parents(self->finished_tree, &self->tree_pool, self->language);
|
||||
|
|
|
|||
|
|
@ -2,44 +2,81 @@
|
|||
|
||||
typedef struct {
|
||||
Tree *tree;
|
||||
uint32_t byte_index;
|
||||
uint32_t child_index;
|
||||
uint32_t byte_offset;
|
||||
} StackEntry;
|
||||
|
||||
typedef struct {
|
||||
Array(StackEntry) stack;
|
||||
Tree *last_external_token;
|
||||
} ReusableNode;
|
||||
|
||||
static inline ReusableNode reusable_node_new(Tree *tree) {
|
||||
ReusableNode result = {tree, 0, NULL};
|
||||
return result;
|
||||
static inline ReusableNode reusable_node_new() {
|
||||
return (ReusableNode) {array_new(), NULL};
|
||||
}
|
||||
|
||||
static inline void reusable_node_pop(ReusableNode *self) {
|
||||
self->byte_index += ts_tree_total_bytes(self->tree);
|
||||
if (self->tree->has_external_tokens) {
|
||||
self->last_external_token = ts_tree_last_external_token(self->tree);
|
||||
}
|
||||
|
||||
while (self->tree) {
|
||||
Tree *parent = self->tree->context.parent;
|
||||
uint32_t next_index = self->tree->context.index + 1;
|
||||
if (parent && parent->children.size > next_index) {
|
||||
self->tree = parent->children.contents[next_index];
|
||||
return;
|
||||
}
|
||||
self->tree = parent;
|
||||
}
|
||||
static inline void reusable_node_reset(ReusableNode *self, Tree *tree) {
|
||||
array_clear(&self->stack);
|
||||
array_push(&self->stack, ((StackEntry) {
|
||||
.tree = tree,
|
||||
.child_index = 0,
|
||||
.byte_offset = 0,
|
||||
}));
|
||||
}
|
||||
|
||||
static inline void reusable_node_pop_leaf(ReusableNode *self) {
|
||||
while (self->tree->children.size > 0) {
|
||||
self->tree = self->tree->children.contents[0];
|
||||
}
|
||||
reusable_node_pop(self);
|
||||
static inline Tree *reusable_node_tree(ReusableNode *self) {
|
||||
return array_back(&self->stack)->tree;
|
||||
}
|
||||
|
||||
static inline bool reusable_node_breakdown(ReusableNode *self) {
|
||||
if (self->tree->children.size == 0) {
|
||||
return false;
|
||||
} else {
|
||||
self->tree = self->tree->children.contents[0];
|
||||
static inline uint32_t reusable_node_byte_offset(ReusableNode *self) {
|
||||
return array_back(&self->stack)->byte_offset;
|
||||
}
|
||||
|
||||
static inline void reusable_node_delete(ReusableNode *self) {
|
||||
array_delete(&self->stack);
|
||||
}
|
||||
|
||||
static inline void reusable_node_assign(ReusableNode *self, const ReusableNode *other) {
|
||||
array_assign(&self->stack, &other->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_tree_total_bytes(last_entry.tree);
|
||||
if (last_entry.tree->has_external_tokens) {
|
||||
self->last_external_token = ts_tree_last_external_token(last_entry.tree);
|
||||
}
|
||||
|
||||
Tree *tree;
|
||||
uint32_t next_index;
|
||||
do {
|
||||
StackEntry popped_entry = array_pop(&self->stack);
|
||||
next_index = popped_entry.child_index + 1;
|
||||
tree = array_back(&self->stack)->tree;
|
||||
} while (tree->children.size <= next_index);
|
||||
|
||||
array_push(&self->stack, ((StackEntry) {
|
||||
.tree = tree->children.contents[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 (last_entry.tree->children.size > 0) {
|
||||
array_push(&self->stack, ((StackEntry) {
|
||||
.tree = last_entry.tree->children.contents[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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -169,7 +169,9 @@ Tree *ts_tree_make_copy(TreePool *pool, Tree *self) {
|
|||
return result;
|
||||
}
|
||||
|
||||
static void ts_tree__compress(Tree *self, unsigned count, const TSLanguage *language) {
|
||||
static void ts_tree__compress(Tree *self, unsigned count, const TSLanguage *language, TreeArray *stack) {
|
||||
unsigned initial_stack_size = stack->size;
|
||||
|
||||
Tree *tree = self;
|
||||
for (unsigned i = 0; i < count; i++) {
|
||||
if (tree->ref_count > 1 || tree->children.size != 2) break;
|
||||
|
|
@ -189,22 +191,14 @@ static void ts_tree__compress(Tree *self, unsigned count, const TSLanguage *lang
|
|||
) break;
|
||||
|
||||
tree->children.contents[0] = grandchild;
|
||||
grandchild->context.parent = tree;
|
||||
grandchild->context.index = -1;
|
||||
|
||||
child->children.contents[0] = grandchild->children.contents[1];
|
||||
child->children.contents[0]->context.parent = child;
|
||||
child->children.contents[0]->context.index = -1;
|
||||
|
||||
grandchild->children.contents[1] = child;
|
||||
grandchild->children.contents[1]->context.parent = grandchild;
|
||||
grandchild->children.contents[1]->context.index = -1;
|
||||
|
||||
array_push(stack, tree);
|
||||
tree = grandchild;
|
||||
}
|
||||
|
||||
while (tree != self) {
|
||||
tree = tree->context.parent;
|
||||
while (stack->size > initial_stack_size) {
|
||||
tree = array_pop(stack);
|
||||
Tree *child = tree->children.contents[0];
|
||||
Tree *grandchild = child->children.contents[1];
|
||||
ts_tree_set_children(grandchild, &grandchild->children, language);
|
||||
|
|
@ -213,50 +207,30 @@ static void ts_tree__compress(Tree *self, unsigned count, const TSLanguage *lang
|
|||
}
|
||||
}
|
||||
|
||||
void ts_tree__balance(Tree *self, const TSLanguage *language) {
|
||||
if (self->children.contents[0]->repeat_depth > self->children.contents[1]->repeat_depth) {
|
||||
unsigned n = self->children.contents[0]->repeat_depth - self->children.contents[1]->repeat_depth;
|
||||
for (unsigned i = n / 2; i > 0; i /= 2) {
|
||||
ts_tree__compress(self, i, language);
|
||||
n -= i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ts_tree_assign_parents(Tree *self, TreePool *pool, const TSLanguage *language) {
|
||||
self->context.parent = NULL;
|
||||
array_clear(&pool->tree_stack);
|
||||
array_push(&pool->tree_stack, self);
|
||||
while (pool->tree_stack.size > 0) {
|
||||
Tree *tree = array_pop(&pool->tree_stack);
|
||||
|
||||
if (tree->repeat_depth > 0) {
|
||||
ts_tree__balance(tree, language);
|
||||
if (tree->children.contents[0]->repeat_depth > tree->children.contents[1]->repeat_depth) {
|
||||
unsigned n = (
|
||||
tree->children.contents[0]->repeat_depth -
|
||||
tree->children.contents[1]->repeat_depth
|
||||
);
|
||||
for (unsigned i = n / 2; i > 0; i /= 2) {
|
||||
ts_tree__compress(tree, i, language, &pool->tree_stack);
|
||||
n -= i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Length offset = length_zero();
|
||||
const TSSymbol *alias_sequence = ts_language_alias_sequence(language, tree->alias_sequence_id);
|
||||
uint32_t non_extra_index = 0;
|
||||
bool earlier_child_was_changed = false;
|
||||
for (uint32_t i = 0; i < tree->children.size; i++) {
|
||||
Tree *child = tree->children.contents[i];
|
||||
if (earlier_child_was_changed || child->context.parent != tree || child->context.index != i) {
|
||||
earlier_child_was_changed = true;
|
||||
child->context.parent = tree;
|
||||
child->context.index = i;
|
||||
child->context.offset = offset;
|
||||
if (!child->extra && alias_sequence && alias_sequence[non_extra_index] != 0) {
|
||||
TSSymbolMetadata metadata = ts_language_symbol_metadata(language, alias_sequence[non_extra_index]);
|
||||
child->context.alias_symbol = alias_sequence[non_extra_index];
|
||||
child->context.alias_is_named = metadata.named;
|
||||
} else {
|
||||
child->context.alias_symbol = 0;
|
||||
child->context.alias_is_named = false;
|
||||
}
|
||||
if (child->ref_count == 1) {
|
||||
array_push(&pool->tree_stack, child);
|
||||
}
|
||||
offset = length_add(offset, ts_tree_total_size(child));
|
||||
if (!child->extra) non_extra_index++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -407,25 +381,6 @@ void ts_tree_release(TreePool *pool, Tree *self) {
|
|||
}
|
||||
}
|
||||
|
||||
uint32_t ts_tree_start_column(const Tree *self) {
|
||||
uint32_t column = self->padding.extent.column;
|
||||
if (self->padding.extent.row > 0)
|
||||
return column;
|
||||
for (const Tree *tree = self; tree != NULL; tree = tree->context.parent) {
|
||||
column += tree->context.offset.extent.column;
|
||||
if (tree->context.offset.extent.row > 0)
|
||||
break;
|
||||
}
|
||||
return column;
|
||||
}
|
||||
|
||||
uint32_t ts_tree_end_column(const Tree *self) {
|
||||
uint32_t result = self->size.extent.column;
|
||||
if (self->size.extent.row == 0)
|
||||
result += ts_tree_start_column(self);
|
||||
return result;
|
||||
}
|
||||
|
||||
bool ts_tree_eq(const Tree *self, const Tree *other) {
|
||||
if (self) {
|
||||
if (!other) return false;
|
||||
|
|
@ -577,7 +532,6 @@ void ts_tree_edit(Tree *self, const TSInputEdit *edit) {
|
|||
}
|
||||
|
||||
child_right = length_add(child_left, ts_tree_total_size(child));
|
||||
child->context.offset = child_left;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -612,9 +566,10 @@ static size_t ts_tree__write_char_to_string(char *s, size_t n, int32_t c) {
|
|||
return snprintf(s, n, "%d", c);
|
||||
}
|
||||
|
||||
static size_t ts_tree__write_to_string(const Tree *self, const TSLanguage *language,
|
||||
char *string, size_t limit, bool is_root,
|
||||
bool include_all) {
|
||||
static size_t ts_tree__write_to_string(const Tree *self, char *string, size_t limit,
|
||||
const TSLanguage *language, bool is_root,
|
||||
bool include_all, TSSymbol alias_symbol,
|
||||
bool alias_is_named) {
|
||||
if (!self) return snprintf(string, limit, "(NULL)");
|
||||
|
||||
char *cursor = string;
|
||||
|
|
@ -624,7 +579,7 @@ static size_t ts_tree__write_to_string(const Tree *self, const TSLanguage *langu
|
|||
is_root ||
|
||||
self->is_missing ||
|
||||
(self->visible && self->named) ||
|
||||
self->context.alias_is_named;
|
||||
alias_is_named;
|
||||
|
||||
if (visible && !is_root) {
|
||||
cursor += snprintf(*writer, limit, " ");
|
||||
|
|
@ -637,15 +592,35 @@ static size_t ts_tree__write_to_string(const Tree *self, const TSLanguage *langu
|
|||
} else if (self->is_missing) {
|
||||
cursor += snprintf(*writer, limit, "(MISSING");
|
||||
} else {
|
||||
TSSymbol symbol = self->context.alias_symbol ? self->context.alias_symbol : self->symbol;
|
||||
TSSymbol symbol = alias_symbol ? alias_symbol : self->symbol;
|
||||
const char *symbol_name = ts_language_symbol_name(language, symbol);
|
||||
cursor += snprintf(*writer, limit, "(%s", symbol_name);
|
||||
}
|
||||
}
|
||||
|
||||
const TSSymbol *alias_sequence = ts_language_alias_sequence(language, self->alias_sequence_id);
|
||||
uint32_t structural_child_index = 0;
|
||||
for (uint32_t i = 0; i < self->children.size; i++) {
|
||||
Tree *child = self->children.contents[i];
|
||||
cursor += ts_tree__write_to_string(child, language, *writer, limit, false, include_all);
|
||||
if (child->extra) {
|
||||
cursor += ts_tree__write_to_string(
|
||||
child, *writer, limit,
|
||||
language, false, include_all,
|
||||
0, false
|
||||
);
|
||||
} else {
|
||||
cursor += ts_tree__write_to_string(
|
||||
child, *writer, limit,
|
||||
language, false, include_all,
|
||||
alias_sequence
|
||||
? alias_sequence[structural_child_index]
|
||||
: 0,
|
||||
alias_sequence
|
||||
? ts_language_symbol_metadata(language, alias_sequence[structural_child_index]).named
|
||||
: false
|
||||
);
|
||||
structural_child_index++;
|
||||
}
|
||||
}
|
||||
|
||||
if (visible) cursor += snprintf(*writer, limit, ")");
|
||||
|
|
@ -655,15 +630,19 @@ static size_t ts_tree__write_to_string(const Tree *self, const TSLanguage *langu
|
|||
|
||||
char *ts_tree_string(const Tree *self, const TSLanguage *language, bool include_all) {
|
||||
char scratch_string[1];
|
||||
size_t size = ts_tree__write_to_string(self, language, scratch_string, 0, true, include_all) + 1;
|
||||
size_t size = ts_tree__write_to_string(
|
||||
self, scratch_string, 0,
|
||||
language, true,
|
||||
include_all, 0, false
|
||||
) + 1;
|
||||
char *result = ts_malloc(size * sizeof(char));
|
||||
ts_tree__write_to_string(self, language, result, size, true, include_all);
|
||||
ts_tree__write_to_string(self, result, size, language, true, include_all, 0, false);
|
||||
return result;
|
||||
}
|
||||
|
||||
void ts_tree__print_dot_graph(const Tree *self, uint32_t byte_offset,
|
||||
const TSLanguage *language, FILE *f) {
|
||||
TSSymbol symbol = self->context.alias_symbol ? self->context.alias_symbol : self->symbol;
|
||||
const TSLanguage *language, TSSymbol alias_symbol, FILE *f) {
|
||||
TSSymbol symbol = alias_symbol ? alias_symbol : self->symbol;
|
||||
fprintf(f, "tree_%p [label=\"%s\"", self, ts_language_symbol_name(language, symbol));
|
||||
|
||||
if (self->children.size == 0)
|
||||
|
|
@ -674,9 +653,18 @@ void ts_tree__print_dot_graph(const Tree *self, uint32_t byte_offset,
|
|||
fprintf(f, ", tooltip=\"address:%p\nrange:%u - %u\nstate:%d\nerror-cost:%u\nrepeat-depth:%u\"]\n",
|
||||
self, byte_offset, byte_offset + ts_tree_total_bytes(self), self->parse_state,
|
||||
self->error_cost, self->repeat_depth);
|
||||
|
||||
const TSSymbol *alias_sequence = ts_language_alias_sequence(language, self->alias_sequence_id);
|
||||
uint32_t structural_child_index = 0;
|
||||
for (uint32_t i = 0; i < self->children.size; i++) {
|
||||
const Tree *child = self->children.contents[i];
|
||||
ts_tree__print_dot_graph(child, byte_offset, language, f);
|
||||
if (child->extra) {
|
||||
ts_tree__print_dot_graph(child, byte_offset, language, 0, f);
|
||||
} else {
|
||||
TSSymbol alias_symbol = alias_sequence ? alias_sequence[structural_child_index] : 0;
|
||||
ts_tree__print_dot_graph(child, byte_offset, language, alias_symbol, f);
|
||||
structural_child_index++;
|
||||
}
|
||||
fprintf(f, "tree_%p -> tree_%p [tooltip=%u]\n", self, child, i);
|
||||
byte_offset += ts_tree_total_bytes(child);
|
||||
}
|
||||
|
|
@ -685,7 +673,7 @@ void ts_tree__print_dot_graph(const Tree *self, uint32_t byte_offset,
|
|||
void ts_tree_print_dot_graph(const Tree *self, const TSLanguage *language, FILE *f) {
|
||||
fprintf(f, "digraph tree {\n");
|
||||
fprintf(f, "edge [arrowhead=none]\n");
|
||||
ts_tree__print_dot_graph(self, 0, language, f);
|
||||
ts_tree__print_dot_graph(self, 0, language, 0, f);
|
||||
fprintf(f, "}\n");
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -27,14 +27,6 @@ typedef struct Tree Tree;
|
|||
typedef Array(Tree *) TreeArray;
|
||||
|
||||
struct Tree {
|
||||
struct {
|
||||
struct Tree *parent;
|
||||
uint32_t index;
|
||||
Length offset;
|
||||
TSSymbol alias_symbol : 15;
|
||||
bool alias_is_named : 1;
|
||||
} context;
|
||||
|
||||
Length padding;
|
||||
Length size;
|
||||
uint32_t ref_count;
|
||||
|
|
@ -106,8 +98,6 @@ void ts_tree_retain(Tree *tree);
|
|||
void ts_tree_release(TreePool *, Tree *tree);
|
||||
bool ts_tree_eq(const Tree *tree1, const Tree *tree2);
|
||||
int ts_tree_compare(const Tree *tree1, const Tree *tree2);
|
||||
uint32_t ts_tree_start_column(const Tree *self);
|
||||
uint32_t ts_tree_end_column(const Tree *self);
|
||||
void ts_tree_set_children(Tree *, TreeArray *, const TSLanguage *);
|
||||
void ts_tree_assign_parents(Tree *, TreePool *, const TSLanguage *);
|
||||
void ts_tree_edit(Tree *, const TSInputEdit *edit);
|
||||
|
|
@ -120,6 +110,10 @@ static inline uint32_t ts_tree_total_bytes(const Tree *self) {
|
|||
return self->padding.bytes + self->size.bytes;
|
||||
}
|
||||
|
||||
static inline uint32_t ts_tree_total_rows(const Tree *self) {
|
||||
return self->padding.extent.row + self->size.extent.row;
|
||||
}
|
||||
|
||||
static inline Length ts_tree_total_size(const Tree *self) {
|
||||
return length_add(self->padding, self->size);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -48,7 +48,7 @@ describe("extract_tokens", []() {
|
|||
Repeat{Symbol::non_terminal(3)}
|
||||
},
|
||||
},
|
||||
{}, {}, {}, {}
|
||||
{}, {}, {}, {}, {}
|
||||
});
|
||||
|
||||
InitialSyntaxGrammar &syntax_grammar = get<0>(result);
|
||||
|
|
@ -156,7 +156,7 @@ describe("extract_tokens", []() {
|
|||
})
|
||||
},
|
||||
},
|
||||
{}, {}, {}, {}
|
||||
{}, {}, {}, {}, {}
|
||||
});
|
||||
|
||||
InitialSyntaxGrammar &syntax_grammar = get<0>(result);
|
||||
|
|
@ -203,7 +203,7 @@ describe("extract_tokens", []() {
|
|||
Rule::seq({ String{"ef"}, String{"cd"} })
|
||||
},
|
||||
},
|
||||
{}, {}, {}, {}
|
||||
{}, {}, {}, {}, {}
|
||||
});
|
||||
|
||||
InitialSyntaxGrammar &syntax_grammar = get<0>(result);
|
||||
|
|
@ -258,7 +258,7 @@ describe("extract_tokens", []() {
|
|||
String{"a"}
|
||||
},
|
||||
},
|
||||
{}, {}, {}, {}
|
||||
{}, {}, {}, {}, {}
|
||||
});
|
||||
|
||||
InitialSyntaxGrammar &syntax_grammar = get<0>(result);
|
||||
|
|
@ -298,7 +298,7 @@ describe("extract_tokens", []() {
|
|||
{
|
||||
{ Symbol::non_terminal(2), Symbol::non_terminal(3) }
|
||||
},
|
||||
{}, {}
|
||||
{}, {}, {}
|
||||
});
|
||||
|
||||
InitialSyntaxGrammar &syntax_grammar = get<0>(result);
|
||||
|
|
@ -319,7 +319,7 @@ describe("extract_tokens", []() {
|
|||
String{"y"},
|
||||
Pattern{" "},
|
||||
},
|
||||
{}, {}, {}
|
||||
{}, {}, {}, {}
|
||||
});
|
||||
|
||||
AssertThat(get<2>(result), Equals(CompileError::none()));
|
||||
|
|
@ -340,7 +340,7 @@ describe("extract_tokens", []() {
|
|||
{
|
||||
String{"y"},
|
||||
},
|
||||
{}, {}, {}
|
||||
{}, {}, {}, {}
|
||||
});
|
||||
|
||||
AssertThat(get<2>(result), Equals(CompileError::none()));
|
||||
|
|
@ -370,7 +370,7 @@ describe("extract_tokens", []() {
|
|||
{
|
||||
Symbol::non_terminal(2),
|
||||
},
|
||||
{}, {}, {}
|
||||
{}, {}, {}, {}
|
||||
});
|
||||
|
||||
AssertThat(get<2>(result), Equals(CompileError::none()));
|
||||
|
|
@ -399,7 +399,7 @@ describe("extract_tokens", []() {
|
|||
{
|
||||
Symbol::non_terminal(1)
|
||||
},
|
||||
{}, {}, {}
|
||||
{}, {}, {}, {}
|
||||
});
|
||||
|
||||
AssertThat(get<2>(result), Equals(CompileError(
|
||||
|
|
@ -417,7 +417,7 @@ describe("extract_tokens", []() {
|
|||
{
|
||||
Rule::choice({ Symbol::non_terminal(1), Blank{} })
|
||||
},
|
||||
{}, {}, {}
|
||||
{}, {}, {}, {}
|
||||
});
|
||||
|
||||
AssertThat(get<2>(result), Equals(CompileError(
|
||||
|
|
@ -446,7 +446,7 @@ describe("extract_tokens", []() {
|
|||
{
|
||||
Variable{"rule_A", VariableTypeNamed, Symbol::non_terminal(0)}
|
||||
},
|
||||
{}
|
||||
{}, {}
|
||||
});
|
||||
|
||||
AssertThat(get<2>(result), Equals(CompileError(
|
||||
|
|
|
|||
|
|
@ -1,8 +1,7 @@
|
|||
#include "bandit/bandit.h"
|
||||
#include "test_helper.h"
|
||||
#include "helpers/tree_helpers.h"
|
||||
#include "helpers/point_helpers.h"
|
||||
#include "runtime/document.h"
|
||||
#include "runtime/node.h"
|
||||
#include <ostream>
|
||||
|
||||
using std::string;
|
||||
|
|
@ -21,24 +20,30 @@ TreeArray *tree_array(std::vector<Tree *> trees) {
|
|||
result.capacity = trees.size();
|
||||
result.size = trees.size();
|
||||
result.contents = (Tree **)calloc(trees.size(), sizeof(Tree *));
|
||||
for (size_t i = 0; i < trees.size(); i++)
|
||||
for (size_t i = 0; i < trees.size(); i++) {
|
||||
result.contents[i] = trees[i];
|
||||
}
|
||||
return &result;
|
||||
}
|
||||
|
||||
ostream &operator<<(std::ostream &stream, const Tree *tree) {
|
||||
static TSLanguage DUMMY_LANGUAGE = {};
|
||||
static TSDocument DUMMY_DOCUMENT = {};
|
||||
DUMMY_DOCUMENT.parser.language = &DUMMY_LANGUAGE;
|
||||
DUMMY_LANGUAGE.symbol_names = symbol_names;
|
||||
TSNode node;
|
||||
node.data = tree;
|
||||
return stream << string(ts_node_string(node, &DUMMY_DOCUMENT));
|
||||
char *string = ts_tree_string(tree, &DUMMY_LANGUAGE, false);
|
||||
stream << string;
|
||||
ts_free(string);
|
||||
return stream;
|
||||
}
|
||||
|
||||
ostream &operator<<(ostream &stream, const TSNode &node) {
|
||||
return stream << string("{") << (const Tree *)node.data <<
|
||||
string(", ") << to_string(ts_node_start_byte(node)) << string("}");
|
||||
if (node.subtree) {
|
||||
char *string = ts_node_string(node, node.document);
|
||||
stream << "{" << string << ", " << to_string(ts_node_start_byte(node)) << "}";
|
||||
ts_free(string);
|
||||
return stream;
|
||||
} else {
|
||||
return stream << "NULL";
|
||||
}
|
||||
}
|
||||
|
||||
bool operator==(const TSNode &left, const TSNode &right) {
|
||||
|
|
|
|||
|
|
@ -182,7 +182,7 @@ describe("Document", [&]() {
|
|||
ts_document_parse(document);
|
||||
|
||||
ts_document_set_language(document, load_real_language("javascript"));
|
||||
AssertThat(ts_document_root_node(document).data, Equals<void *>(nullptr));
|
||||
AssertThat(ts_document_root_node(document).subtree, Equals<void *>(nullptr));
|
||||
|
||||
ts_document_parse(document);
|
||||
root = ts_document_root_node(document);
|
||||
|
|
|
|||
|
|
@ -71,6 +71,7 @@ describe("Node", [&]() {
|
|||
document = ts_document_new();
|
||||
ts_document_set_language(document, load_real_language("json"));
|
||||
ts_document_set_input_string(document, json_string.c_str());
|
||||
// ts_document_print_debugging_graphs(document, true);
|
||||
ts_document_parse(document);
|
||||
root_node = ts_node_child(ts_document_root_node(document), 0);
|
||||
});
|
||||
|
|
@ -157,7 +158,7 @@ describe("Node", [&]() {
|
|||
AssertThat(ts_node_parent(number_node), Equals(root_node));
|
||||
AssertThat(ts_node_parent(false_node), Equals(root_node));
|
||||
AssertThat(ts_node_parent(object_node), Equals(root_node));
|
||||
AssertThat(ts_node_parent(ts_document_root_node(document)).data, Equals<void *>(nullptr));
|
||||
AssertThat(ts_node_parent(ts_document_root_node(document)).subtree, Equals<void *>(nullptr));
|
||||
});
|
||||
|
||||
it("works correctly when the node contains aliased children and extras", [&]() {
|
||||
|
|
@ -239,19 +240,7 @@ describe("Node", [&]() {
|
|||
child = ts_node_first_named_child_for_byte(root_node, object_index + 1);
|
||||
AssertThat(ts_node_type(child, document), Equals("object"));
|
||||
child = ts_node_first_named_child_for_byte(root_node, object_end_index);
|
||||
AssertThat(child.data, Equals<void *>(nullptr));
|
||||
});
|
||||
});
|
||||
|
||||
describe("child_index()", [&]() {
|
||||
it("returns the index of the node within its parent", [&]() {
|
||||
AssertThat(ts_node_child_index(ts_node_child(root_node, 0)), Equals(0u));
|
||||
AssertThat(ts_node_child_index(ts_node_child(root_node, 1)), Equals(1u));
|
||||
AssertThat(ts_node_child_index(ts_node_child(root_node, 2)), Equals(2u));
|
||||
AssertThat(ts_node_child_index(ts_node_child(root_node, 3)), Equals(3u));
|
||||
AssertThat(ts_node_child_index(ts_node_child(root_node, 4)), Equals(4u));
|
||||
AssertThat(ts_node_child_index(ts_node_child(root_node, 5)), Equals(5u));
|
||||
AssertThat(ts_node_child_index(ts_node_child(root_node, 6)), Equals(6u));
|
||||
AssertThat(child.subtree, Equals<void *>(nullptr));
|
||||
});
|
||||
});
|
||||
|
||||
|
|
@ -335,7 +324,7 @@ describe("Node", [&]() {
|
|||
AssertThat(ts_node_parent(child5), Equals(root_node));
|
||||
AssertThat(ts_node_parent(child6), Equals(root_node));
|
||||
AssertThat(ts_node_parent(child7), Equals(root_node));
|
||||
AssertThat(ts_node_parent(ts_document_root_node(document)).data, Equals<void *>(nullptr));
|
||||
AssertThat(ts_node_parent(ts_document_root_node(document)).subtree, Equals<void *>(nullptr));
|
||||
});
|
||||
});
|
||||
|
||||
|
|
@ -355,15 +344,16 @@ describe("Node", [&]() {
|
|||
TSNode brace_node2 = ts_node_child(object_node, 2);
|
||||
TSNode bracket_node2 = ts_node_child(root_node, 6);
|
||||
|
||||
AssertThat(ts_node_parent(bracket_node1), Equals(root_node));
|
||||
AssertThat(ts_node_next_sibling(bracket_node1), Equals(number_node));
|
||||
AssertThat(ts_node_next_sibling(number_node), Equals(array_comma_node1));
|
||||
AssertThat(ts_node_next_sibling(array_comma_node1), Equals(false_node));
|
||||
AssertThat(ts_node_next_sibling(false_node), Equals(array_comma_node2));
|
||||
AssertThat(ts_node_next_sibling(array_comma_node2), Equals(object_node));
|
||||
AssertThat(ts_node_next_sibling(object_node), Equals(bracket_node2));
|
||||
AssertThat(ts_node_next_sibling(bracket_node2).data, Equals<void *>(nullptr));
|
||||
AssertThat(ts_node_next_sibling(bracket_node2).subtree, Equals<void *>(nullptr));
|
||||
|
||||
AssertThat(ts_node_prev_sibling(bracket_node1).data, Equals<void *>(nullptr));
|
||||
AssertThat(ts_node_prev_sibling(bracket_node1).subtree, Equals<void *>(nullptr));
|
||||
AssertThat(ts_node_prev_sibling(number_node), Equals(bracket_node1));
|
||||
AssertThat(ts_node_prev_sibling(array_comma_node1), Equals(number_node));
|
||||
AssertThat(ts_node_prev_sibling(false_node), Equals(array_comma_node1));
|
||||
|
|
@ -373,24 +363,24 @@ describe("Node", [&]() {
|
|||
|
||||
AssertThat(ts_node_next_sibling(brace_node1), Equals(pair_node));
|
||||
AssertThat(ts_node_next_sibling(pair_node), Equals(brace_node2));
|
||||
AssertThat(ts_node_next_sibling(brace_node2).data, Equals<void *>(nullptr));
|
||||
AssertThat(ts_node_next_sibling(brace_node2).subtree, Equals<void *>(nullptr));
|
||||
|
||||
AssertThat(ts_node_prev_sibling(brace_node1).data, Equals<void *>(nullptr));
|
||||
AssertThat(ts_node_prev_sibling(brace_node1).subtree, Equals<void *>(nullptr));
|
||||
AssertThat(ts_node_prev_sibling(pair_node), Equals(brace_node1));
|
||||
AssertThat(ts_node_prev_sibling(brace_node2), Equals(pair_node));
|
||||
|
||||
AssertThat(ts_node_next_sibling(string_node), Equals(colon_node));
|
||||
AssertThat(ts_node_next_sibling(colon_node), Equals(null_node));
|
||||
AssertThat(ts_node_next_sibling(null_node).data, Equals<void *>(nullptr));
|
||||
AssertThat(ts_node_next_sibling(null_node).subtree, Equals<void *>(nullptr));
|
||||
|
||||
AssertThat(ts_node_prev_sibling(string_node).data, Equals<void *>(nullptr));
|
||||
AssertThat(ts_node_prev_sibling(string_node).subtree, Equals<void *>(nullptr));
|
||||
AssertThat(ts_node_prev_sibling(colon_node), Equals(string_node));
|
||||
AssertThat(ts_node_prev_sibling(null_node), Equals(colon_node));
|
||||
});
|
||||
|
||||
it("returns null when the node has no parent", [&]() {
|
||||
AssertThat(ts_node_next_named_sibling(root_node).data, Equals<void *>(nullptr));
|
||||
AssertThat(ts_node_prev_named_sibling(root_node).data, Equals<void *>(nullptr));
|
||||
AssertThat(ts_node_next_named_sibling(root_node).subtree, Equals<void *>(nullptr));
|
||||
AssertThat(ts_node_prev_named_sibling(root_node).subtree, Equals<void *>(nullptr));
|
||||
});
|
||||
});
|
||||
|
||||
|
|
@ -412,8 +402,8 @@ describe("Node", [&]() {
|
|||
});
|
||||
|
||||
it("returns null when the node has no parent", [&]() {
|
||||
AssertThat(ts_node_next_named_sibling(root_node).data, Equals<void *>(nullptr));
|
||||
AssertThat(ts_node_prev_named_sibling(root_node).data, Equals<void *>(nullptr));
|
||||
AssertThat(ts_node_next_named_sibling(root_node).subtree, Equals<void *>(nullptr));
|
||||
AssertThat(ts_node_prev_named_sibling(root_node).subtree, Equals<void *>(nullptr));
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -5,14 +5,12 @@
|
|||
#include "runtime/length.h"
|
||||
|
||||
void assert_consistent(const Tree *tree) {
|
||||
if (tree->child_count == 0)
|
||||
return;
|
||||
if (tree->child_count == 0) return;
|
||||
AssertThat(tree->children.contents[0]->padding, Equals<Length>(tree->padding));
|
||||
|
||||
Length total_children_size = length_zero();
|
||||
for (size_t i = 0; i < tree->children.size; i++) {
|
||||
Tree *child = tree->children.contents[i];
|
||||
AssertThat(child->context.offset, Equals(total_children_size));
|
||||
assert_consistent(child);
|
||||
total_children_size = length_add(total_children_size, ts_tree_total_size(child));
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue