Collapse redundant interior error nodes
This commit is contained in:
parent
eb47edb446
commit
267092940d
4 changed files with 61 additions and 42 deletions
|
|
@ -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))
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue