From 1b8843dd41bd69798e6d99cf0685fb8bdaaff754 Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Mon, 29 Aug 2016 09:34:08 -0700 Subject: [PATCH] Perform all possible reductions recursively upon detecting an error --- .../error_corpus/javascript_errors.txt | 230 +++++------------- src/runtime/parser.c | 77 ++++-- 2 files changed, 116 insertions(+), 191 deletions(-) diff --git a/spec/fixtures/error_corpus/javascript_errors.txt b/spec/fixtures/error_corpus/javascript_errors.txt index cf171f55..9c213dea 100644 --- a/spec/fixtures/error_corpus/javascript_errors.txt +++ b/spec/fixtures/error_corpus/javascript_errors.txt @@ -1,177 +1,67 @@ -============================================ -Invalid statements -============================================ +=================================================== +one invalid token right after the viable prefix +=================================================== -what the heck ! -y(); +if (a b) { + c d +} +e f -if (x) { - >>> - var y = right +--- + +(program + (if_statement + (identifier) + (ERROR (identifier)) + (statement_block + (expression_statement + (identifier) + (ERROR (identifier))))) + (expression_statement + (identifier) + (ERROR (identifier)))) + +======================================================= +multiple invalid tokens right after the viable prefix +======================================================= + +if (a b c) { + d e f g +} +h i j k + +--- + +(program + (if_statement + (identifier) + (ERROR (identifier) (identifier)) + (statement_block + (expression_statement + (identifier) + (ERROR (identifier) (identifier) (identifier))))) + (expression_statement + (identifier) + (ERROR (identifier) (identifier) (identifier)))) + +=================================================== +one invalid subtree right after the viable prefix +=================================================== + +if ({a: 'b'} {c: 'd'}) { + function(a) { b; } function(c) { d; } } --- (program - (expression_statement - (identifier) - (ERROR (identifier) (identifier))) - (expression_statement (function_call (identifier))) - (if_statement (identifier) (statement_block - (ERROR) - (var_declaration (var_assignment (identifier) (identifier)))))) - -============================================ -Invalid if conditions -============================================ - -if (uh oh) - hmm(); - -ok(); - ---- - -(program - (if_statement (ERROR (identifier)) (identifier) - (expression_statement (function_call (identifier)))) - (expression_statement (function_call (identifier)))) - -============================================ -Invalid for loops -============================================ - -ok1; - -for (a b c; d; e) - wat(); - -ok2; - -for (a; b; c d e) - wat(); - ---- - -(program - (expression_statement (identifier)) - - (for_statement - (ERROR (identifier) (identifier)) - (identifier) - (identifier) - (identifier) - (expression_statement (function_call (identifier)))) - - (expression_statement (identifier)) - - (for_statement - (identifier) - (identifier) - (ERROR (identifier) (identifier)) - (identifier) - (expression_statement (function_call (identifier))))) - -============================================ -Invalid statement blocks -============================================ - -function() { ^ & * } - ---- - -(program - (expression_statement (function (statement_block (ERROR))))) - -============================================ -Invalid objects -============================================ - -x = { - key1: value1, - - abc efg, - - key2: value2 -}; - ---- - -(program - (expression_statement (assignment - (identifier) - (object - (pair (identifier) (identifier)) - (ERROR (identifier) (identifier)) - (pair (identifier) (identifier)))))) - -============================================ -Invalid items in var declarations -============================================ - -var - a = 1, - -b, - c = 2, - d = = = = =, - e; - ---- - -(program - (var_declaration - (var_assignment (identifier) (number)) - (ERROR) (identifier) - (var_assignment (identifier) (number)) - (var_assignment (identifier) (ERROR) (identifier)))) - -============================================ -Misplaced expressions in var declarations -============================================ - -var - a = 1, - b = 2, - [1, 2], - {}, - c = 3, - d = 4; - -var x; - ---- - -(program - (var_declaration - (var_assignment (identifier) (number)) - (var_assignment (identifier) (number)) - (ERROR (array (number) (number)) (object)) - (var_assignment (identifier) (number)) - (var_assignment (identifier) (number))) - (var_declaration (identifier))) - -================================================ -Mismatched delimiters in var declarations -================================================ - -var - // keep this - a, - - // skip this - [ - - // keep this - b = 1; - -var c; - ---- - -(program - (var_declaration - (comment) - (identifier) - (ERROR (comment) (comment)) - (var_assignment (identifier) (number))) - (var_declaration (identifier))) + (if_statement + (object (pair (identifier) (string))) + (ERROR (object (pair (identifier) (string)))) + (statement_block + (ERROR (function + (formal_parameters (identifier)) + (statement_block (expression_statement (identifier))))) + (expression_statement (function + (formal_parameters (identifier)) + (statement_block (expression_statement (identifier)))))))) diff --git a/src/runtime/parser.c b/src/runtime/parser.c index 5d774f1b..d05c8b90 100644 --- a/src/runtime/parser.c +++ b/src/runtime/parser.c @@ -831,29 +831,24 @@ error: return false; } -static bool ts_parser__handle_error(TSParser *self, StackVersion version) { - TSStateId state = ts_stack_top_state(self->stack, version); +typedef enum { + PotentialReductionsFailed, + PotentialReductionsContinue, + PotentialReductionsDone, +} PotentialReductionStatus; - unsigned error_cost = ts_stack_error_cost(self->stack, version); - unsigned error_depth = ts_stack_error_depth(self->stack, version) + 1; - if (ts_parser__better_version_exists(self, version, error_depth, error_cost)) { - ts_stack_halt(self->stack, version); - LOG("bail_on_error"); - return true; - } - - LOG("handle_error"); - - size_t previous_version_count = ts_stack_version_count(self->stack); +static PotentialReductionStatus parser__do_potential_reductions(TSParser *self, + StackVersion version) { bool has_shift_action = false; + TSStateId state = ts_stack_top_state(self->stack, version); + size_t previous_version_count = ts_stack_version_count(self->stack); + array_clear(&self->reduce_actions); for (TSSymbol symbol = 0; symbol < self->language->symbol_count; symbol++) { - size_t action_count; - const TSParseAction *actions = - ts_language_actions(self->language, state, symbol, &action_count); - - for (size_t i = 0; i < action_count; i++) { - TSParseAction action = actions[i]; + TableEntry entry; + ts_language_table_entry(self->language, state, symbol, &entry); + for (size_t i = 0; i < entry.action_count; i++) { + TSParseAction action = entry.actions[i]; if (action.extra) continue; switch (action.type) { @@ -892,8 +887,48 @@ static bool ts_parser__handle_error(TSParser *self, StackVersion version) { } } - if (did_reduce && !has_shift_action) - ts_stack_renumber_version(self->stack, previous_version_count, version); + if (did_reduce) { + if (has_shift_action) { + return PotentialReductionsDone; + } else { + ts_stack_renumber_version(self->stack, previous_version_count, version); + return PotentialReductionsContinue; + } + } else { + return PotentialReductionsDone; + } + +error: + return PotentialReductionsFailed; +} + +static bool ts_parser__handle_error(TSParser *self, StackVersion version) { + unsigned error_cost = ts_stack_error_cost(self->stack, version); + unsigned error_depth = ts_stack_error_depth(self->stack, version) + 1; + if (ts_parser__better_version_exists(self, version, error_depth, error_cost)) { + ts_stack_halt(self->stack, version); + LOG("bail_on_error"); + return true; + } + + LOG("handle_error"); + + size_t previous_version_count = ts_stack_version_count(self->stack); + for (StackVersion v = version; v < ts_stack_version_count(self->stack);) { + switch (parser__do_potential_reductions(self, v)) { + case PotentialReductionsFailed: + goto error; + case PotentialReductionsContinue: + break; + case PotentialReductionsDone: + if (v == version) { + v = previous_version_count; + } else { + v++; + } + break; + } + } CHECK(ts_stack_push(self->stack, version, NULL, false, TS_STATE_ERROR)); while (ts_stack_version_count(self->stack) > previous_version_count) {