@babel/parser error recovery (#10363)
* Add error recovery support to @babel/parser * Update @babel/parser tests to always recover from errors * Update this.raise usage in @babel/parser: - expression.js - lval.js - statement.js - estree.js - flow.js - jsx/index.js - tokenizer/index.js * Update @babel/parser fixtures with recovered errors * Fix tests out of @babel/parser * Do not use try/catch for control flow * Update invalid fixtures * Do not report invalid lhs in toAssignable * Do not validate function id multiple times * Dedupe reserved await errors * Remove duplicate errors about strict reserved bindings * Remove duplicated error about yield/await inside params * Don't error twice for methods in object patterns * Don't report invalid super() twice * Remove dup error about reserved param for expr arrows * Remove double escapes in migrated tests * Dedupe errors about invalid escapes in identifiers * Remove duplicated error about decorated constructor * Remove duplicated error about spread in flow class * Don't throw for invalid super usage * Don't fail for object decorators with stage 2 * Fix flow inexact type errors * Fix flow * Fix errors about escapes in keywords (ref: #10455) * Update after rebase * Fix todo * Remove duplicated error when using += for defaults * Remove unnecessary throw * Nit: use ??
This commit is contained in:
@@ -2,6 +2,7 @@
|
||||
|
||||
import { types as tt, type TokenType } from "../tokenizer/types";
|
||||
import Tokenizer from "../tokenizer";
|
||||
import State from "../tokenizer/state";
|
||||
import type { Node } from "../types";
|
||||
import { lineBreak, skipWhiteSpace } from "../util/whitespace";
|
||||
import { isIdentifierChar } from "../util/identifier";
|
||||
@@ -9,6 +10,14 @@ import * as charCodes from "charcodes";
|
||||
|
||||
const literal = /^('|")((?:\\?.)*?)\1/;
|
||||
|
||||
type TryParse<Node, Error, Thrown, Aborted, FailState> = {
|
||||
node: Node,
|
||||
error: Error,
|
||||
thrown: Thrown,
|
||||
aborted: Aborted,
|
||||
failState: FailState,
|
||||
};
|
||||
|
||||
// ## Parser utilities
|
||||
|
||||
export default class UtilParser extends Tokenizer {
|
||||
@@ -215,4 +224,58 @@ export default class UtilParser extends Tokenizer {
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// tryParse will clone parser state.
|
||||
// It is expensive and should be used with cautions
|
||||
tryParse<T: Node | $ReadOnlyArray<Node>>(
|
||||
fn: (abort: (node?: T) => empty) => T,
|
||||
oldState: State = this.state.clone(),
|
||||
):
|
||||
| TryParse<T, null, false, false, null>
|
||||
| TryParse<T | null, SyntaxError, boolean, false, State>
|
||||
| TryParse<T | null, null, false, true, State> {
|
||||
const abortSignal: { node: T | null } = { node: null };
|
||||
try {
|
||||
const node = fn((node = null) => {
|
||||
abortSignal.node = node;
|
||||
throw abortSignal;
|
||||
});
|
||||
if (this.state.errors.length > oldState.errors.length) {
|
||||
const failState = this.state;
|
||||
this.state = oldState;
|
||||
return {
|
||||
node,
|
||||
error: (failState.errors[oldState.errors.length]: SyntaxError),
|
||||
thrown: false,
|
||||
aborted: false,
|
||||
failState,
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
node,
|
||||
error: null,
|
||||
thrown: false,
|
||||
aborted: false,
|
||||
failState: null,
|
||||
};
|
||||
} catch (error) {
|
||||
const failState = this.state;
|
||||
this.state = oldState;
|
||||
if (error instanceof SyntaxError) {
|
||||
return { node: null, error, thrown: true, aborted: false, failState };
|
||||
}
|
||||
if (error === abortSignal) {
|
||||
return {
|
||||
node: abortSignal.node,
|
||||
error: null,
|
||||
thrown: false,
|
||||
aborted: true,
|
||||
failState,
|
||||
};
|
||||
}
|
||||
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user