From cc74ece662a5c30e5f4f33ed77144ff16a679d72 Mon Sep 17 00:00:00 2001 From: Francisco Ryan Tolmasky I Date: Thu, 3 Mar 2022 19:57:28 -0800 Subject: [PATCH] Get rid of ParseError class and use SyntaxErrors instead. Reviewed by @tolmasky. --- packages/babel-parser/src/parse-error.js | 249 ++++++++---------- .../src/parse-error/credentials.js | 47 +++- .../babel-parser/src/parser/expression.js | 2 +- packages/babel-parser/src/parser/util.js | 14 +- .../babel-parser/src/plugins/flow/index.js | 4 +- .../babel-parser/src/plugins/jsx/index.js | 4 +- .../babel-parser/src/plugins/placeholders.js | 4 +- .../src/plugins/typescript/index.js | 4 +- packages/babel-parser/src/tokenizer/index.js | 37 +-- packages/babel-parser/src/tokenizer/state.js | 6 +- .../babel-parser/src/util/expression-scope.js | 26 +- 11 files changed, 203 insertions(+), 194 deletions(-) diff --git a/packages/babel-parser/src/parse-error.js b/packages/babel-parser/src/parse-error.js index 848e3ebaa4cd..db5609f2ad0e 100644 --- a/packages/babel-parser/src/parse-error.js +++ b/packages/babel-parser/src/parse-error.js @@ -3,198 +3,155 @@ import { Position } from "./util/location"; import type { NodeBase } from "./types"; import { + instantiate, type ParseErrorCode, ParseErrorCodes, type ParseErrorCredentials, } from "./parse-error/credentials"; -const ArrayIsArray = Array.isArray; -const { - assign: ObjectAssign, - defineProperty: ObjectDefineProperty, - getPrototypeOf: ObjectGetPrototypeOf, - keys: ObjectKeys, -} = Object; - -type ToMessage = (self: ErrorDetails) => string; - -const StandardMessage = Symbol("StandardMessage"); - -// This should really be an abstract class, but that concept doesn't exist in -// Flow, outside of just creating an interface, but then you can't specify that -// it's a subclass of `SyntaxError`. You could do something like: -// -// interface IParseError { ... } -// type ParseError = SyntaxError & IParseError; -// -// But this is just a more complicated way of getting the same behavior, with -// the added clumsiness of not being able to extends ParseError directly. So, -// to keep things simple and prepare for a Typescript future, we just make it a -// "private" superclass that we exclusively subclass: - -export class ParseError extends SyntaxError { +// Babel uses "normal" SyntaxErrors for it's errors, but adds some extra +// functionality. This functionality is defined in the +// `ParseErrorSpecification` interface below. We may choose to change to someday +// give our errors their own full-blown class, but until then this allow us to +// keep all the desirable properties of SyntaxErrors (like their name in stack +// traces, etc.), and also allows us to punt on any publically facing +// class-hierarchy decisions until Babel 8. +interface ParseErrorSpecification { + // Look, these *could* be readonly, but then Flow complains when we initially + // set them. We could do a whole dance and make a special interface that's not + // readonly for when we create the error, then cast it to the readonly + // interface for public use, but the previous implementation didn't have them + // as readonly, so let's just not worry about it for now. code: ParseErrorCode; reasonCode: string; + syntaxPlugin?: string; + + missingPlugin?: string | string[]; loc: Position; details: ErrorDetails; - // There are no optional fields in classes in Flow, so we can't list these - // here: https://github.com/facebook/flow/issues/2859 - // syntaxPlugin?: SyntaxPlugin - // missingPlugin?: string[] - - constructor({ - loc, - details, - }: { - loc: Position, - details: ErrorDetails, - }): ParseError { - super(); - - this.loc = loc; - - ObjectDefineProperty(this, "details", { - value: details, - enumerable: false, - }); - - // $FlowIgnore - if (details.missingPlugin) { - ObjectDefineProperty(this, "missingPlugin", { - get() { - return this.details.missingPlugin; - }, - enumerable: true, - }); - } - - return this; - } - - clone({ - loc, - details, - }: { - loc?: Position, - details?: ErrorDetails, - } = {}) { - return new (ObjectGetPrototypeOf(this).constructor)({ - loc: loc || this.loc, - details: { ...this.details, ...details }, - }); - } - - get pos() { - return this.loc.index; - } + // We should consider removing this as it now just contains the same + // information as `loc.index`. + // pos: number; } -function toParseErrorClass( - toMessage: ToMessage, - credentials: ParseErrorCredentials, -): Class> { - return class extends ParseError { - #message: typeof StandardMessage | string = StandardMessage; - - constructor(...args): ParseError { - super(...args); - // $FlowIgnore - Only necessary because we can't make syntaxPlugin optional. - ObjectAssign(this, credentials); - return this; - } - - get message() { - return this.#message !== StandardMessage - ? String(this.#message) - : `${toMessage(this.details)} (${this.loc.line}:${this.loc.column})`; - } - - set message(message) { - this.#message = message; - } - }; +export type ParseError = SyntaxError & + ParseErrorSpecification; + +// By `ParseErrorConstructor`, we mean something like the new-less style +// `ErrorConstructor`[1], since `ParseError`'s are not themselves actually +// separate classes from `SyntaxError`'s. +// +// 1. https://github.com/microsoft/TypeScript/blob/v4.5.5/lib/lib.es5.d.ts#L1027 +export type ParseErrorConstructor = ({ + loc: Position, + details: ErrorDetails, +}) => ParseError; + +function toParseErrorConstructor({ + toMessage, + ...properties +}: ParseErrorCredentials): ParseErrorConstructor { + return ({ loc, details }: { loc: Position, details: ErrorDetails }) => + instantiate>( + SyntaxError, + { ...properties, loc }, + { + details: { value: details, enumerable: false }, + message: { + get: ({ details, loc }) => + `${toMessage(details)} (${loc.line}:${loc.column})`, + set: (self, value) => + Object.defineProperty(self, "message", { value }), + }, + pos: "loc.index", + missingPlugin: "missingPlugin" in details && "details.missingPlugin", + }, + ); } -// This part is tricky, and only necessary due to some bugs in Flow that won't -// be fixed for a year(?): https://github.com/facebook/flow/issues/8838 -// Flow has a very difficult time extracting the parameter types of functions, -// so we are forced to pretend the class exists earlier than it does. -// `toParseErrorCredentials` *does not* actuall return a -// `Class>`, but we simply mark it as such to "carry" -// the `ErrorDetails` type parameter around. This is not a problem in Typescript -// where this intermediate function actually won't be needed at all. +// This part is tricky. You'll probably notice from the name of this function +// that it is supposed to return `ParseErrorCredentials`, but instead these. +// declarations seem to instead imply that they return +// `ParseErrorConstructor` instead. This is because in Flow we +// can't easily extract parameter types (either from functions, like with +// Typescript's Parameters utility type, or from generic types either). As +// such, this function does double duty: packaging up the credentials during +// its actual runtime operation, but pretending to return the +// `ParseErrorConstructor` that we won't actually have until later +// to the type system, avoiding the need to do so with $ObjMap (which doesn't +// work) in `ParseErrorEnum`. This hack won't be necessary when we switch to +// Typescript. declare function toParseErrorCredentials( T, ?{ code?: ParseErrorCode, reasonCode?: string } | boolean, -): Class>; +): ParseErrorConstructor<{||}>; // ESLint seems to erroneously think that Flow's overloading syntax is an // accidental redeclaration of the function: // https://github.com/babel/eslint-plugin-babel/issues/162 // eslint-disable-next-line no-redeclare -declare function toParseErrorCredentials( - (T) => string, +declare function toParseErrorCredentials( + (ErrorDetails) => string, ?{ code?: ParseErrorCode, reasonCode?: string } | boolean, -): Class>; +): ParseErrorConstructor; // See comment about eslint and Flow overloading above. // eslint-disable-next-line no-redeclare export function toParseErrorCredentials(toMessageOrMessage, credentials) { - return [ - typeof toMessageOrMessage === "string" - ? () => toMessageOrMessage - : toMessageOrMessage, - credentials, - ]; + return { + toMessage: + typeof toMessageOrMessage === "string" + ? () => toMessageOrMessage + : toMessageOrMessage, + ...credentials, + }; } -declare function toParseErrorClasses(string[]): typeof toParseErrorClasses; +// This is the templated form. +declare function ParseErrorEnum(string[]): typeof ParseErrorEnum; // See comment about eslint and Flow overloading above. // eslint-disable-next-line no-redeclare -declare function toParseErrorClasses( - toClasses: (typeof toParseErrorCredentials) => T, +declare function ParseErrorEnum( + toParseErrorCredentials: (typeof toParseErrorCredentials) => T, syntaxPlugin?: string, ): T; -// toParseErrorClasses can optionally be template tagged to provide a -// syntaxPlugin: +// You call `ParseErrorEnum` with a mapping from `ReasonCode`'s to either error +// messages, or `toMessage` functions that define additional necessary `details` +// needed by the `ParseError`: // -// toParseErrorClasses`syntaxPlugin` (_ => ... ) +// ParseErrorEnum`optionalSyntaxPlugin` (_ => ({ +// ErrorWithStaticMessage: _("message"), +// ErrorWithDynamicMessage: _<{ type: string }>(({ type }) => `${type}`), +// }); // // See comment about eslint and Flow overloading above. // eslint-disable-next-line no-redeclare -export function toParseErrorClasses(argument, syntaxPlugin) { +export function ParseErrorEnum(argument, syntaxPlugin) { // If the first parameter is an array, that means we were called with a tagged // template literal. Extract the syntaxPlugin from this, and call again in // the "normalized" form. - if (ArrayIsArray(argument)) { - return toClasses => toParseErrorClasses(toClasses, argument[0]); + if (Array.isArray(argument)) { + return toParseErrorCredentialsMap => + ParseErrorEnum(toParseErrorCredentialsMap, argument[0]); } - const classes = argument(toParseErrorCredentials); + const partialCredentials = argument(toParseErrorCredentials); + const ParseErrorConstructors = {}; - for (const reasonCode of ObjectKeys(classes)) { - const [toMessage, credentials = {}] = classes[reasonCode]; - const ParseErrorClass = toParseErrorClass(toMessage, { - code: credentials.code || ParseErrorCodes.SyntaxError, - reasonCode: credentials.reasonCode || reasonCode, + for (const reasonCode of Object.keys(partialCredentials)) { + ParseErrorConstructors[reasonCode] = toParseErrorConstructor({ + code: ParseErrorCodes.SyntaxError, + reasonCode, ...(syntaxPlugin ? { syntaxPlugin } : {}), - }); - - classes[reasonCode] = ParseErrorClass; - - // We do this for backwards compatibility so that all errors just have the - // "SyntaxError" name in their messages instead of leaking the private - // subclass name. - ObjectDefineProperty(ParseErrorClass.prototype.constructor, "name", { - value: "SyntaxError", + ...partialCredentials[reasonCode], }); } - return classes; + return ParseErrorConstructors; } export type RaiseProperties = {| @@ -208,10 +165,10 @@ import StrictModeErrors from "./parse-error/strict-mode-errors"; import PipelineOperatorErrors from "./parse-error/pipeline-operator-errors"; export const Errors = { - ...toParseErrorClasses(ModuleErrors), - ...toParseErrorClasses(StandardErrors), - ...toParseErrorClasses(StrictModeErrors), - ...toParseErrorClasses`pipelineOperator`(PipelineOperatorErrors), + ...ParseErrorEnum(ModuleErrors), + ...ParseErrorEnum(StandardErrors), + ...ParseErrorEnum(StrictModeErrors), + ...ParseErrorEnum`pipelineOperator`(PipelineOperatorErrors), }; export type { LValAncestor } from "./parse-error/standard-errors"; diff --git a/packages/babel-parser/src/parse-error/credentials.js b/packages/babel-parser/src/parse-error/credentials.js index 437dc7a97742..477240c24b40 100644 --- a/packages/babel-parser/src/parse-error/credentials.js +++ b/packages/babel-parser/src/parse-error/credentials.js @@ -14,8 +14,53 @@ export type SyntaxPlugin = | "pipelineOperator" | "placeholders"; -export type ParseErrorCredentials = { +export type ToMessage = (self: ErrorDetails) => string; + +export type ParseErrorCredentials = { code: ParseErrorCode, reasonCode: string, syntaxPlugin?: SyntaxPlugin, + + toMessage: ToMessage, }; + +const thisify = (f: (self: any, ...args: any[]) => T): ((...any[]) => T) => + function (...args: any[]): T { + return ((f(this, ...args): any): T); + }; + +const reflect = (keys: string[], last = keys.length - 1) => ({ + get: self => keys.reduce((object, key) => object[key], self), + set: (self, value) => + keys.reduce( + (item, key, i) => (i === last ? (item[key] = value) : item[key]), + self, + ), +}); + +const instantiate = ( + constructor: () => any, + properties: Object, + descriptors: Object, +) => + Object.keys(descriptors) + .map(key => [key, descriptors[key]]) + .filter(([, descriptor]) => !!descriptor) + .map(([key, descriptor]) => [ + key, + typeof descriptor === "string" + ? reflect(descriptor.split(".")) + : descriptor, + ]) + .reduce( + (instance, [key, descriptor]) => + Object.defineProperty(instance, key, { + configurable: true, + ...descriptor, + ...(descriptor.get && { get: thisify(descriptor.get) }), + ...(descriptor.set && { set: thisify(descriptor.set) }), + }), + Object.assign((new constructor(): T), properties), + ); + +export { instantiate }; diff --git a/packages/babel-parser/src/parser/expression.js b/packages/babel-parser/src/parser/expression.js index 96ff0ddf7e66..a6318ef65905 100644 --- a/packages/babel-parser/src/parser/expression.js +++ b/packages/babel-parser/src/parser/expression.js @@ -67,7 +67,7 @@ import { newAsyncArrowScope, newExpressionScope, } from "../util/expression-scope"; -import { Errors, ParseError } from "../parse-error"; +import { Errors, type ParseError } from "../parse-error"; import { UnparenthesizedPipeBodyDescriptions } from "../parse-error/pipeline-operator-errors"; import { setInnerComments } from "./comments"; import { cloneIdentifier } from "./node"; diff --git a/packages/babel-parser/src/parser/util.js b/packages/babel-parser/src/parser/util.js index 5830618d197c..fbe51edefa16 100644 --- a/packages/babel-parser/src/parser/util.js +++ b/packages/babel-parser/src/parser/util.js @@ -18,7 +18,11 @@ import ProductionParameterHandler, { PARAM_AWAIT, PARAM, } from "../util/production-parameter"; -import { Errors, ParseError } from "../parse-error"; +import { + Errors, + type ParseError, + type ParseErrorConstructor, +} from "../parse-error"; /*:: import type ScopeHandler from "../util/scope"; */ @@ -97,11 +101,11 @@ export default class UtilParser extends Tokenizer { expectContextual( token: TokenType, - ParseErrorClass?: Class>, + toParseError?: ParseErrorConstructor, ): void { if (!this.eatContextual(token)) { - if (ParseErrorClass != null) { - throw this.raise(ParseErrorClass, { at: this.state.startLoc }); + if (toParseError != null) { + throw this.raise(toParseError, { at: this.state.startLoc }); } throw this.unexpected(null, token); } @@ -190,7 +194,7 @@ export default class UtilParser extends Tokenizer { } catch (error) { const failState = this.state; this.state = oldState; - if (error instanceof ParseError) { + if (error instanceof SyntaxError) { return { node: null, error, thrown: true, aborted: false, failState }; } if (error === abortSignal) { diff --git a/packages/babel-parser/src/plugins/flow/index.js b/packages/babel-parser/src/plugins/flow/index.js index 38fd875af437..bcb69382e7b0 100644 --- a/packages/babel-parser/src/plugins/flow/index.js +++ b/packages/babel-parser/src/plugins/flow/index.js @@ -29,7 +29,7 @@ import { SCOPE_OTHER, } from "../../util/scopeflags"; import type { ExpressionErrors } from "../../parser/util"; -import { Errors, toParseErrorClasses } from "../../parse-error"; +import { Errors, ParseErrorEnum } from "../../parse-error"; import { cloneIdentifier } from "../../parser/node"; const reservedTypes = new Set([ @@ -53,7 +53,7 @@ const reservedTypes = new Set([ /* eslint sort-keys: "error" */ // The Errors key follows https://github.com/facebook/flow/blob/master/src/parser/parse_error.ml unless it does not exist -const FlowErrors = toParseErrorClasses`flow`(_ => ({ +const FlowErrors = ParseErrorEnum`flow`(_ => ({ AmbiguousConditionalArrow: _( "Ambiguous expression: wrap the arrow functions in parentheses to disambiguate.", ), diff --git a/packages/babel-parser/src/plugins/jsx/index.js b/packages/babel-parser/src/plugins/jsx/index.js index eabf27d6a024..918524db8139 100644 --- a/packages/babel-parser/src/plugins/jsx/index.js +++ b/packages/babel-parser/src/plugins/jsx/index.js @@ -17,13 +17,13 @@ import * as N from "../../types"; import { isIdentifierChar, isIdentifierStart } from "../../util/identifier"; import type { Position } from "../../util/location"; import { isNewLine } from "../../util/whitespace"; -import { Errors, toParseErrorClasses } from "../../parse-error"; +import { Errors, ParseErrorEnum } from "../../parse-error"; const HEX_NUMBER = /^[\da-fA-F]+$/; const DECIMAL_NUMBER = /^\d+$/; /* eslint sort-keys: "error" */ -const JsxErrors = toParseErrorClasses`jsx`(_ => ({ +const JsxErrors = ParseErrorEnum`jsx`(_ => ({ AttributeIsEmpty: _( "JSX attributes must only be assigned a non-empty expression.", ), diff --git a/packages/babel-parser/src/plugins/placeholders.js b/packages/babel-parser/src/plugins/placeholders.js index 9859e4a96d37..3b28fc968b65 100644 --- a/packages/babel-parser/src/plugins/placeholders.js +++ b/packages/babel-parser/src/plugins/placeholders.js @@ -5,7 +5,7 @@ import * as charCodes from "charcodes"; import { tokenLabelName, tt } from "../tokenizer/types"; import type Parser from "../parser"; import * as N from "../types"; -import { toParseErrorClasses } from "../parse-error"; +import { ParseErrorEnum } from "../parse-error"; export type PlaceholderTypes = | "Identifier" @@ -47,7 +47,7 @@ type NodeOf = $Switch< type MaybePlaceholder = NodeOf; // | Placeholder /* eslint sort-keys: "error" */ -const PlaceholderErrors = toParseErrorClasses`placeholders`(_ => ({ +const PlaceholderErrors = ParseErrorEnum`placeholders`(_ => ({ ClassNameIsRequired: _("A class name is required."), UnexpectedSpace: _("Unexpected space in placeholder."), })); diff --git a/packages/babel-parser/src/plugins/typescript/index.js b/packages/babel-parser/src/plugins/typescript/index.js index 3a3fc29921b1..f6d0110779ff 100644 --- a/packages/babel-parser/src/plugins/typescript/index.js +++ b/packages/babel-parser/src/plugins/typescript/index.js @@ -35,7 +35,7 @@ import TypeScriptScopeHandler from "./scope"; import * as charCodes from "charcodes"; import type { ExpressionErrors } from "../../parser/util"; import { PARAM } from "../../util/production-parameter"; -import { Errors, toParseErrorClasses } from "../../parse-error"; +import { Errors, ParseErrorEnum } from "../../parse-error"; import { cloneIdentifier } from "../../parser/node"; type TsModifier = @@ -68,7 +68,7 @@ type ParsingContext = | "TypeParametersOrArguments"; /* eslint sort-keys: "error" */ -const TSErrors = toParseErrorClasses`typescript`(_ => ({ +const TSErrors = ParseErrorEnum`typescript`(_ => ({ AbstractMethodHasImplementation: _<{| methodName: string |}>( ({ methodName }) => `Method '${methodName}' cannot have an implementation because it is marked abstract.`, diff --git a/packages/babel-parser/src/tokenizer/index.js b/packages/babel-parser/src/tokenizer/index.js index e5fabcb6e19f..ec5252b43ec9 100644 --- a/packages/babel-parser/src/tokenizer/index.js +++ b/packages/babel-parser/src/tokenizer/index.js @@ -20,7 +20,12 @@ import { type TokenType, } from "./types"; import { type TokContext } from "./context"; -import { Errors, ParseError, type RaiseProperties } from "../parse-error"; +import { + Errors, + type ParseError, + type ParseErrorConstructor, + type RaiseProperties, +} from "../parse-error"; import { lineBreakG, isNewLine, @@ -28,7 +33,7 @@ import { skipWhiteSpace, } from "../util/whitespace"; import State from "./state"; -import type { LookaheadState, DeferredStrictErrorClass } from "./state"; +import type { LookaheadState, DeferredStrictError } from "./state"; const VALID_REGEX_FLAGS = new Set([ charCodes.lowercaseG, @@ -282,8 +287,8 @@ export default class Tokenizer extends CommentsParser { // after a "use strict" directive. Strict mode will be set at parse // time for any literals that occur after the next node of the strict // directive. - this.state.strictErrors.forEach(([ParseErrorClass, at]) => - this.raise(ParseErrorClass, { at }), + this.state.strictErrors.forEach(([toParseError, at]) => + this.raise(toParseError, { at }), ); this.state.strictErrors.clear(); } @@ -1534,15 +1539,15 @@ export default class Tokenizer extends CommentsParser { } recordStrictModeErrors( - ParseErrorClass: DeferredStrictErrorClass, + toParseError: DeferredStrictError, { at }: { at: Position }, ) { const index = at.index; if (this.state.strict && !this.state.strictErrors.has(index)) { - this.raise(ParseErrorClass, { at }); + this.raise(toParseError, { at }); } else { - this.state.strictErrors.set(index, [ParseErrorClass, at]); + this.state.strictErrors.set(index, [toParseError, at]); } } @@ -1753,13 +1758,13 @@ export default class Tokenizer extends CommentsParser { * @returns {(ParseError | empty)} * @memberof Tokenizer */ - raise>>( - ParseErrorClass: T, + raise( + toParseError: ParseErrorConstructor, raiseProperties: RaiseProperties, ): ParseError { const { at, ...details } = raiseProperties; const loc = at instanceof Position ? at : at.loc.start; - const error = new ParseErrorClass({ loc, details }); + const error = toParseError({ loc, details }); if (!this.options.errorRecovery) throw error; if (!this.isLookahead) this.state.errors.push(error); @@ -1778,8 +1783,8 @@ export default class Tokenizer extends CommentsParser { * @returns {(ParseError | empty)} * @memberof Tokenizer */ - raiseOverwrite>>( - ParseErrorClass: T, + raiseOverwrite( + toParseError: ParseErrorConstructor, raiseProperties: RaiseProperties, ): ParseError | empty { const { at, ...details } = raiseProperties; @@ -1789,13 +1794,13 @@ export default class Tokenizer extends CommentsParser { for (let i = errors.length - 1; i >= 0; i--) { const error = errors[i]; - if (error.pos === pos) { - return (errors[i] = new ParseErrorClass({ loc, details })); + if (error.loc.index === pos) { + return (errors[i] = toParseError({ loc, details })); } - if (error.pos < pos) break; + if (error.loc.index < pos) break; } - return this.raise(ParseErrorClass, raiseProperties); + return this.raise(toParseError, raiseProperties); } // updateContext is used by the jsx plugin diff --git a/packages/babel-parser/src/tokenizer/state.js b/packages/babel-parser/src/tokenizer/state.js index 1e3fe4d300cd..692da2c1c591 100644 --- a/packages/babel-parser/src/tokenizer/state.js +++ b/packages/babel-parser/src/tokenizer/state.js @@ -7,9 +7,9 @@ import { Position } from "../util/location"; import { types as ct, type TokContext } from "./context"; import { tt, type TokenType } from "./types"; -import { Errors, ParseError } from "../parse-error"; +import { Errors, type ParseError } from "../parse-error"; -export type DeferredStrictErrorClass = +export type DeferredStrictError = | typeof Errors.StrictNumericEscape | typeof Errors.StrictOctalLiteral; @@ -144,7 +144,7 @@ export default class State { // todo(JLHwung): set strictErrors to null and avoid recording string errors // after a non-directive is parsed - strictErrors: Map = new Map(); + strictErrors: Map = new Map(); // Tokens length in token store tokensLength: number = 0; diff --git a/packages/babel-parser/src/util/expression-scope.js b/packages/babel-parser/src/util/expression-scope.js index 3886c613731a..c38394f0b6ac 100644 --- a/packages/babel-parser/src/util/expression-scope.js +++ b/packages/babel-parser/src/util/expression-scope.js @@ -76,24 +76,22 @@ class ExpressionScope { } } -type ArrowHeadParsingParameterInitializerErrorClass = +type ArrowHeadParsingParameterInitializerError = | typeof Errors.AwaitExpressionFormalParameter | typeof Errors.YieldInParameter; -type ArrowHeadParsingDeclarationErrorClass = - | ArrowHeadParsingParameterInitializerErrorClass +type ArrowHeadParsingDeclarationError = + | ArrowHeadParsingParameterInitializerError | typeof Errors.InvalidParenthesizedAssignment | typeof Errors.AwaitBindingIdentifier; class ArrowHeadParsingScope extends ExpressionScope { - declarationErrors: Map< - number, - [ArrowHeadParsingDeclarationErrorClass, Position], - > = new Map(); + declarationErrors: Map = + new Map(); constructor(type: 1 | 2) { super(type); } - recordDeclarationError( + recordDeclarationError( ParsingErrorClass: T, { at }: { at: Position }, ) { @@ -105,7 +103,7 @@ class ArrowHeadParsingScope extends ExpressionScope { this.declarationErrors.delete(index); } iterateErrors( - iterator: ([ArrowHeadParsingDeclarationErrorClass, Position]) => void, + iterator: ([ArrowHeadParsingDeclarationError, Position]) => void, ) { this.declarationErrors.forEach(iterator); } @@ -137,7 +135,7 @@ export default class ExpressionScopeHandler { * @memberof ExpressionScopeHandler */ recordParameterInitializerError( - ParseErrorClass: ArrowHeadParsingParameterInitializerErrorClass, + toParseError: ArrowHeadParsingParameterInitializerError, { at: node }: { at: Node }, ): void { const origin = { at: node.loc.start }; @@ -147,7 +145,7 @@ export default class ExpressionScopeHandler { while (!scope.isCertainlyParameterDeclaration()) { if (scope.canBeArrowParameterDeclaration()) { /*:: invariant(scope instanceof ArrowHeadParsingScope) */ - scope.recordDeclarationError(ParseErrorClass, origin); + scope.recordDeclarationError(toParseError, origin); } else { /*:: invariant(scope.type == kExpression) */ // Type-Expression is the boundary where initializer error can populate to @@ -155,7 +153,7 @@ export default class ExpressionScopeHandler { } scope = stack[--i]; } - this.parser.raise(ParseErrorClass, origin); + this.parser.raise(toParseError, origin); } /** @@ -223,8 +221,8 @@ export default class ExpressionScopeHandler { const currentScope = stack[stack.length - 1]; if (!currentScope.canBeArrowParameterDeclaration()) return; /*:: invariant(currentScope instanceof ArrowHeadParsingScope) */ - currentScope.iterateErrors(([ParseErrorClass, loc]) => { - this.parser.raise(ParseErrorClass, { at: loc }); + currentScope.iterateErrors(([toParseError, loc]) => { + this.parser.raise(toParseError, { at: loc }); // iterate from parent scope let i = stack.length - 2; let scope = stack[i];