Rework API completely
This commit is contained in:
parent
33f7643040
commit
e75ecd1bb1
31 changed files with 841 additions and 1075 deletions
|
|
@ -1,188 +0,0 @@
|
|||
#include "runtime/alloc.h"
|
||||
#include "runtime/subtree.h"
|
||||
#include "runtime/parser.h"
|
||||
#include "runtime/string_input.h"
|
||||
#include "runtime/document.h"
|
||||
#include "runtime/tree_cursor.h"
|
||||
#include "runtime/get_changed_ranges.h"
|
||||
|
||||
#define LOG(...) \
|
||||
snprintf(self->parser.lexer.debug_buffer, TREE_SITTER_SERIALIZATION_BUFFER_SIZE, __VA_ARGS__); \
|
||||
self->parser.lexer.logger.log(self->parser.lexer.logger.payload, TSLogTypeLex, self->parser.lexer.debug_buffer); \
|
||||
|
||||
TSDocument *ts_document_new() {
|
||||
TSDocument *self = ts_calloc(1, sizeof(TSDocument));
|
||||
ts_parser_init(&self->parser);
|
||||
array_init(&self->cursor1.stack);
|
||||
array_init(&self->cursor2.stack);
|
||||
return self;
|
||||
}
|
||||
|
||||
void ts_document_free(TSDocument *self) {
|
||||
if (self->tree) ts_subtree_release(&self->parser.tree_pool, self->tree);
|
||||
if (self->cursor1.stack.contents) array_delete(&self->cursor1.stack);
|
||||
if (self->cursor2.stack.contents) array_delete(&self->cursor2.stack);
|
||||
ts_parser_destroy(&self->parser);
|
||||
ts_document_set_input(self, (TSInput){
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
TSInputEncodingUTF8,
|
||||
});
|
||||
ts_free(self);
|
||||
}
|
||||
|
||||
const TSLanguage *ts_document_language(TSDocument *self) {
|
||||
return self->parser.language;
|
||||
}
|
||||
|
||||
void ts_document_set_language(TSDocument *self, const TSLanguage *language) {
|
||||
if (language->version != TREE_SITTER_LANGUAGE_VERSION) return;
|
||||
ts_document_invalidate(self);
|
||||
ts_parser_set_language(&self->parser, language);
|
||||
if (self->tree) {
|
||||
ts_subtree_release(&self->parser.tree_pool, self->tree);
|
||||
self->tree = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
TSLogger ts_document_logger(const TSDocument *self) {
|
||||
return self->parser.lexer.logger;
|
||||
}
|
||||
|
||||
void ts_document_set_logger(TSDocument *self, TSLogger logger) {
|
||||
self->parser.lexer.logger = logger;
|
||||
}
|
||||
|
||||
void ts_document_print_debugging_graphs(TSDocument *self, bool should_print) {
|
||||
self->parser.print_debugging_graphs = should_print;
|
||||
}
|
||||
|
||||
TSInput ts_document_input(TSDocument *self) {
|
||||
return self->input;
|
||||
}
|
||||
|
||||
void ts_document_set_input(TSDocument *self, TSInput input) {
|
||||
if (self->owns_input)
|
||||
ts_free(self->input.payload);
|
||||
self->input = input;
|
||||
self->owns_input = false;
|
||||
}
|
||||
|
||||
void ts_document_set_input_string(TSDocument *self, const char *text) {
|
||||
ts_document_invalidate(self);
|
||||
TSInput input = ts_string_input_make(text);
|
||||
ts_document_set_input(self, input);
|
||||
if (input.payload) {
|
||||
self->owns_input = true;
|
||||
}
|
||||
}
|
||||
|
||||
void ts_document_set_input_string_with_length(TSDocument *self, const char *text, uint32_t length) {
|
||||
ts_document_invalidate(self);
|
||||
TSInput input = ts_string_input_make_with_length(text, length);
|
||||
ts_document_set_input(self, input);
|
||||
if (input.payload) {
|
||||
self->owns_input = true;
|
||||
}
|
||||
}
|
||||
|
||||
void ts_document_edit(TSDocument *self, TSInputEdit edit) {
|
||||
if (!self->tree)
|
||||
return;
|
||||
|
||||
uint32_t max_bytes = ts_subtree_total_bytes(self->tree);
|
||||
if (edit.start_byte > max_bytes)
|
||||
return;
|
||||
if (edit.bytes_removed > max_bytes - edit.start_byte)
|
||||
edit.bytes_removed = max_bytes - edit.start_byte;
|
||||
|
||||
self->tree = ts_subtree_edit(self->tree, &edit, &self->parser.tree_pool);
|
||||
|
||||
if (self->parser.print_debugging_graphs) {
|
||||
ts_subtree_print_dot_graph(self->tree, self->parser.language, stderr);
|
||||
}
|
||||
}
|
||||
|
||||
void ts_document_parse(TSDocument *self) {
|
||||
ts_document_parse_with_options(self, (TSParseOptions){
|
||||
.halt_on_error = false,
|
||||
.changed_ranges = NULL,
|
||||
.changed_range_count = NULL,
|
||||
});
|
||||
}
|
||||
|
||||
void ts_document_parse_and_get_changed_ranges(TSDocument *self, TSRange **ranges,
|
||||
uint32_t *range_count) {
|
||||
ts_document_parse_with_options(self, (TSParseOptions){
|
||||
.halt_on_error = false,
|
||||
.changed_ranges = ranges,
|
||||
.changed_range_count = range_count,
|
||||
});
|
||||
}
|
||||
|
||||
void ts_document_parse_with_options(TSDocument *self, TSParseOptions options) {
|
||||
if (options.changed_ranges && options.changed_range_count) {
|
||||
*options.changed_ranges = NULL;
|
||||
*options.changed_range_count = 0;
|
||||
}
|
||||
|
||||
if (!self->input.read || !self->parser.language)
|
||||
return;
|
||||
|
||||
Subtree *reusable_tree = self->valid ? self->tree : NULL;
|
||||
if (reusable_tree && !reusable_tree->has_changes)
|
||||
return;
|
||||
|
||||
Subtree *tree = ts_parser_parse(&self->parser, self->input, reusable_tree, options.halt_on_error);
|
||||
|
||||
if (self->tree) {
|
||||
Subtree *old_tree = self->tree;
|
||||
self->tree = tree;
|
||||
|
||||
if (options.changed_ranges && options.changed_range_count) {
|
||||
*options.changed_range_count = ts_subtree_get_changed_ranges(
|
||||
old_tree, tree, &self->cursor1, &self->cursor2,
|
||||
self->parser.language, options.changed_ranges
|
||||
);
|
||||
|
||||
if (self->parser.lexer.logger.log) {
|
||||
for (unsigned i = 0; i < *options.changed_range_count; i++) {
|
||||
TSRange range = (*options.changed_ranges)[i];
|
||||
LOG(
|
||||
"changed_range start:[%u %u], end:[%u %u]",
|
||||
range.start.row, range.start.column,
|
||||
range.end.row, range.end.column
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ts_subtree_release(&self->parser.tree_pool, old_tree);
|
||||
}
|
||||
|
||||
self->tree = tree;
|
||||
self->parse_count++;
|
||||
self->valid = true;
|
||||
}
|
||||
|
||||
void ts_document_invalidate(TSDocument *self) {
|
||||
self->valid = false;
|
||||
}
|
||||
|
||||
TSNode ts_document_root_node(const TSDocument *self) {
|
||||
return (TSNode) {
|
||||
.subtree = self->tree,
|
||||
.document = self,
|
||||
.position = {0, 0},
|
||||
.byte = 0,
|
||||
};
|
||||
}
|
||||
|
||||
uint32_t ts_document_parse_count(const TSDocument *self) {
|
||||
return self->parse_count;
|
||||
}
|
||||
|
||||
TSTreeCursor *ts_document_tree_cursor(const TSDocument *self) {
|
||||
return ts_tree_cursor_new(self);
|
||||
}
|
||||
|
|
@ -1,20 +0,0 @@
|
|||
#ifndef RUNTIME_DOCUMENT_H_
|
||||
#define RUNTIME_DOCUMENT_H_
|
||||
|
||||
#include "runtime/parser.h"
|
||||
#include "runtime/subtree.h"
|
||||
#include "runtime/tree_cursor.h"
|
||||
#include <stdbool.h>
|
||||
|
||||
struct TSDocument {
|
||||
TSParser parser;
|
||||
TSInput input;
|
||||
Subtree *tree;
|
||||
TSTreeCursor cursor1;
|
||||
TSTreeCursor cursor2;
|
||||
size_t parse_count;
|
||||
bool valid;
|
||||
bool owns_input;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
@ -34,7 +34,7 @@ typedef struct {
|
|||
static Iterator iterator_new(TSTreeCursor *cursor, Subtree *tree, const TSLanguage *language) {
|
||||
array_clear(&cursor->stack);
|
||||
array_push(&cursor->stack, ((TreeCursorEntry){
|
||||
.tree = tree,
|
||||
.subtree = tree,
|
||||
.position = length_zero(),
|
||||
.child_index = 0,
|
||||
.structural_child_index = 0,
|
||||
|
|
@ -56,25 +56,25 @@ Length iterator_start_position(Iterator *self) {
|
|||
if (self->in_padding) {
|
||||
return entry.position;
|
||||
} else {
|
||||
return length_add(entry.position, entry.tree->padding);
|
||||
return length_add(entry.position, entry.subtree->padding);
|
||||
}
|
||||
}
|
||||
|
||||
Length iterator_end_position(Iterator *self) {
|
||||
TreeCursorEntry entry = *array_back(&self->cursor.stack);
|
||||
Length result = length_add(entry.position, entry.tree->padding);
|
||||
Length result = length_add(entry.position, entry.subtree->padding);
|
||||
if (self->in_padding) {
|
||||
return result;
|
||||
} else {
|
||||
return length_add(result, entry.tree->size);
|
||||
return length_add(result, entry.subtree->size);
|
||||
}
|
||||
}
|
||||
|
||||
static bool iterator_tree_is_visible(const Iterator *self) {
|
||||
TreeCursorEntry entry = *array_back(&self->cursor.stack);
|
||||
if (entry.tree->visible) return true;
|
||||
if (entry.subtree->visible) return true;
|
||||
if (self->cursor.stack.size > 1) {
|
||||
Subtree *parent = self->cursor.stack.contents[self->cursor.stack.size - 2].tree;
|
||||
Subtree *parent = self->cursor.stack.contents[self->cursor.stack.size - 2].subtree;
|
||||
const TSSymbol *alias_sequence = ts_language_alias_sequence(self->language, parent->alias_sequence_id);
|
||||
return alias_sequence && alias_sequence[entry.structural_child_index] != 0;
|
||||
}
|
||||
|
|
@ -94,7 +94,7 @@ static void iterator_get_visible_state(const Iterator *self, Subtree **tree,
|
|||
TreeCursorEntry entry = self->cursor.stack.contents[i];
|
||||
|
||||
if (i > 0) {
|
||||
Subtree *parent = self->cursor.stack.contents[i - 1].tree;
|
||||
Subtree *parent = self->cursor.stack.contents[i - 1].subtree;
|
||||
const TSSymbol *alias_sequence = ts_language_alias_sequence(
|
||||
self->language,
|
||||
parent->alias_sequence_id
|
||||
|
|
@ -104,8 +104,8 @@ static void iterator_get_visible_state(const Iterator *self, Subtree **tree,
|
|||
}
|
||||
}
|
||||
|
||||
if (entry.tree->visible || *alias_symbol) {
|
||||
*tree = entry.tree;
|
||||
if (entry.subtree->visible || *alias_symbol) {
|
||||
*tree = entry.subtree;
|
||||
*start_byte = entry.position.bytes;
|
||||
break;
|
||||
}
|
||||
|
|
@ -128,14 +128,14 @@ static bool iterator_descend(Iterator *self, uint32_t goal_position) {
|
|||
TreeCursorEntry entry = *array_back(&self->cursor.stack);
|
||||
Length position = entry.position;
|
||||
uint32_t structural_child_index = 0;
|
||||
for (uint32_t i = 0; i < entry.tree->children.size; i++) {
|
||||
Subtree *child = entry.tree->children.contents[i];
|
||||
for (uint32_t i = 0; i < entry.subtree->children.size; i++) {
|
||||
Subtree *child = entry.subtree->children.contents[i];
|
||||
Length child_left = length_add(position, child->padding);
|
||||
Length child_right = length_add(child_left, child->size);
|
||||
|
||||
if (child_right.bytes > goal_position) {
|
||||
array_push(&self->cursor.stack, ((TreeCursorEntry){
|
||||
.tree = child,
|
||||
.subtree = child,
|
||||
.position = position,
|
||||
.child_index = i,
|
||||
.structural_child_index = structural_child_index,
|
||||
|
|
@ -178,16 +178,16 @@ static void iterator_advance(Iterator *self) {
|
|||
TreeCursorEntry entry = array_pop(&self->cursor.stack);
|
||||
if (iterator_done(self)) return;
|
||||
|
||||
Subtree *parent = array_back(&self->cursor.stack)->tree;
|
||||
Subtree *parent = array_back(&self->cursor.stack)->subtree;
|
||||
uint32_t child_index = entry.child_index + 1;
|
||||
if (parent->children.size > child_index) {
|
||||
Length position = length_add(entry.position, ts_subtree_total_size(entry.tree));
|
||||
Length position = length_add(entry.position, ts_subtree_total_size(entry.subtree));
|
||||
uint32_t structural_child_index = entry.structural_child_index;
|
||||
if (!entry.tree->extra) structural_child_index++;
|
||||
if (!entry.subtree->extra) structural_child_index++;
|
||||
Subtree *next_child = parent->children.contents[child_index];
|
||||
|
||||
array_push(&self->cursor.stack, ((TreeCursorEntry){
|
||||
.tree = next_child,
|
||||
.subtree = next_child,
|
||||
.position = position,
|
||||
.child_index = child_index,
|
||||
.structural_child_index = structural_child_index,
|
||||
|
|
@ -250,7 +250,7 @@ static inline void iterator_print_state(Iterator *self) {
|
|||
TreeCursorEntry entry = *array_back(&self->cursor.stack);
|
||||
TSPoint start = iterator_start_position(self).extent;
|
||||
TSPoint end = iterator_end_position(self).extent;
|
||||
const char *name = ts_language_symbol_name(self->language, entry.tree->symbol);
|
||||
const char *name = ts_language_symbol_name(self->language, entry.subtree->symbol);
|
||||
printf(
|
||||
"(%-25s %s\t depth:%u [%u, %u] - [%u, %u])",
|
||||
name, self->in_padding ? "(p)" : " ",
|
||||
|
|
|
|||
|
|
@ -1,13 +1,13 @@
|
|||
#include <stdbool.h>
|
||||
#include "runtime/subtree.h"
|
||||
#include "runtime/document.h"
|
||||
#include "runtime/tree.h"
|
||||
#include "runtime/language.h"
|
||||
|
||||
// NodeChildIterator
|
||||
|
||||
typedef struct {
|
||||
const Subtree *parent;
|
||||
const TSDocument *document;
|
||||
const TSTree *tree;
|
||||
Length position;
|
||||
uint32_t child_index;
|
||||
uint32_t structural_child_index;
|
||||
|
|
@ -19,7 +19,7 @@ typedef struct {
|
|||
static inline TSNode ts_node__null() {
|
||||
return (TSNode) {
|
||||
.subtree = NULL,
|
||||
.document = NULL,
|
||||
.tree = NULL,
|
||||
.position = {0, 0},
|
||||
.byte = 0,
|
||||
};
|
||||
|
|
@ -32,12 +32,12 @@ static inline const Subtree *ts_node__tree(TSNode self) {
|
|||
static inline NodeChildIterator ts_node_child_iterator_begin(const TSNode *node) {
|
||||
const Subtree *tree = ts_node__tree(*node);
|
||||
const TSSymbol *alias_sequence = ts_language_alias_sequence(
|
||||
node->document->parser.language,
|
||||
node->tree->language,
|
||||
tree->alias_sequence_id
|
||||
);
|
||||
return (NodeChildIterator) {
|
||||
.parent = tree,
|
||||
.document = node->document,
|
||||
.tree = node->tree,
|
||||
.position = {node->byte, node->position},
|
||||
.child_index = 0,
|
||||
.structural_child_index = 0,
|
||||
|
|
@ -57,7 +57,7 @@ static inline bool ts_node_child_iterator_next(NodeChildIterator *self, TSNode *
|
|||
}
|
||||
*result = (TSNode) {
|
||||
.subtree = child,
|
||||
.document = self->document,
|
||||
.tree = self->tree,
|
||||
.position = self->position.extent,
|
||||
.byte = self->position.bytes,
|
||||
.alias_symbol = alias_symbol,
|
||||
|
|
@ -77,7 +77,7 @@ static inline bool ts_node__is_relevant(TSNode self, bool include_anonymous) {
|
|||
(
|
||||
self.alias_symbol &&
|
||||
ts_language_symbol_metadata(
|
||||
self.document->parser.language,
|
||||
self.tree->language,
|
||||
self.alias_symbol
|
||||
).named
|
||||
)
|
||||
|
|
@ -343,11 +343,11 @@ TSSymbol ts_node_symbol(TSNode self) {
|
|||
}
|
||||
|
||||
const char *ts_node_type(TSNode self) {
|
||||
return ts_language_symbol_name(self.document->parser.language, ts_node_symbol(self));
|
||||
return ts_language_symbol_name(self.tree->language, ts_node_symbol(self));
|
||||
}
|
||||
|
||||
char *ts_node_string(TSNode self) {
|
||||
return ts_subtree_string(ts_node__tree(self), self.document->parser.language, false);
|
||||
return ts_subtree_string(ts_node__tree(self), self.tree->language, false);
|
||||
}
|
||||
|
||||
bool ts_node_eq(TSNode self, TSNode other) {
|
||||
|
|
@ -360,7 +360,7 @@ bool ts_node_eq(TSNode self, TSNode other) {
|
|||
bool ts_node_is_named(TSNode self) {
|
||||
const Subtree *tree = ts_node__tree(self);
|
||||
return self.alias_symbol
|
||||
? ts_language_symbol_metadata(self.document->parser.language, self.alias_symbol).named
|
||||
? ts_language_symbol_metadata(self.tree->language, self.alias_symbol).named
|
||||
: tree->named;
|
||||
}
|
||||
|
||||
|
|
@ -378,7 +378,7 @@ bool ts_node_has_error(TSNode self) {
|
|||
}
|
||||
|
||||
TSNode ts_node_parent(TSNode self) {
|
||||
TSNode node = ts_document_root_node(self.document);
|
||||
TSNode node = ts_tree_root_node(self.tree);
|
||||
uint32_t end_byte = ts_node_end_byte(self);
|
||||
if (node.subtree == self.subtree) return ts_node__null();
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
#include "runtime/parser.h"
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <limits.h>
|
||||
|
|
@ -10,8 +9,12 @@
|
|||
#include "runtime/array.h"
|
||||
#include "runtime/language.h"
|
||||
#include "runtime/alloc.h"
|
||||
#include "runtime/stack.h"
|
||||
#include "runtime/reusable_node.h"
|
||||
#include "runtime/reduce_action.h"
|
||||
#include "runtime/error_costs.h"
|
||||
#include "runtime/string_input.h"
|
||||
#include "runtime/tree.h"
|
||||
|
||||
#define LOG(...) \
|
||||
if (self->lexer.logger.log || self->print_debugging_graphs) { \
|
||||
|
|
@ -37,6 +40,29 @@ static const unsigned MAX_VERSION_COUNT = 6;
|
|||
static const unsigned MAX_SUMMARY_DEPTH = 16;
|
||||
static const unsigned MAX_COST_DIFFERENCE = 16 * ERROR_COST_PER_SKIPPED_TREE;
|
||||
|
||||
typedef struct {
|
||||
Subtree *token;
|
||||
Subtree *last_external_token;
|
||||
uint32_t byte_index;
|
||||
} TokenCache;
|
||||
|
||||
struct TSParser {
|
||||
Lexer lexer;
|
||||
Stack *stack;
|
||||
SubtreePool tree_pool;
|
||||
const TSLanguage *language;
|
||||
ReduceActionSet reduce_actions;
|
||||
Subtree *finished_tree;
|
||||
Subtree scratch_tree;
|
||||
TokenCache token_cache;
|
||||
ReusableNode reusable_node;
|
||||
void *external_scanner_payload;
|
||||
bool in_ambiguity;
|
||||
bool print_debugging_graphs;
|
||||
bool halt_on_error;
|
||||
unsigned accept_count;
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
unsigned cost;
|
||||
unsigned node_count;
|
||||
|
|
@ -52,6 +78,8 @@ typedef enum {
|
|||
ErrorComparisonTakeRight,
|
||||
} ErrorComparison;
|
||||
|
||||
// Parser - Private
|
||||
|
||||
static void ts_parser__log(TSParser *self) {
|
||||
if (self->lexer.logger.log) {
|
||||
self->lexer.logger.log(
|
||||
|
|
@ -670,7 +698,7 @@ static StackSliceArray ts_parser__reduce(TSParser *self, StackVersion version, T
|
|||
return pop;
|
||||
}
|
||||
|
||||
static void ts_parser__start(TSParser *self, TSInput input, Subtree *previous_tree) {
|
||||
static void ts_parser__start(TSParser *self, TSInput input, const Subtree *previous_tree) {
|
||||
if (previous_tree) {
|
||||
LOG("parse_after_edit");
|
||||
} else {
|
||||
|
|
@ -1258,42 +1286,76 @@ static unsigned ts_parser__condense_stack(TSParser *self) {
|
|||
return min_error_cost;
|
||||
}
|
||||
|
||||
bool ts_parser_init(TSParser *self) {
|
||||
// Parser - Public
|
||||
|
||||
TSParser *ts_parser_new() {
|
||||
TSParser *self = ts_calloc(1, sizeof(TSParser));
|
||||
ts_lexer_init(&self->lexer);
|
||||
array_init(&self->reduce_actions);
|
||||
array_reserve(&self->reduce_actions, 4);
|
||||
ts_subtree_pool_init(&self->tree_pool);
|
||||
self->tree_pool = ts_subtree_pool_new(32);
|
||||
self->stack = ts_stack_new(&self->tree_pool);
|
||||
self->finished_tree = NULL;
|
||||
self->reusable_node = reusable_node_new();
|
||||
self->print_debugging_graphs = false;
|
||||
self->halt_on_error = false;
|
||||
ts_parser__set_cached_token(self, 0, NULL, NULL);
|
||||
return true;
|
||||
return self;
|
||||
}
|
||||
|
||||
void ts_parser_set_language(TSParser *self, const TSLanguage *language) {
|
||||
if (self->external_scanner_payload && self->language->external_scanner.destroy)
|
||||
self->language->external_scanner.destroy(self->external_scanner_payload);
|
||||
|
||||
if (language && language->external_scanner.create)
|
||||
self->external_scanner_payload = language->external_scanner.create();
|
||||
else
|
||||
self->external_scanner_payload = NULL;
|
||||
|
||||
self->language = language;
|
||||
}
|
||||
|
||||
void ts_parser_destroy(TSParser *self) {
|
||||
if (self->stack)
|
||||
void ts_parser_delete(TSParser *self) {
|
||||
if (self->stack) {
|
||||
ts_stack_delete(self->stack);
|
||||
if (self->reduce_actions.contents)
|
||||
}
|
||||
if (self->reduce_actions.contents) {
|
||||
array_delete(&self->reduce_actions);
|
||||
}
|
||||
ts_subtree_pool_delete(&self->tree_pool);
|
||||
reusable_node_delete(&self->reusable_node);
|
||||
ts_parser_set_language(self, NULL);
|
||||
ts_free(self);
|
||||
}
|
||||
|
||||
Subtree *ts_parser_parse(TSParser *self, TSInput input, Subtree *old_tree, bool halt_on_error) {
|
||||
ts_parser__start(self, input, old_tree);
|
||||
const TSLanguage *ts_parser_language(const TSParser *self) {
|
||||
return self->language;
|
||||
}
|
||||
|
||||
bool ts_parser_set_language(TSParser *self, const TSLanguage *language) {
|
||||
if (language && language->version != TREE_SITTER_LANGUAGE_VERSION) return false;
|
||||
|
||||
if (self->external_scanner_payload && self->language->external_scanner.destroy) {
|
||||
self->language->external_scanner.destroy(self->external_scanner_payload);
|
||||
}
|
||||
|
||||
if (language && language->external_scanner.create) {
|
||||
self->external_scanner_payload = language->external_scanner.create();
|
||||
} else {
|
||||
self->external_scanner_payload = NULL;
|
||||
}
|
||||
|
||||
self->language = language;
|
||||
return true;
|
||||
}
|
||||
|
||||
TSLogger ts_parser_logger(const TSParser *self) {
|
||||
return self->lexer.logger;
|
||||
}
|
||||
|
||||
void ts_parser_set_logger(TSParser *self, TSLogger logger) {
|
||||
self->lexer.logger = logger;
|
||||
}
|
||||
|
||||
void ts_parser_print_debugging_graphs(TSParser *self, bool should_print) {
|
||||
self->print_debugging_graphs = should_print;
|
||||
}
|
||||
|
||||
void ts_parser_halt_on_error(TSParser *self, bool should_halt_on_error) {
|
||||
self->halt_on_error = should_halt_on_error;
|
||||
}
|
||||
|
||||
TSTree *ts_parser_parse(TSParser *self, const TSTree *old_tree, TSInput input) {
|
||||
if (!self->language) return NULL;
|
||||
ts_parser__start(self, input, old_tree ? old_tree->root : NULL);
|
||||
|
||||
StackVersion version = STACK_VERSION_NONE;
|
||||
uint32_t position = 0, last_position = 0;
|
||||
|
|
@ -1327,7 +1389,7 @@ Subtree *ts_parser_parse(TSParser *self, TSInput input, Subtree *old_tree, bool
|
|||
unsigned min_error_cost = ts_parser__condense_stack(self);
|
||||
if (self->finished_tree && self->finished_tree->error_cost < min_error_cost) {
|
||||
break;
|
||||
} else if (halt_on_error && min_error_cost > 0) {
|
||||
} else if (self->halt_on_error && min_error_cost > 0) {
|
||||
ts_parser__halt_parse(self);
|
||||
break;
|
||||
}
|
||||
|
|
@ -1342,5 +1404,13 @@ Subtree *ts_parser_parse(TSParser *self, TSInput input, Subtree *old_tree, bool
|
|||
|
||||
LOG("done");
|
||||
LOG_TREE();
|
||||
return self->finished_tree;
|
||||
|
||||
return ts_tree_new(self->finished_tree, self->language);
|
||||
}
|
||||
|
||||
TSTree *ts_parser_parse_string(TSParser *self, const TSTree *old_tree,
|
||||
const char *string, uint32_t length) {
|
||||
TSStringInput input;
|
||||
ts_string_input_init(&input, string, length);
|
||||
return ts_parser_parse(self, old_tree, input.input);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,46 +0,0 @@
|
|||
#ifndef RUNTIME_PARSER_H_
|
||||
#define RUNTIME_PARSER_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "runtime/stack.h"
|
||||
#include "runtime/array.h"
|
||||
#include "runtime/lexer.h"
|
||||
#include "runtime/reusable_node.h"
|
||||
#include "runtime/reduce_action.h"
|
||||
#include "runtime/subtree.h"
|
||||
|
||||
typedef struct {
|
||||
Subtree *token;
|
||||
Subtree *last_external_token;
|
||||
uint32_t byte_index;
|
||||
} TokenCache;
|
||||
|
||||
typedef struct {
|
||||
Lexer lexer;
|
||||
Stack *stack;
|
||||
SubtreePool tree_pool;
|
||||
const TSLanguage *language;
|
||||
ReduceActionSet reduce_actions;
|
||||
Subtree *finished_tree;
|
||||
Subtree scratch_tree;
|
||||
TokenCache token_cache;
|
||||
ReusableNode reusable_node;
|
||||
void *external_scanner_payload;
|
||||
bool in_ambiguity;
|
||||
bool print_debugging_graphs;
|
||||
unsigned accept_count;
|
||||
} TSParser;
|
||||
|
||||
bool ts_parser_init(TSParser *);
|
||||
void ts_parser_destroy(TSParser *);
|
||||
Subtree *ts_parser_parse(TSParser *, TSInput, Subtree *, bool halt_on_error);
|
||||
void ts_parser_set_language(TSParser *, const TSLanguage *);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // RUNTIME_PARSER_H_
|
||||
|
|
@ -24,7 +24,7 @@ static inline void reusable_node_reset(ReusableNode *self, Subtree *tree) {
|
|||
}));
|
||||
}
|
||||
|
||||
static inline Subtree *reusable_node_tree(ReusableNode *self) {
|
||||
static inline const Subtree *reusable_node_tree(ReusableNode *self) {
|
||||
return self->stack.size > 0
|
||||
? self->stack.contents[self->stack.size - 1].tree
|
||||
: NULL;
|
||||
|
|
|
|||
|
|
@ -1,13 +1,7 @@
|
|||
#include "tree_sitter/runtime.h"
|
||||
#include "runtime/string_input.h"
|
||||
#include "runtime/alloc.h"
|
||||
#include <string.h>
|
||||
|
||||
typedef struct {
|
||||
const char *string;
|
||||
uint32_t position;
|
||||
uint32_t length;
|
||||
} TSStringInput;
|
||||
|
||||
static const char *ts_string_input__read(void *payload, uint32_t *bytes_read) {
|
||||
TSStringInput *input = (TSStringInput *)payload;
|
||||
if (input->position >= input->length) {
|
||||
|
|
@ -26,17 +20,12 @@ static int ts_string_input__seek(void *payload, uint32_t byte, TSPoint _) {
|
|||
return (byte < input->length);
|
||||
}
|
||||
|
||||
TSInput ts_string_input_make(const char *string) {
|
||||
return ts_string_input_make_with_length(string, strlen(string));
|
||||
}
|
||||
|
||||
TSInput ts_string_input_make_with_length(const char *string, uint32_t length) {
|
||||
TSStringInput *input = ts_malloc(sizeof(TSStringInput));
|
||||
input->string = string;
|
||||
input->position = 0;
|
||||
input->length = length;
|
||||
return (TSInput){
|
||||
.payload = input,
|
||||
void ts_string_input_init(TSStringInput *self, const char *string, uint32_t length) {
|
||||
self->string = string;
|
||||
self->position = 0;
|
||||
self->length = length;
|
||||
self->input = (TSInput) {
|
||||
.payload = self,
|
||||
.read = ts_string_input__read,
|
||||
.seek = ts_string_input__seek,
|
||||
.encoding = TSInputEncodingUTF8,
|
||||
|
|
|
|||
|
|
@ -7,8 +7,14 @@ extern "C" {
|
|||
|
||||
#include "tree_sitter/runtime.h"
|
||||
|
||||
TSInput ts_string_input_make(const char *);
|
||||
TSInput ts_string_input_make_with_length(const char *, uint32_t);
|
||||
typedef struct {
|
||||
const char *string;
|
||||
uint32_t position;
|
||||
uint32_t length;
|
||||
TSInput input;
|
||||
} TSStringInput;
|
||||
|
||||
void ts_string_input_init(TSStringInput *, const char *, uint32_t);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,6 +19,10 @@ typedef struct {
|
|||
|
||||
TSStateId TS_TREE_STATE_NONE = USHRT_MAX;
|
||||
|
||||
static const uint32_t MAX_TREE_POOL_SIZE = 1024;
|
||||
|
||||
static const TSExternalTokenState empty_state = {.length = 0, .short_data = {0}};
|
||||
|
||||
// ExternalTokenState
|
||||
|
||||
void ts_external_token_state_init(TSExternalTokenState *self, const char *content, unsigned length) {
|
||||
|
|
@ -102,11 +106,10 @@ void ts_subtree_array_reverse(SubtreeArray *self) {
|
|||
|
||||
// SubtreePool
|
||||
|
||||
static const uint32_t MAX_TREE_POOL_SIZE = 1024;
|
||||
|
||||
void ts_subtree_pool_init(SubtreePool *self) {
|
||||
array_init(&self->free_trees);
|
||||
array_init(&self->tree_stack);
|
||||
SubtreePool ts_subtree_pool_new(uint32_t capacity) {
|
||||
SubtreePool self = {array_new(), array_new()};
|
||||
array_reserve(&self.free_trees, capacity);
|
||||
return self;
|
||||
}
|
||||
|
||||
void ts_subtree_pool_delete(SubtreePool *self) {
|
||||
|
|
@ -128,7 +131,7 @@ Subtree *ts_subtree_pool_allocate(SubtreePool *self) {
|
|||
}
|
||||
|
||||
void ts_subtree_pool_free(SubtreePool *self, Subtree *tree) {
|
||||
if (self->free_trees.size < MAX_TREE_POOL_SIZE) {
|
||||
if (self->free_trees.capacity > 0 && self->free_trees.size < MAX_TREE_POOL_SIZE) {
|
||||
array_push(&self->free_trees, tree);
|
||||
} else {
|
||||
ts_free(tree);
|
||||
|
|
@ -691,8 +694,6 @@ void ts_subtree_print_dot_graph(const Subtree *self, const TSLanguage *language,
|
|||
fprintf(f, "}\n");
|
||||
}
|
||||
|
||||
static const TSExternalTokenState empty_state = {.length = 0, .short_data = {0}};
|
||||
|
||||
bool ts_subtree_external_token_state_eq(const Subtree *self, const Subtree *other) {
|
||||
const TSExternalTokenState *state1 = &empty_state;
|
||||
const TSExternalTokenState *state2 = &empty_state;
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
#ifndef RUNTIME_TREE_H_
|
||||
#define RUNTIME_TREE_H_
|
||||
#ifndef RUNTIME_SUBTREE_H_
|
||||
#define RUNTIME_SUBTREE_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
|
|
@ -83,7 +83,7 @@ void ts_subtree_array_delete(SubtreePool *, SubtreeArray *);
|
|||
SubtreeArray ts_subtree_array_remove_trailing_extras(SubtreeArray *);
|
||||
void ts_subtree_array_reverse(SubtreeArray *);
|
||||
|
||||
void ts_subtree_pool_init(SubtreePool *);
|
||||
SubtreePool ts_subtree_pool_new(uint32_t capacity);
|
||||
void ts_subtree_pool_delete(SubtreePool *);
|
||||
Subtree *ts_subtree_pool_allocate(SubtreePool *);
|
||||
void ts_subtree_pool_free(SubtreePool *, Subtree *);
|
||||
|
|
@ -122,4 +122,4 @@ static inline Length ts_subtree_total_size(const Subtree *self) {
|
|||
}
|
||||
#endif
|
||||
|
||||
#endif // RUNTIME_TREE_H_
|
||||
#endif // RUNTIME_SUBTREE_H_
|
||||
|
|
|
|||
59
src/runtime/tree.c
Normal file
59
src/runtime/tree.c
Normal file
|
|
@ -0,0 +1,59 @@
|
|||
#include "tree_sitter/runtime.h"
|
||||
#include "runtime/array.h"
|
||||
#include "runtime/get_changed_ranges.h"
|
||||
#include "runtime/subtree.h"
|
||||
#include "runtime/tree_cursor.h"
|
||||
#include "runtime/tree.h"
|
||||
|
||||
TSTree *ts_tree_new(const Subtree *root, const TSLanguage *language) {
|
||||
TSTree *result = ts_malloc(sizeof(TSTree));
|
||||
result->root = root;
|
||||
result->language = language;
|
||||
return result;
|
||||
}
|
||||
|
||||
TSTree *ts_tree_copy(const TSTree *self) {
|
||||
ts_subtree_retain(self->root);
|
||||
return ts_tree_new(self->root, self->language);
|
||||
}
|
||||
|
||||
void ts_tree_delete(const TSTree *self) {
|
||||
SubtreePool pool = ts_subtree_pool_new(0);
|
||||
ts_subtree_release(&pool, self->root);
|
||||
ts_subtree_pool_delete(&pool);
|
||||
ts_free(self);
|
||||
}
|
||||
|
||||
TSNode ts_tree_root_node(const TSTree *self) {
|
||||
return (TSNode) {
|
||||
.subtree = self->root,
|
||||
.tree = self,
|
||||
.position = {0, 0},
|
||||
.byte = 0,
|
||||
.alias_symbol = 0,
|
||||
};
|
||||
}
|
||||
|
||||
void ts_tree_edit(TSTree *self, const TSInputEdit *edit) {
|
||||
SubtreePool pool = ts_subtree_pool_new(0);
|
||||
self->root = ts_subtree_edit(self->root, edit, &pool);
|
||||
assert(pool.tree_stack.capacity == 0 && pool.free_trees.capacity == 0);
|
||||
}
|
||||
|
||||
TSRange *ts_tree_get_changed_ranges(const TSTree *self, const TSTree *other, uint32_t *count) {
|
||||
TSRange *result;
|
||||
TSTreeCursor cursor1, cursor2;
|
||||
ts_tree_cursor_init(&cursor1, self);
|
||||
ts_tree_cursor_init(&cursor2, self);
|
||||
*count = ts_subtree_get_changed_ranges(
|
||||
self->root, other->root, &cursor1, &cursor2,
|
||||
self->language, &result
|
||||
);
|
||||
array_delete(&cursor1.stack);
|
||||
array_delete(&cursor2.stack);
|
||||
return result;
|
||||
}
|
||||
|
||||
void ts_tree_print_dot_graph(const TSTree *self, FILE *file) {
|
||||
ts_subtree_print_dot_graph(self->root, self->language, file);
|
||||
}
|
||||
19
src/runtime/tree.h
Normal file
19
src/runtime/tree.h
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
#ifndef RUNTIME_TREE_H_
|
||||
#define RUNTIME_TREE_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct TSTree {
|
||||
const Subtree *root;
|
||||
const TSLanguage *language;
|
||||
};
|
||||
|
||||
TSTree *ts_tree_new(const Subtree *root, const TSLanguage *language);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // RUNTIME_TREE_H_
|
||||
|
|
@ -1,20 +1,24 @@
|
|||
#include "tree_sitter/runtime.h"
|
||||
#include "runtime/alloc.h"
|
||||
#include "runtime/tree_cursor.h"
|
||||
#include "runtime/document.h"
|
||||
#include "runtime/language.h"
|
||||
#include "runtime/tree.h"
|
||||
|
||||
TSTreeCursor *ts_tree_cursor_new(const TSDocument *document) {
|
||||
TSTreeCursor *ts_tree_cursor_new(const TSTree *tree) {
|
||||
TSTreeCursor *self = ts_malloc(sizeof(TSTreeCursor));
|
||||
self->document = document;
|
||||
ts_tree_cursor_init(self, tree);
|
||||
return self;
|
||||
}
|
||||
|
||||
void ts_tree_cursor_init(TSTreeCursor *self, const TSTree *tree) {
|
||||
self->tree = tree;
|
||||
array_init(&self->stack);
|
||||
array_push(&self->stack, ((TreeCursorEntry) {
|
||||
.tree = document->tree,
|
||||
.subtree = tree->root,
|
||||
.position = length_zero(),
|
||||
.child_index = 0,
|
||||
.structural_child_index = 0,
|
||||
}));
|
||||
return self;
|
||||
}
|
||||
|
||||
void ts_tree_cursor_delete(TSTreeCursor *self) {
|
||||
|
|
@ -24,7 +28,7 @@ void ts_tree_cursor_delete(TSTreeCursor *self) {
|
|||
|
||||
bool ts_tree_cursor_goto_first_child(TSTreeCursor *self) {
|
||||
TreeCursorEntry *last_entry = array_back(&self->stack);
|
||||
Subtree *tree = last_entry->tree;
|
||||
Subtree *tree = last_entry->subtree;
|
||||
Length position = last_entry->position;
|
||||
|
||||
bool did_descend;
|
||||
|
|
@ -36,7 +40,7 @@ bool ts_tree_cursor_goto_first_child(TSTreeCursor *self) {
|
|||
Subtree *child = tree->children.contents[i];
|
||||
if (child->visible || child->visible_child_count > 0) {
|
||||
array_push(&self->stack, ((TreeCursorEntry) {
|
||||
.tree = child,
|
||||
.subtree = child,
|
||||
.child_index = i,
|
||||
.structural_child_index = structural_child_index,
|
||||
.position = position,
|
||||
|
|
@ -64,7 +68,7 @@ bool ts_tree_cursor_goto_next_sibling(TSTreeCursor *self) {
|
|||
for (unsigned i = self->stack.size - 2; i + 1 > 0; i--) {
|
||||
TreeCursorEntry *parent_entry = &self->stack.contents[i];
|
||||
|
||||
Subtree *parent = parent_entry->tree;
|
||||
Subtree *parent = parent_entry->subtree;
|
||||
uint32_t child_index = child_entry->child_index;
|
||||
uint32_t structural_child_index = child_entry->structural_child_index;
|
||||
Length position = child_entry->position;
|
||||
|
|
@ -77,7 +81,7 @@ bool ts_tree_cursor_goto_next_sibling(TSTreeCursor *self) {
|
|||
|
||||
if (child->visible || child->visible_child_count > 0) {
|
||||
self->stack.contents[i + 1] = (TreeCursorEntry) {
|
||||
.tree = child,
|
||||
.subtree = child,
|
||||
.child_index = child_index,
|
||||
.structural_child_index = structural_child_index,
|
||||
.position = position,
|
||||
|
|
@ -103,7 +107,7 @@ bool ts_tree_cursor_goto_next_sibling(TSTreeCursor *self) {
|
|||
bool ts_tree_cursor_goto_parent(TSTreeCursor *self) {
|
||||
for (unsigned i = self->stack.size - 2; i + 1 > 0; i--) {
|
||||
TreeCursorEntry *entry = &self->stack.contents[i];
|
||||
if (entry->tree->visible) {
|
||||
if (entry->subtree->visible) {
|
||||
self->stack.size = i + 1;
|
||||
return true;
|
||||
}
|
||||
|
|
@ -117,16 +121,16 @@ TSNode ts_tree_cursor_current_node(TSTreeCursor *self) {
|
|||
if (self->stack.size > 1) {
|
||||
TreeCursorEntry *parent_entry = &self->stack.contents[self->stack.size - 2];
|
||||
const TSSymbol *alias_sequence = ts_language_alias_sequence(
|
||||
self->document->parser.language,
|
||||
parent_entry->tree->alias_sequence_id
|
||||
self->tree->language,
|
||||
parent_entry->subtree->alias_sequence_id
|
||||
);
|
||||
if (alias_sequence) {
|
||||
alias_symbol = alias_sequence[last_entry->structural_child_index];
|
||||
}
|
||||
}
|
||||
return (TSNode) {
|
||||
.document = self->document,
|
||||
.subtree = last_entry->tree,
|
||||
.tree = self->tree,
|
||||
.subtree = last_entry->subtree,
|
||||
.position = last_entry->position.extent,
|
||||
.byte = last_entry->position.bytes,
|
||||
.alias_symbol = alias_symbol,
|
||||
|
|
|
|||
|
|
@ -4,17 +4,17 @@
|
|||
#include "runtime/subtree.h"
|
||||
|
||||
typedef struct {
|
||||
Subtree *tree;
|
||||
Subtree *subtree;
|
||||
Length position;
|
||||
uint32_t child_index;
|
||||
uint32_t structural_child_index;
|
||||
} TreeCursorEntry;
|
||||
|
||||
struct TSTreeCursor {
|
||||
const TSDocument *document;
|
||||
const TSTree *tree;
|
||||
Array(TreeCursorEntry) stack;
|
||||
};
|
||||
|
||||
TSTreeCursor *ts_tree_cursor_new(const TSDocument *);
|
||||
void ts_tree_cursor_init(TSTreeCursor *, const TSTree *);
|
||||
|
||||
#endif // RUNTIME_TREE_CURSOR_H_
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue