Collapse redundant interior error nodes

This commit is contained in:
Max Brunsfeld 2016-04-03 23:46:43 -07:00
parent eb47edb446
commit 267092940d
4 changed files with 61 additions and 42 deletions

View file

@ -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))

View file

@ -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) {

View file

@ -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();
}

View file

@ -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;