From fd4c33209e687e64d54041f3500ed74dceda7a0d Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Sun, 24 Apr 2016 00:54:20 -0700 Subject: [PATCH] Select ambiguous alternatives by minimizing error size --- spec/helpers/reference_stack.cc | 151 ++++++++++++++++++++++++++++++++ spec/helpers/reference_stack.h | 53 +++++++++++ spec/runtime/stack_spec.cc | 58 ++---------- src/runtime/array.h | 12 +-- src/runtime/parser.c | 139 ++++++++++++++++++----------- src/runtime/parser.h | 1 + src/runtime/stack.c | 70 +++------------ src/runtime/stack.h | 7 +- src/runtime/tree.c | 10 +++ src/runtime/tree.h | 2 + 10 files changed, 329 insertions(+), 174 deletions(-) create mode 100644 spec/helpers/reference_stack.cc create mode 100644 spec/helpers/reference_stack.h diff --git a/spec/helpers/reference_stack.cc b/spec/helpers/reference_stack.cc new file mode 100644 index 00000000..d0d930e1 --- /dev/null +++ b/spec/helpers/reference_stack.cc @@ -0,0 +1,151 @@ +#include "helpers/reference_stack.h" +#include + +using std::vector; + +struct PotentialSlice { + StackVersion head_index; + vector trees; +}; + +ReferenceStack::ReferenceStack() { + clear(); +} + +ReferenceStack::~ReferenceStack() { + clear(); +} + +void ReferenceStack::clear() { + for (Version &version : versions) { + while (!version.empty()) { + ts_tree_release(version.top().tree); + version.pop(); + } + } + + Version initial_version; + initial_version.push(Node{{0, ts_length_zero()}, NULL, false}); + + versions = {initial_version}; + version_ids = {initial_version.top().id}; +} + +int ReferenceStack::head_count() const { + return version_ids.size(); +} + +TSStateId ReferenceStack::top_state(int head_index) const { + return version_ids[head_index].state; +} + +TSLength ReferenceStack::top_position(int head_index) const { + return version_ids[head_index].position; +} + +StackVersion ReferenceStack::push(int head_index, TSTree *tree, bool is_verifying, TSStateId state) { + NodeId id = version_ids[head_index]; + NodeId new_id = {state, ts_length_add(id.position, ts_tree_total_size(tree))}; + + StackVersion i = -1, existing_id = -1; + for (Version &version : versions) { + i++; + Node top = version.top(); + if (top.id == new_id) { + existing_id = i; + } else if (top.id == id) { + ts_tree_retain(tree); + version.push(Node{new_id, tree, false}); + } + } + + if (existing_id != -1) { + version_ids.erase(version_ids.begin() + head_index); + return existing_id; + } else { + version_ids[head_index] = new_id; + return head_index; + } +} + +StackPopResult ReferenceStack::pop_count(int head_index, int goal_count) { + NodeId id = version_ids[head_index]; + + vector new_versions; + vector potential_slices; + + for (const Version &version : versions) + if (version.top().id == id) { + PotentialSlice potential_slice; + Version new_version = version; + size_t tree_count = 0; + + while (!new_version.empty()) { + TSTree *tree = new_version.top().tree; + if (tree->symbol == ts_builtin_sym_error) + return StackPopResult{ + StackPopResult::StackPopStoppedAtError, + finalize_slices({potential_slice}), + }; + if (!tree->extra) + tree_count++; + + potential_slice.trees.insert(potential_slice.trees.begin(), tree); + new_version.pop(); + + if (tree_count == goal_count) { + potential_slice.head_index = find_or_add_node_id(new_version.top().id); + new_versions.push_back(new_version); + potential_slices.push_back(potential_slice); + break; + } + } + } + + for (auto i = potential_slices.begin(); i != potential_slices.end();) { + bool merged = false; + for (auto j = potential_slices.begin(); j < i; ++j) { + if (i->head_index == j->head_index) { + merged = true; + j->trees = merge_trees(j->trees, i->trees); + potential_slices.erase(i); + break; + } + } + if (!merged) ++i; + } + + versions.insert(versions.end(), new_versions.begin(), new_versions.end()); + + return StackPopResult{ + StackPopResult::StackPopSucceeded, + finalize_slices(potential_slices), + }; +} + +// Private + +int ReferenceStack::find_or_add_node_id(NodeId id) { + for (int i = 0; i < version_ids.size(); i++) + if (version_ids[i] == id) + return i; + version_ids.push_back(id); + return version_ids.size() - 1; +} + +vector ReferenceStack::merge_trees(vector left, vector right) const { + return left; +} + +StackSliceArray ReferenceStack::finalize_slices(const vector &potential_slices) const { + StackSliceArray result = array_new(); + for (const PotentialSlice &potential_slice : potential_slices) { + StackSlice slice{array_new(), potential_slice.head_index}; + for (TSTree *tree : potential_slice.trees) { + ts_tree_retain(tree); + array_push(&slice.trees, tree); + } + array_push(&result, slice); + } + return result; +} diff --git a/spec/helpers/reference_stack.h b/spec/helpers/reference_stack.h new file mode 100644 index 00000000..fb711e73 --- /dev/null +++ b/spec/helpers/reference_stack.h @@ -0,0 +1,53 @@ +#ifndef HELPERS_REFERENCE_STACK_H_ +#define HELPERS_REFERENCE_STACK_H_ + +#include "runtime/stack.h" +#include +#include + +struct PotentialSlice; + +class ReferenceStack { + public: + ReferenceStack(); + ~ReferenceStack(); + + int head_count() const; + TSStateId top_state(int head_index) const; + TSLength top_position(int head_index) const; + + StackVersion push(int head_index, TSTree *tree, bool is_verifying, TSStateId state); + StackPopResult pop_count(int head_index, int count); + StackPopResult pop_until(int head_index, StackIterateCallback, void *); + + void remove_head(int head_index); + void clear(); + + private: + struct NodeId { + TSStateId state; + TSLength position; + + bool operator==(const NodeId &other) const { + return state == other.state && ts_length_eq(position, other.position); + } + }; + + struct Node { + NodeId id; + TSTree *tree; + bool is_verifying; + }; + + typedef std::stack Version; + + int find_or_add_node_id(NodeId id); + std::vector merge_trees(std::vector, std::vector) const; + StackSliceArray finalize_slices(const std::vector &) const; + + std::vector versions; + std::vector version_ids; + void *tree_selection_payload; +}; + +#endif // HELPERS_REFERENCE_STACK_H_ diff --git a/spec/runtime/stack_spec.cc b/spec/runtime/stack_spec.cc index 47e55ec7..df015464 100644 --- a/spec/runtime/stack_spec.cc +++ b/spec/runtime/stack_spec.cc @@ -18,32 +18,10 @@ enum { symbol9, symbol10 }; -struct TreeSelectionSpy { - TreeSelectionSpy() : - call_count(0), - tree_to_return(nullptr), - arguments{nullptr, nullptr} {} - int call_count; - TSTree *tree_to_return; - const TSTree *arguments[2]; -}; - TSLength operator*(const TSLength &length, size_t factor) { return {length.bytes * factor, length.chars * factor, 0, length.columns * factor}; } -extern "C" -int tree_selection_spy_callback(void *data, TSTree *left, TSTree *right) { - TreeSelectionSpy *spy = (TreeSelectionSpy *)data; - spy->call_count++; - spy->arguments[0] = left; - spy->arguments[1] = right; - if (spy->tree_to_return == left) - return -1; - else - return 1; -} - void free_slice_array(StackSliceArray *slices) { for (size_t i = 0; i < slices->size; i++) { StackSlice slice = slices->contents[i]; @@ -91,7 +69,6 @@ describe("Stack", [&]() { Stack *stack; const size_t tree_count = 11; TSTree *trees[tree_count]; - TreeSelectionSpy tree_selection_spy; TSLength tree_len = {2, 3, 0, 3}; before_each([&]() { @@ -99,11 +76,6 @@ describe("Stack", [&]() { stack = ts_stack_new(); - ts_stack_set_tree_selection_callback(stack, - &tree_selection_spy, - tree_selection_spy_callback - ); - for (size_t i = 0; i < tree_count; i++) trees[i] = ts_tree_make_leaf(i, ts_length_zero(), tree_len, { true, true, false, true, @@ -383,42 +355,22 @@ describe("Stack", [&]() { }); describe("when there are two paths that converge on one version", [&]() { - it("returns the first path of trees if they are selected by the selection callback", [&]() { - tree_selection_spy.tree_to_return = trees[1]; - + it("returns two slices with the same version", [&]() { // . <──0── A <──1── B <──2── C <──3── D <──10── I* // ↑ | // ├───4─── E <──5── F <──6───┘ // | // └* StackPopResult pop = ts_stack_pop_count(stack, 0, 4); - AssertThat(pop.slices.size, Equals(1)); + AssertThat(pop.slices.size, Equals(2)); StackSlice slice1 = pop.slices.contents[0]; AssertThat(slice1.version, Equals(1)); AssertThat(slice1.trees, Equals(vector({ trees[1], trees[2], trees[3], trees[10] }))); - AssertThat(ts_stack_version_count(stack), Equals(2)); - AssertThat(ts_stack_top_state(stack, 0), Equals(stateI)); - AssertThat(ts_stack_top_state(stack, 1), Equals(stateA)); - - free_slice_array(&pop.slices); - }); - - it("returns the second path of trees if they are selected by the selection callback", [&]() { - tree_selection_spy.tree_to_return = trees[4]; - - // . <──0── A <──1── B <──2── C <──3── D <──10── I* - // ↑ | - // ├───4─── E <──5── F <──6───┘ - // | - // └* - StackPopResult pop = ts_stack_pop_count(stack, 0, 4); - AssertThat(pop.slices.size, Equals(1)); - - StackSlice slice1 = pop.slices.contents[0]; - AssertThat(slice1.version, Equals(1)); - AssertThat(slice1.trees, Equals(vector({ trees[4], trees[5], trees[6], trees[10] }))) + StackSlice slice2 = pop.slices.contents[1]; + AssertThat(slice2.version, Equals(1)); + AssertThat(slice2.trees, Equals(vector({ trees[4], trees[5], trees[6], trees[10] }))) AssertThat(ts_stack_version_count(stack), Equals(2)); AssertThat(ts_stack_top_state(stack, 0), Equals(stateI)); diff --git a/src/runtime/array.h b/src/runtime/array.h index 47366c51..7770711c 100644 --- a/src/runtime/array.h +++ b/src/runtime/array.h @@ -48,7 +48,10 @@ extern "C" { #define array_splice(self, index, old_count, new_count, new_elements) \ array__splice((VoidArray *)(self), array__elem_size(self), index, old_count, \ - new_count, new_elements) + new_count, (new_elements)) + +#define array_insert(self, index, element) \ + array_splice(self, index, 0, 1, &(element)) #define array_pop(self) ((self)->contents[--(self)->size]) @@ -107,15 +110,14 @@ static inline bool array__grow(VoidArray *self, size_t element_size, static inline bool array__splice(VoidArray *self, size_t element_size, size_t index, size_t old_count, size_t new_count, void *elements) { - assert(index + old_count <= self->size); - assert(index < self->size); size_t new_size = self->size + new_count - old_count; size_t old_end = index + old_count; size_t new_end = index + new_count; - if (new_size >= self->capacity) { + assert(old_end <= self->size); + + if (new_size >= self->capacity) if (!array__grow(self, element_size, new_size)) return false; - } char *contents = (char *)self->contents; if (self->size > old_end) diff --git a/src/runtime/parser.c b/src/runtime/parser.c index 2a4e637a..17411929 100644 --- a/src/runtime/parser.c +++ b/src/runtime/parser.c @@ -258,26 +258,20 @@ static TSTree *ts_parser__get_lookahead(TSParser *self, StackVersion version, return self->language->lex_fn(&self->lexer, lex_state, false); } -static int ts_parser__select_tree(void *data, TSTree *left, TSTree *right) { - if (!left || left->symbol == ts_builtin_sym_error) - return 1; - if (!right || right->symbol == ts_builtin_sym_error) - return -1; - - TSParser *self = data; - int comparison = ts_tree_compare(left, right); - switch (comparison) { - case -1: - LOG_ACTION("select tree:%s, over_tree:%s", SYM_NAME(left->symbol), - SYM_NAME(right->symbol)); - break; - case 1: - LOG_ACTION("select tree:%s, over_tree:%s", SYM_NAME(right->symbol), - SYM_NAME(left->symbol)); - break; +static bool ts_parser__select_tree(TSParser *self, TSTree *left, TSTree *right) { + if (!left) + return true; + if (!right) + return false; + if (right->error_size < left->error_size) { + LOG_ACTION("select_smaller_error symbol:%s, over_symbol:%s", SYM_NAME(right->symbol), SYM_NAME(left->symbol)); + return true; } - - return comparison; + if (left->error_size < right->error_size) { + LOG_ACTION("select_smaller_error symbol:%s, over_symbol:%s", SYM_NAME(left->symbol), SYM_NAME(right->symbol)); + return false; + } + return ts_tree_compare(right, left) < 0; } static void ts_parser__remove_version(TSParser *self, StackVersion version) { @@ -319,6 +313,25 @@ error: return false; } +static bool ts_parser__switch_children(TSParser *self, TSTree *tree, + TSTree **children, size_t count) { + self->scratch_tree.symbol = tree->symbol; + self->scratch_tree.child_count = 0; + ts_tree_set_children(&self->scratch_tree, count, children); + if (ts_parser__select_tree(self, tree, &self->scratch_tree)) { + tree->size = self->scratch_tree.size; + tree->padding = self->scratch_tree.padding; + tree->error_size = self->scratch_tree.error_size; + tree->children = self->scratch_tree.children; + tree->child_count = self->scratch_tree.child_count; + tree->named_child_count = self->scratch_tree.named_child_count; + tree->visible_child_count = self->scratch_tree.visible_child_count; + return true; + } else { + return false; + } +} + static Reduction ts_parser__reduce(TSParser *self, StackVersion version, TSSymbol symbol, unsigned count, bool extra, bool fragile) { @@ -356,6 +369,25 @@ static Reduction ts_parser__reduce(TSParser *self, StackVersion version, goto error; } + while (i + 1 < pop.slices.size) { + StackSlice next_slice = pop.slices.contents[i + 1]; + if (next_slice.version != slice.version) + break; + i++; + + size_t child_count = next_slice.trees.size; + while (child_count > 0 && next_slice.trees.contents[child_count - 1]->extra) + child_count--; + + if (ts_parser__switch_children(self, parent, next_slice.trees.contents, + child_count)) { + ts_tree_array_delete(&slice.trees); + slice = next_slice; + } else { + ts_tree_array_delete(&next_slice.trees); + } + } + TSStateId state = ts_stack_top_state(self->stack, slice.version); if (fragile || self->is_split || ts_stack_version_count(self->stack) > 1) { parent->fragile_left = true; @@ -376,7 +408,7 @@ static Reduction ts_parser__reduce(TSParser *self, StackVersion version, } CHECK(ts_parser__push(self, slice.version, parent, new_state)); - for (size_t j = child_count; j < slice.trees.size; j++) { + for (size_t j = parent->child_count; j < slice.trees.size; j++) { TSTree *tree = slice.trees.contents[j]; CHECK(ts_parser__push(self, slice.version, tree, new_state)); } @@ -490,15 +522,16 @@ static RepairResult ts_parser__repair_error(TSParser *self, StackSlice slice, TreeArray children_below = new_slice.trees; ts_stack_renumber_version(self->stack, new_slice.version, slice.version); - while (pop.slices.size) { - StackSlice other_slice = array_pop(&pop.slices); + for (size_t i = pop.slices.size - 1; i + 1 > 0; i--) { + StackSlice other_slice = pop.slices.contents[i]; ts_tree_array_delete(&other_slice.trees); - ts_stack_remove_version(self->stack, other_slice.version); + if (other_slice.version != pop.slices.contents[i + 1].version) + ts_stack_remove_version(self->stack, other_slice.version); } LOG_ACTION( "repair_found sym:%s, child_count:%lu, match_count:%lu, skipped:%lu", - SYM_NAME(symbol), repair.count_below_error, repair.in_progress_state_count, + SYM_NAME(symbol), repair.count_below_error + count_above_error, repair.in_progress_state_count, skip_count); if (skip_count > 0) { @@ -538,43 +571,51 @@ static void ts_parser__start(TSParser *self, TSInput input, ts_lexer_set_input(&self->lexer, input); ts_stack_clear(self->stack); - ts_stack_set_tree_selection_callback(self->stack, self, - ts_parser__select_tree); self->finished_tree = NULL; } static bool ts_parser__accept(TSParser *self, StackVersion version) { LOG_ACTION("accept"); - TreeArray trees = ts_stack_pop_all(self->stack, version); - CHECK(trees.contents); + StackPopResult pop = ts_stack_pop_all(self->stack, version); + CHECK(pop.status); + CHECK(pop.slices.size); - for (size_t i = trees.size - 1; i + 1 > 0; i--) { - if (!trees.contents[i]->extra) { - TSTree *root = trees.contents[i]; - CHECK(array_splice(&trees, i, 1, root->child_count, root->children)); + for (size_t i = 0; i < pop.slices.size; i++) { + StackSlice slice = pop.slices.contents[i]; + TreeArray trees = slice.trees; - ts_tree_set_children(root, trees.size, trees.contents); - if (!trees.size) - array_delete(&trees); + for (size_t j = trees.size - 1; j + 1 > 0; j--) { + if (!trees.contents[j]->extra) { + TSTree *root = trees.contents[j]; - ts_stack_remove_version(self->stack, version); - int comparison = ts_parser__select_tree(self, self->finished_tree, root); - if (comparison > 0) { - ts_tree_release(self->finished_tree); - self->finished_tree = root; - } else { - ts_tree_release(root); + CHECK(array_splice(&trees, j, 1, root->child_count, root->children)); + ts_tree_set_children(root, trees.size, trees.contents); + if (!trees.size) + array_delete(&trees); + + for (size_t k = j - 1; k + 1 > 0; k--) + if (!root->children[k]->extra) + root->error_size += root->children[j]->size.chars; + + if (ts_parser__select_tree(self, self->finished_tree, root)) { + ts_tree_release(self->finished_tree); + self->finished_tree = root; + } else { + ts_tree_release(root); + } + + break; } - - break; } } + ts_stack_remove_version(self->stack, pop.slices.contents[0].version); + ts_stack_remove_version(self->stack, version); + return true; error: - ts_tree_array_delete(&trees); return false; } @@ -597,10 +638,8 @@ static ParseActionResult ts_parser__handle_error(TSParser *self, CHECK(error); CHECK(ts_parser__push(self, version, error, 0)); - TreeArray trees = ts_stack_pop_all(self->stack, version); - CHECK(trees.contents); - TSTree *parent = ts_tree_make_node( - ts_builtin_sym_start, trees.size, trees.contents, + TSTree *parent = ts_tree_make_leaf( + ts_builtin_sym_start, ts_length_zero(), ts_length_zero(), ts_language_symbol_metadata(language, ts_builtin_sym_start)); CHECK(parent); CHECK(ts_parser__push(self, version, parent, 0)); @@ -682,7 +721,7 @@ static ParseActionResult ts_parser__consume_lookahead(TSParser *self, break; } - if (ts_stack_version_count(self->stack) == 1) { + if (ts_stack_version_count(self->stack) == 1 && !self->finished_tree) { return ts_parser__handle_error(self, version, lookahead); } else { ts_parser__remove_version(self, version); diff --git a/src/runtime/parser.h b/src/runtime/parser.h index 1fd2f6bf..c5de3ca1 100644 --- a/src/runtime/parser.h +++ b/src/runtime/parser.h @@ -19,6 +19,7 @@ typedef struct { TSTree *finished_tree; bool is_split; bool print_debugging_graphs; + TSTree scratch_tree; } TSParser; bool ts_parser_init(TSParser *); diff --git a/src/runtime/stack.c b/src/runtime/stack.c index c9341966..c861f943 100644 --- a/src/runtime/stack.c +++ b/src/runtime/stack.c @@ -47,8 +47,6 @@ struct Stack { StackSliceArray slices; Array(PopPath) pop_paths; StackNodeArray node_pool; - void *tree_selection_payload; - TreeSelectionFunction tree_selection_function; StackNode *base_node; }; @@ -131,10 +129,6 @@ static void stack_node_add_link(StackNode *self, StackLink link) { } } -static int ts_stack__default_tree_selection(void *p, TSTree *t1, TSTree *t2) { - return 0; -} - static StackVersion ts_stack__add_version(Stack *self, StackNode *node) { if (!array_push(&self->heads, node)) return STACK_VERSION_NONE; @@ -142,55 +136,24 @@ static StackVersion ts_stack__add_version(Stack *self, StackNode *node) { return (StackVersion)(self->heads.size - 1); } -static void ts_stack__update_slice(Stack *self, StackSlice *slice, - TreeArray *trees) { - bool should_update = false; - if (slice->trees.size < trees->size) { - should_update = true; - } else if (slice->trees.size == trees->size) { - for (size_t i = 0; i < slice->trees.size; i++) { - TSTree *tree = slice->trees.contents[i]; - TSTree *new_tree = trees->contents[i]; - int comparison = self->tree_selection_function( - self->tree_selection_payload, tree, new_tree); - if (comparison < 0) { - break; - } else if (comparison > 0) { - should_update = true; - break; - } - } - } - - if (should_update) { - ts_tree_array_delete(&slice->trees); - slice->trees = *trees; - } else { - ts_tree_array_delete(trees); - } -} - -static bool ts_stack__add_slice(Stack *self, size_t previous_version_count, - StackNode *node, TreeArray *trees) { - for (size_t i = 0; i < self->slices.size; i++) { - StackSlice *previous_slice = &self->slices.contents[i]; - size_t version_index = previous_version_count + i; - if (self->heads.contents[version_index] == node) { - ts_stack__update_slice(self, previous_slice, trees); - return true; +static bool ts_stack__add_slice(Stack *self, StackNode *node, TreeArray *trees) { + for (size_t i = self->slices.size - 1; i + 1 > 0; i--) { + StackVersion version = self->slices.contents[i].version; + if (self->heads.contents[version] == node) { + StackSlice slice = {*trees, version}; + return array_insert(&self->slices, i + 1, slice); } } StackVersion version = ts_stack__add_version(self, node); if (version == STACK_VERSION_NONE) return false; - StackSlice slice = {.version = version, .trees = *trees }; + StackSlice slice = {*trees, version}; return array_push(&self->slices, slice); } INLINE StackPopResult stack__iter(Stack *self, StackVersion version, StackIterateCallback callback, void *payload) { - size_t previous_version_count = self->heads.size; array_clear(&self->slices); PopPath pop_path = { @@ -219,7 +182,7 @@ INLINE StackPopResult stack__iter(Stack *self, StackVersion version, TreeArray trees = should_stop ? path->trees : ts_tree_array_copy(&path->trees); array_reverse(&trees); - if (!ts_stack__add_slice(self, previous_version_count, node, &trees)) + if (!ts_stack__add_slice(self, node, &trees)) goto error; } @@ -275,8 +238,6 @@ Stack *ts_stack_new() { array_init(&self->slices); array_init(&self->pop_paths); array_init(&self->node_pool); - self->tree_selection_payload = NULL; - self->tree_selection_function = ts_stack__default_tree_selection; if (!array_grow(&self->heads, 4)) goto error; @@ -426,13 +387,8 @@ INLINE StackIterateAction pop_all_callback(void *payload, TSStateId state, return is_done ? (StackIteratePop | StackIterateStop) : StackIterateNone; } -TreeArray ts_stack_pop_all(Stack *self, StackVersion version) { - StackPopResult pop = stack__iter(self, version, pop_all_callback, NULL); - if (pop.status != StackPopSucceeded) - return (TreeArray)array_new(); - assert(pop.slices.size == 1); - ts_stack_renumber_version(self, pop.slices.contents[0].version, version); - return pop.slices.contents[0].trees; +StackPopResult ts_stack_pop_all(Stack *self, StackVersion version) { + return stack__iter(self, version, pop_all_callback, NULL); } void ts_stack_remove_version(Stack *self, StackVersion version) { @@ -475,12 +431,6 @@ void ts_stack_clear(Stack *self) { array_push(&self->heads, self->base_node); } -void ts_stack_set_tree_selection_callback(Stack *self, void *payload, - TreeSelectionFunction function) { - self->tree_selection_payload = payload; - self->tree_selection_function = function; -} - int ts_stack_print_dot_graph(Stack *self, const char **symbol_names, FILE *f) { fprintf(f, "digraph stack {\n"); fprintf(f, "rankdir=\"RL\";\n"); diff --git a/src/runtime/stack.h b/src/runtime/stack.h index e01b6184..bf95cc2d 100644 --- a/src/runtime/stack.h +++ b/src/runtime/stack.h @@ -45,8 +45,6 @@ typedef StackIterateAction (*StackIterateCallback)(void *, TSStateId state, bool is_done, bool is_pending); -typedef int (*TreeSelectionFunction)(void *, TSTree *tree1, TSTree *tree2); - /* * Create a parse stack. */ @@ -94,7 +92,7 @@ StackPopResult ts_stack_iterate(Stack *, StackVersion, StackIterateCallback, StackPopResult ts_stack_pop_pending(Stack *, StackVersion); -TreeArray ts_stack_pop_all(Stack *, StackVersion); +StackPopResult ts_stack_pop_all(Stack *, StackVersion); void ts_stack_merge(Stack *); @@ -110,9 +108,6 @@ void ts_stack_remove_version(Stack *, StackVersion); */ void ts_stack_clear(Stack *); -void ts_stack_set_tree_selection_callback(Stack *, void *, - TreeSelectionFunction); - int ts_stack_print_dot_graph(Stack *, const char **, FILE *); #ifdef __cplusplus diff --git a/src/runtime/tree.c b/src/runtime/tree.c index 9f3303b8..8a51b149 100644 --- a/src/runtime/tree.c +++ b/src/runtime/tree.c @@ -110,10 +110,13 @@ recur: void ts_tree_set_children(TSTree *self, size_t child_count, TSTree **children) { if (self->child_count > 0) ts_free(self->children); + self->children = children; self->child_count = child_count; self->named_child_count = 0; self->visible_child_count = 0; + size_t error_size = 0; + for (size_t i = 0; i < child_count; i++) { TSTree *child = children[i]; @@ -136,9 +139,16 @@ void ts_tree_set_children(TSTree *self, size_t child_count, TSTree **children) { if (child->symbol == ts_builtin_sym_error) { self->fragile_left = self->fragile_right = true; self->parse_state = TS_TREE_STATE_ERROR; + } else { + error_size += child->error_size; } } + if (self->symbol == ts_builtin_sym_error) + self->error_size = self->size.chars; + else + self->error_size = error_size; + if (child_count > 0) { self->lex_state = children[0]->lex_state; if (children[0]->fragile_left) diff --git a/src/runtime/tree.h b/src/runtime/tree.h index ab3995e9..2ace03ca 100644 --- a/src/runtime/tree.h +++ b/src/runtime/tree.h @@ -34,6 +34,8 @@ struct TSTree { TSSymbol symbol; TSStateId lex_state; TSStateId parse_state; + size_t error_size; + unsigned short ref_count; bool visible : 1; bool named : 1;