diff --git a/src/runtime/parser.c b/src/runtime/parser.c index 8a23d6f1..6e221010 100644 --- a/src/runtime/parser.c +++ b/src/runtime/parser.c @@ -45,6 +45,7 @@ struct ErrorRepair { TSParseAction action; TSStateId next_state; size_t in_progress_state_count; + size_t essential_tree_count; }; typedef struct { @@ -108,6 +109,8 @@ static BreakdownResult ts_parser__breakdown_top_of_stack(TSParser *self, do { StackPopResult pop = ts_stack_pop_pending(self->stack, head); + if (!pop.status) + goto error; if (!pop.slices.size) break; @@ -468,6 +471,7 @@ static StackIterateAction ts_parser__error_repair_callback(void *payload, if (ts_language_has_action(self->language, repair->next_state, lookahead_symbol)) { session->best_repair_index = i; + repair->essential_tree_count = tree_count; return StackIteratePop; } } @@ -506,6 +510,7 @@ static RepairResult ts_parser__repair_error(TSParser *self, int head_index, array_push(&self->error_repairs, ((ErrorRepair){ .action = actions[i], .in_progress_state_count = 0, + .essential_tree_count = 0, })); StackPopResult result = ts_stack_pop_until( @@ -519,7 +524,7 @@ static RepairResult ts_parser__repair_error(TSParser *self, int head_index, size_t count_needed_below = repair.action.data.child_count - session.count_above_error; TreeArray children_below = result.slices.contents[0].trees; - size_t count_skipped_below = children_below.size - count_needed_below; + size_t count_skipped_below = repair.essential_tree_count - count_needed_below; TSSymbol symbol = repair.action.data.symbol; LOG_ACTION( @@ -527,16 +532,15 @@ static RepairResult ts_parser__repair_error(TSParser *self, int head_index, SYM_NAME(symbol), repair.action.data.child_count, repair.in_progress_state_count, count_skipped_below); - if (count_skipped_below > 1) { + if (count_skipped_below > 0) { TreeArray skipped_children = array_new(); if (!array_grow(&skipped_children, count_skipped_below)) goto error; for (size_t i = count_needed_below; i < children_below.size; i++) array_push(&skipped_children, children_below.contents[i]); - TSTree *error = ts_tree_make_node( - ts_builtin_sym_error, skipped_children.size, skipped_children.contents, - ts_language_symbol_metadata(self->language, ts_builtin_sym_error)); - error->extra = true; + TSTree *error = ts_tree_make_error_node(&skipped_children); + if (!error) + goto error; children_below.size = count_needed_below; array_push(&children_below, error); } @@ -630,9 +634,7 @@ static ParseActionResult ts_parser__handle_error(TSParser *self, int head, for (;;) { if (next_token->symbol == ts_builtin_sym_end) { LOG_ACTION("fail_to_recover"); - TSTree *error = ts_tree_make_node( - ts_builtin_sym_error, invalid_trees.size, invalid_trees.contents, - ts_language_symbol_metadata(self->language, ts_builtin_sym_error)); + TSTree *error = ts_tree_make_error_node(&invalid_trees); if (!ts_stack_push(self->stack, head, error, false, 0)) goto error; @@ -665,10 +667,10 @@ static ParseActionResult ts_parser__handle_error(TSParser *self, int head, following_token->symbol)) { LOG_ACTION("resume_without_context state:%d", next_state); ts_lexer_reset(&self->lexer, position); - TSTree *error = ts_tree_make_node( - ts_builtin_sym_error, invalid_trees.size, invalid_trees.contents, - ts_language_symbol_metadata(self->language, ts_builtin_sym_error)); - error->extra = true; + ts_tree_steal_padding(*array_back(&invalid_trees), next_token); + TSTree *error = ts_tree_make_error_node(&invalid_trees); + if (!error) + goto error; if (!ts_stack_push(self->stack, head, error, false, ts_parse_state_error)) goto error; if (!ts_stack_push(self->stack, head, next_token, false, next_state)) diff --git a/src/runtime/stack.c b/src/runtime/stack.c index 3a9db3d1..687a1f13 100644 --- a/src/runtime/stack.c +++ b/src/runtime/stack.c @@ -32,7 +32,7 @@ struct StackNode { typedef struct { TreeArray trees; - size_t extra_count; + size_t essential_tree_count; StackNode *node; bool is_done; bool is_pending; @@ -306,7 +306,7 @@ int ts_stack_split(Stack *self, int head_index) { return ts_stack__add_head(self, head); } -static inline ALWAYS_INLINE StackSliceArray stack__pop( +static inline ALWAYS_INLINE StackPopResult stack__pop( Stack *self, int head_index, StackIterateCallback callback, void *payload) { array_clear(&self->slices); array_clear(&self->pop_paths); @@ -315,7 +315,7 @@ static inline ALWAYS_INLINE StackSliceArray stack__pop( PopPath pop_path = { .node = initial_head, .trees = array_new(), - .extra_count = 0, + .essential_tree_count = 0, .is_done = false, .is_pending = true, }; @@ -334,7 +334,7 @@ static inline ALWAYS_INLINE StackSliceArray stack__pop( StackNode *node = path->node; size_t successor_count = node->successor_count; - switch (callback(payload, node->state, depth - path->extra_count, + switch (callback(payload, node->state, path->essential_tree_count, node == self->base_node, path->is_pending && depth > 0)) { case StackIteratePop: path->is_done = true; @@ -372,8 +372,8 @@ static inline ALWAYS_INLINE StackSliceArray stack__pop( next_path->node = successor.node; if (!array_push(&next_path->trees, successor.tree)) goto error; - if (successor.tree->extra) - next_path->extra_count++; + if (!successor.tree->extra && successor.tree->symbol != ts_builtin_sym_error) + next_path->essential_tree_count++; if (!successor.is_pending) next_path->is_pending = false; ts_tree_retain(successor.tree); @@ -419,13 +419,13 @@ static inline ALWAYS_INLINE StackSliceArray stack__pop( if (self->slices.size) stack_node_release(initial_head, &self->node_pool); - return self->slices; + return (StackPopResult){.status = StackPopSucceeded, .slices = self->slices}; error: for (size_t i = 0; i < self->pop_paths.size; i++) array_delete(&self->pop_paths.contents[i].trees); array_clear(&self->slices); - return self->slices; + return (StackPopResult){.status = StackPopFailed}; } static inline ALWAYS_INLINE StackIterateAction @@ -469,38 +469,29 @@ StackPopResult ts_stack_pop_count(Stack *self, int head_index, int count) { .goal_tree_count = count, .found_error = false, }; - StackSliceArray slices = + StackPopResult pop = stack__pop(self, head_index, stack__pop_count_callback, &session); - int status; - if (slices.size) { - if (session.found_error) { - status = StackPopStoppedAtError; - array_reverse(&slices); - while (slices.size > 1) { - StackSlice slice = array_pop(&slices); - ts_tree_array_delete(&slice.trees); - ts_stack_remove_head(self, slice.head_index); - } - } else { - status = StackPopSucceeded; + + if (pop.status && session.found_error) { + pop.status = StackPopStoppedAtError; + array_reverse(&pop.slices); + while (pop.slices.size > 1) { + StackSlice slice = array_pop(&pop.slices); + ts_tree_array_delete(&slice.trees); + ts_stack_remove_head(self, slice.head_index); } - } else { - status = StackPopFailed; } - return (StackPopResult){.status = status, .slices = slices }; + return pop; } StackPopResult ts_stack_pop_until(Stack *self, int head_index, StackIterateCallback callback, void *payload) { - StackSliceArray slices = stack__pop(self, head_index, callback, payload); - return (StackPopResult){.status = StackPopSucceeded, .slices = slices }; + return stack__pop(self, head_index, callback, payload); } StackPopResult ts_stack_pop_pending(Stack *self, int head_index) { - StackSliceArray slices = - stack__pop(self, head_index, stack__pop_pending_callback, NULL); - return (StackPopResult){.status = StackPopSucceeded, .slices = slices }; + return stack__pop(self, head_index, stack__pop_pending_callback, NULL); } void ts_stack_shrink(Stack *self, int head_index, int count) { diff --git a/src/runtime/tree.c b/src/runtime/tree.c index 7a705167..b9b8c867 100644 --- a/src/runtime/tree.c +++ b/src/runtime/tree.c @@ -146,6 +146,25 @@ TSTree *ts_tree_make_node(TSSymbol symbol, size_t child_count, return result; } +TSTree *ts_tree_make_error_node(TreeArray *children) { + for (size_t i = 0; i < children->size; i++) { + TSTree *child = children->contents[i]; + if (child->symbol == ts_builtin_sym_error && child->child_count > 0) { + if (!array_splice(children, i, 1, child->child_count, child->children)) + return NULL; + i += child->child_count - 1; + for (size_t j = 0; j < child->child_count; j++) + ts_tree_retain(child->children[j]); + ts_tree_release(child); + } + } + + return ts_tree_make_node(ts_builtin_sym_error, children->size, + children->contents, (TSSymbolMetadata){ + .extra = false, .visible = true, .named = true + }); +} + void ts_tree_retain(TSTree *self) { assert(self->ref_count > 0); self->ref_count++; @@ -311,3 +330,8 @@ void ts_tree_edit(TSTree *self, TSInputEdit edit) { } } } + +void ts_tree_steal_padding(TSTree *self, TSTree *other) { + self->size = ts_length_add(self->size, other->padding); + other->padding = ts_length_zero(); +} diff --git a/src/runtime/tree.h b/src/runtime/tree.h index f5c68adb..1c573aa0 100644 --- a/src/runtime/tree.h +++ b/src/runtime/tree.h @@ -50,6 +50,7 @@ void ts_tree_array_delete(TreeArray *); TSTree *ts_tree_make_leaf(TSSymbol, TSLength, TSLength, TSSymbolMetadata); TSTree *ts_tree_make_node(TSSymbol, size_t, TSTree **, TSSymbolMetadata); TSTree *ts_tree_make_copy(TSTree *child); +TSTree *ts_tree_make_error_node(TreeArray *); TSTree *ts_tree_make_error(TSLength, TSLength, char); void ts_tree_retain(TSTree *tree); void ts_tree_release(TSTree *tree); @@ -61,6 +62,7 @@ size_t ts_tree_end_column(const TSTree *self); void ts_tree_set_children(TSTree *, size_t, TSTree **); void ts_tree_assign_parents(TSTree *); void ts_tree_edit(TSTree *, TSInputEdit); +void ts_tree_steal_padding(TSTree *, TSTree *); static inline size_t ts_tree_total_chars(const TSTree *self) { return self->padding.chars + self->size.chars;