Perform all possible reductions recursively upon detecting an error
This commit is contained in:
parent
a3c943d88e
commit
1b8843dd41
2 changed files with 116 additions and 191 deletions
230
spec/fixtures/error_corpus/javascript_errors.txt
vendored
230
spec/fixtures/error_corpus/javascript_errors.txt
vendored
|
|
@ -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))))))))
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue