From e70547cd11a7a640251e7fd9b710623fef1cb7dd Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Tue, 14 Jun 2016 14:48:31 -0700 Subject: [PATCH] Allow recoveries that skip leading children of invisible trees Before this, errors could only be recovered by skipping internal children. --- spec/fixtures/error_corpus/c_errors.txt | 39 ++++++- .../error_corpus/javascript_errors.txt | 9 +- src/runtime/parser.c | 108 +++++++++--------- 3 files changed, 97 insertions(+), 59 deletions(-) diff --git a/spec/fixtures/error_corpus/c_errors.txt b/spec/fixtures/error_corpus/c_errors.txt index 900295e1..a8a56037 100644 --- a/spec/fixtures/error_corpus/c_errors.txt +++ b/spec/fixtures/error_corpus/c_errors.txt @@ -90,5 +90,42 @@ int y = 5; --- (translation_unit - (declaration (identifier) (identifier) (ERROR (identifier))) + (declaration (identifier) (ERROR (identifier)) (identifier)) (declaration (identifier) (init_declarator (identifier) (number_literal)))) + +========================================== +Errors at the beginnings of blocks +========================================== + +int a() { + struct x = 1; + struct y = 2; +} + +int b() { + w x y z = 3; + w x y z = 4; +} + +--- + +(translation_unit + (function_definition + (identifier) (function_declarator (identifier)) + (compound_statement + (ERROR (struct_specifier (identifier))) + (expression_statement (number_literal)) + (ERROR (struct_specifier (identifier))) + (expression_statement (number_literal)))) + + (function_definition + (identifier) (function_declarator (identifier)) + (compound_statement + (declaration + (ERROR (identifier) (identifier)) + (identifier) + (init_declarator (identifier) (number_literal))) + (declaration + (ERROR (identifier) (identifier)) + (identifier) + (init_declarator (identifier) (number_literal)))))) diff --git a/spec/fixtures/error_corpus/javascript_errors.txt b/spec/fixtures/error_corpus/javascript_errors.txt index 0b401769..ca2a125e 100644 --- a/spec/fixtures/error_corpus/javascript_errors.txt +++ b/spec/fixtures/error_corpus/javascript_errors.txt @@ -14,8 +14,8 @@ if (x) { (program (expression_statement - (identifier) - (ERROR (identifier) (identifier))) + (ERROR (identifier) (identifier)) + (identifier)) (expression_statement (function_call (identifier))) (if_statement (identifier) (statement_block (ERROR) @@ -33,7 +33,7 @@ ok(); --- (program - (if_statement (identifier) (ERROR (identifier)) + (if_statement (ERROR (identifier)) (identifier) (expression_statement (function_call (identifier)))) (expression_statement (function_call (identifier)))) @@ -123,4 +123,5 @@ var (var_assignment (identifier) (number)) (ERROR) (identifier) (var_assignment (identifier) (number)) - (var_assignment (identifier) (ERROR) (identifier)))) + (ERROR (identifier)) + (identifier))) diff --git a/src/runtime/parser.c b/src/runtime/parser.c index 7ccd4cd9..ab257889 100644 --- a/src/runtime/parser.c +++ b/src/runtime/parser.c @@ -44,7 +44,7 @@ goto error; \ } -static const unsigned ERROR_COST_THRESHOLD = 5; +static const unsigned ERROR_COST_THRESHOLD = 3; static const TSParseAction ERROR_ACTION = {.type = TSParseActionTypeError }; @@ -546,7 +546,7 @@ static StackIterateAction ts_parser__error_repair_callback( StackIterateAction result = StackIterateNone; - size_t last_repair_count = 0; + size_t last_repair_count = -1; size_t repair_reduction_count = -1; const TSParseAction *repair_reductions = NULL; @@ -573,19 +573,14 @@ static StackIterateAction ts_parser__error_repair_callback( continue; if (count_needed_below_error != last_repair_count) { - assert(count_needed_below_error > last_repair_count); last_repair_count = count_needed_below_error; repair_reductions = ts_parser__reductions_after_sequence( self, state, trees, count_needed_below_error, trees_above_error, lookahead_symbol, &repair_reduction_count); } - if (!repair_reductions) - continue; - for (size_t j = 0; j < repair_reduction_count; j++) { - const TSParseAction repair_reduction = repair_reductions[j]; - if (repair_reduction.data.symbol == repair->symbol) { + if (repair_reductions[j].data.symbol == repair->symbol) { result |= StackIteratePop; session->found_repair = true; session->best_repair = *repair; @@ -603,6 +598,36 @@ static StackIterateAction ts_parser__error_repair_callback( return result; } +static bool ts_parser__halt_if_better_version_exists(TSParser *self, + StackVersion version, + unsigned my_error_depth, + unsigned my_error_cost) { + for (StackVersion i = 0, n = ts_stack_version_count(self->stack); i < n; i++) { + if (i == version || ts_stack_is_halted(self->stack, i)) + continue; + + unsigned error_cost = ts_stack_error_cost(self->stack, i); + unsigned error_depth = ts_stack_error_depth(self->stack, i); + + if ((error_depth > my_error_depth && error_cost >= my_error_cost) || + (error_depth == my_error_depth && + error_cost >= my_error_cost + ERROR_COST_THRESHOLD)) { + LOG_ACTION("halt_other version:%u", i); + ts_stack_halt(self->stack, i); + continue; + } + + if ((my_error_depth > error_depth && my_error_cost >= error_cost) || + (my_error_depth == error_depth && + my_error_cost >= error_cost + ERROR_COST_THRESHOLD)) { + ts_stack_halt(self->stack, version); + return true; + } + } + + return false; +} + static RepairResult ts_parser__repair_error(TSParser *self, StackSlice slice, TSTree *lookahead, const TSParseAction *actions, @@ -616,14 +641,18 @@ static RepairResult ts_parser__repair_error(TSParser *self, StackSlice slice, }; array_clear(&self->reduce_actions); - for (size_t i = 0; i < action_count; i++) - if (actions[i].type == TSParseActionTypeReduce && - actions[i].data.child_count > session.tree_count_above_error) - CHECK(array_push( - &self->reduce_actions, - ((ReduceAction){ - .symbol = actions[i].data.symbol, .count = actions[i].data.child_count, - }))); + for (size_t i = 0; i < action_count; i++) { + if (actions[i].type == TSParseActionTypeReduce) { + TSSymbol symbol = actions[i].data.symbol; + size_t child_count = actions[i].data.child_count; + if ((child_count > session.tree_count_above_error) || + (child_count == session.tree_count_above_error && + !ts_language_symbol_metadata(self->language, symbol).visible)) + CHECK(array_push( + &self->reduce_actions, + ((ReduceAction){.symbol = symbol, .count = child_count }))); + } + } StackPopResult pop = ts_stack_iterate( self->stack, slice.version, ts_parser__error_repair_callback, &session); @@ -673,27 +702,19 @@ static RepairResult ts_parser__repair_error(TSParser *self, StackSlice slice, CHECK(parent); CHECK(ts_parser__push(self, slice.version, parent, next_state)); - LOG_ACTION("repair_found sym:%s, child_count:%lu, skipped:%lu", - SYM_NAME(symbol), repair.count, parent->error_size); - unsigned my_error_cost = ts_stack_error_cost(self->stack, slice.version); unsigned my_error_depth = ts_stack_error_depth(self->stack, slice.version); - for (StackVersion i = 0; i < ts_stack_version_count(self->stack); i++) { - if (i == slice.version || ts_stack_is_halted(self->stack, i)) - continue; - unsigned error_cost = ts_stack_error_cost(self->stack, i); - unsigned error_depth = ts_stack_error_depth(self->stack, i); - if (error_depth > my_error_depth + 1 || - (error_depth == my_error_depth + 1 && error_cost >= my_error_cost) || - (error_depth == my_error_depth && - error_cost >= my_error_cost + ERROR_COST_THRESHOLD)) { - LOG_ACTION("halt_other version:%u", i); - ts_stack_halt(self->stack, i); - } + if (ts_parser__halt_if_better_version_exists(self, slice.version, + my_error_depth, my_error_cost)) { + LOG_ACTION("no_better_repair_found"); + ts_stack_halt(self->stack, slice.version); + return RepairNoneFound; + } else { + LOG_ACTION("repair_found sym:%s, child_count:%lu, skipped:%lu", + SYM_NAME(symbol), repair.count, parent->error_size); + return RepairSucceeded; } - return RepairSucceeded; - error: ts_tree_array_delete(&slice.trees); return RepairFailed; @@ -756,27 +777,6 @@ error: return false; } -static bool ts_parser__halt_if_better_version_exists(TSParser *self, - StackVersion version, - unsigned my_error_depth, - unsigned my_error_cost) { - for (StackVersion i = 0; i < ts_stack_version_count(self->stack); i++) { - if (i == version || ts_stack_is_halted(self->stack, i)) - continue; - unsigned error_cost = ts_stack_error_cost(self->stack, i); - unsigned error_depth = ts_stack_error_depth(self->stack, i); - if (error_depth < my_error_depth - 1 || - (error_depth == my_error_depth - 1 && error_cost < my_error_cost) || - (error_depth == my_error_depth && - error_cost + ERROR_COST_THRESHOLD <= my_error_cost)) { - ts_stack_halt(self->stack, version); - return true; - } - } - - return false; -} - static bool ts_parser__handle_error(TSParser *self, StackVersion version, TSStateId state, TSTree *lookahead) { size_t previous_version_count = ts_stack_version_count(self->stack);