aboutsummaryrefslogtreecommitdiff
path: root/node_modules/meriyah/src/parser.ts
diff options
context:
space:
mode:
authorMinteck <nekostarfan@gmail.com>2021-08-24 14:41:48 +0200
committerMinteck <nekostarfan@gmail.com>2021-08-24 14:41:48 +0200
commitd25e11bee6ca5ca523884da132d18e1400e077b9 (patch)
tree8af39fde19f7ed640a60fb397c7edd647dff1c4c /node_modules/meriyah/src/parser.ts
downloadkartik-iridium-d25e11bee6ca5ca523884da132d18e1400e077b9.tar.gz
kartik-iridium-d25e11bee6ca5ca523884da132d18e1400e077b9.tar.bz2
kartik-iridium-d25e11bee6ca5ca523884da132d18e1400e077b9.zip
Initial commit
Diffstat (limited to 'node_modules/meriyah/src/parser.ts')
-rw-r--r--node_modules/meriyah/src/parser.ts9165
1 files changed, 9165 insertions, 0 deletions
diff --git a/node_modules/meriyah/src/parser.ts b/node_modules/meriyah/src/parser.ts
new file mode 100644
index 0000000..d5b4a51
--- /dev/null
+++ b/node_modules/meriyah/src/parser.ts
@@ -0,0 +1,9165 @@
+import { nextToken, skipHashBang } from './lexer';
+import { Token, KeywordDescTable } from './token';
+import * as ESTree from './estree';
+import { report, reportMessageAt, reportScopeError, Errors } from './errors';
+import { scanTemplateTail } from './lexer/template';
+import { scanJSXIdentifier, scanJSXToken, scanJSXAttributeValue } from './lexer/jsx';
+import {
+ Context,
+ ParserState,
+ PropertyKind,
+ Origin,
+ consumeOpt,
+ consume,
+ Flags,
+ OnComment,
+ OnToken,
+ pushComment,
+ pushToken,
+ reinterpretToPattern,
+ DestructuringKind,
+ AssignmentKind,
+ BindingKind,
+ validateBindingIdentifier,
+ validateFunctionName,
+ isStrictReservedWord,
+ optionalBit,
+ matchOrInsertSemicolon,
+ isPropertyWithPrivateFieldKey,
+ isValidLabel,
+ validateAndDeclareLabel,
+ finishNode,
+ HoistedClassFlags,
+ HoistedFunctionFlags,
+ createScope,
+ addChildScope,
+ ScopeKind,
+ ScopeState,
+ addVarName,
+ addBlockName,
+ addBindingToExports,
+ declareUnboundVariable,
+ isEqualTagName,
+ isValidStrictMode,
+ createArrowHeadParsingScope,
+ addVarOrBlock,
+ isValidIdentifier,
+ classifyIdentifier
+} from './common';
+
+/**
+ * Create a new parser instance
+ */
+
+export function create(
+ source: string,
+ sourceFile: string | void,
+ onComment: OnComment | void,
+ onToken: OnToken | void
+): ParserState {
+ return {
+ /**
+ * The source code to be parsed
+ */
+ source,
+
+ /**
+ * The mutable parser flags, in case any flags need passed by reference.
+ */
+ flags: Flags.None,
+
+ /**
+ * The current index
+ */
+ index: 0,
+
+ /**
+ * Beginning of current line
+ */
+ line: 1,
+
+ /**
+ * Beginning of current column
+ */
+ column: 0,
+
+ /**
+ * Start position of whitespace before current token
+ */
+ startPos: 0,
+
+ /**
+ * The end of the source code
+ */
+ end: source.length,
+
+ /**
+ * Start position of text of current token
+ */
+ tokenPos: 0,
+
+ /**
+ * Start position of the colum before newline
+ */
+ startColumn: 0,
+
+ /**
+ * Position in the input code of the first character after the last newline
+ */
+ colPos: 0,
+
+ /**
+ * The number of newlines
+ */
+ linePos: 1,
+
+ /**
+ * Start position of text of current token
+ */
+ startLine: 1,
+
+ /**
+ * Used together with source maps. File containing the code being parsed
+ */
+
+ sourceFile,
+
+ /**
+ * Holds the scanned token value
+ */
+ tokenValue: '',
+
+ /**
+ * The current token in the stream to consume
+ */
+ token: Token.EOF,
+
+ /**
+ * Holds the raw text that have been scanned by the lexer
+ */
+ tokenRaw: '',
+
+ /**
+ * Holds the regExp info text that have been collected by the lexer
+ */
+ tokenRegExp: void 0,
+
+ /**
+ * The code point at the current index
+ */
+ currentChar: source.charCodeAt(0),
+
+ /**
+ * https://tc39.es/ecma262/#sec-module-semantics-static-semantics-exportednames
+ */
+ exportedNames: [],
+
+ /**
+ * https://tc39.es/ecma262/#sec-exports-static-semantics-exportedbindings
+ */
+
+ exportedBindings: [],
+
+ /**
+ * Assignable state
+ */
+ assignable: 1,
+
+ /**
+ * Destructuring state
+ */
+ destructible: 0,
+
+ /**
+ * Holds either a function or array used on every comment
+ */
+ onComment,
+
+ /**
+ * Holds either a function or array used on every token
+ */
+ onToken,
+
+ /**
+ * Holds leading decorators before "export" or "class" keywords
+ */
+ leadingDecorators: []
+ };
+}
+
+/**
+ * The parser options.
+ */
+export interface Options {
+ // Allow module code
+ module?: boolean;
+ // Enable stage 3 support (ESNext)
+ next?: boolean;
+ // Enable start and end offsets to each node
+ ranges?: boolean;
+ // Enable web compatibility
+ webcompat?: boolean;
+ // Enable line/column location information to each node
+ loc?: boolean;
+ // Attach raw property to each literal and identifier node
+ raw?: boolean;
+ // Enabled directives
+ directives?: boolean;
+ // Allow return in the global scope
+ globalReturn?: boolean;
+ // Enable implied strict mode
+ impliedStrict?: boolean;
+ // Enable non-standard parenthesized expression node
+ preserveParens?: boolean;
+ // Enable lexical binding and scope tracking
+ lexical?: boolean;
+ // Adds a source attribute in every node’s loc object when the locations option is `true`
+ source?: string;
+ // Distinguish Identifier from IdentifierPattern
+ identifierPattern?: boolean;
+ // Enable React JSX parsing
+ jsx?: boolean;
+ // Allow edge cases that deviate from the spec
+ specDeviation?: boolean;
+ // Allows comment extraction. Accepts either a a callback function or an array
+ onComment?: OnComment;
+ // Allows token extraction. Accepts either a a callback function or an array
+ onToken?: OnToken;
+ // Creates unique key for in ObjectPattern when key value are same
+ uniqueKeyInPattern?: boolean;
+}
+
+/**
+ * Consumes a sequence of tokens and produces an syntax tree
+ */
+export function parseSource(source: string, options: Options | void, context: Context): ESTree.Program {
+ let sourceFile = '';
+ let onComment;
+ let onToken;
+ if (options != null) {
+ if (options.module) context |= Context.Module | Context.Strict;
+ if (options.next) context |= Context.OptionsNext;
+ if (options.loc) context |= Context.OptionsLoc;
+ if (options.ranges) context |= Context.OptionsRanges;
+ if (options.uniqueKeyInPattern) context |= Context.OptionsUniqueKeyInPattern;
+ if (options.lexical) context |= Context.OptionsLexical;
+ if (options.webcompat) context |= Context.OptionsWebCompat;
+ if (options.directives) context |= Context.OptionsDirectives | Context.OptionsRaw;
+ if (options.globalReturn) context |= Context.OptionsGlobalReturn;
+ if (options.raw) context |= Context.OptionsRaw;
+ if (options.preserveParens) context |= Context.OptionsPreserveParens;
+ if (options.impliedStrict) context |= Context.Strict;
+ if (options.jsx) context |= Context.OptionsJSX;
+ if (options.identifierPattern) context |= Context.OptionsIdentifierPattern;
+ if (options.specDeviation) context |= Context.OptionsSpecDeviation;
+ if (options.source) sourceFile = options.source;
+ // Accepts either a callback function to be invoked or an array to collect comments (as the node is constructed)
+ if (options.onComment != null) {
+ onComment = Array.isArray(options.onComment) ? pushComment(context, options.onComment) : options.onComment;
+ }
+ // Accepts either a callback function to be invoked or an array to collect tokens
+ if (options.onToken != null) {
+ onToken = Array.isArray(options.onToken) ? pushToken(context, options.onToken) : options.onToken;
+ }
+ }
+
+ // Initialize parser state
+ const parser = create(source, sourceFile, onComment, onToken);
+
+ // See: https://github.com/tc39/proposal-hashbang
+ if (context & Context.OptionsNext) skipHashBang(parser);
+
+ const scope: ScopeState | undefined = context & Context.OptionsLexical ? createScope() : void 0;
+
+ let body: (ESTree.Statement | ReturnType<typeof parseDirective | typeof parseModuleItem>)[] = [];
+
+ // https://tc39.es/ecma262/#sec-scripts
+ // https://tc39.es/ecma262/#sec-modules
+
+ let sourceType: 'module' | 'script' = 'script';
+
+ if (context & Context.Module) {
+ sourceType = 'module';
+ body = parseModuleItemList(parser, context | Context.InGlobal, scope);
+
+ if (scope) {
+ for (const key in parser.exportedBindings) {
+ if (key[0] === '#' && !(scope as any)[key]) report(parser, Errors.UndeclaredExportedBinding, key.slice(1));
+ }
+ }
+ } else {
+ body = parseStatementList(parser, context | Context.InGlobal, scope);
+ }
+
+ const node: ESTree.Program = {
+ type: 'Program',
+ sourceType,
+ body
+ };
+
+ if (context & Context.OptionsRanges) {
+ node.start = 0;
+ node.end = source.length;
+ node.range = [0, source.length];
+ }
+
+ if (context & Context.OptionsLoc) {
+ node.loc = {
+ start: { line: 1, column: 0 },
+ end: { line: parser.line, column: parser.column }
+ };
+
+ if (parser.sourceFile) node.loc.source = sourceFile;
+ }
+
+ return node;
+}
+
+/**
+ * Parses statement list items
+ *
+ * @param parser Parser object
+ * @param context Context masks
+ */
+export function parseStatementList(
+ parser: ParserState,
+ context: Context,
+ scope: ScopeState | undefined
+): ESTree.Statement[] {
+ // StatementList ::
+ // (StatementListItem)* <end_token>
+
+ nextToken(parser, context | Context.AllowRegExp | Context.AllowEscapedKeyword);
+
+ const statements: ESTree.Statement[] = [];
+
+ while (parser.token === Token.StringLiteral) {
+ // "use strict" must be the exact literal without escape sequences or line continuation.
+ const { index, tokenPos, tokenValue, linePos, colPos, token } = parser;
+ const expr = parseLiteral(parser, context);
+ if (isValidStrictMode(parser, index, tokenPos, tokenValue)) context |= Context.Strict;
+ statements.push(parseDirective(parser, context, expr, token, tokenPos, linePos, colPos));
+ }
+
+ while (parser.token !== Token.EOF) {
+ statements.push(parseStatementListItem(parser, context, scope, Origin.TopLevel, {}) as ESTree.Statement);
+ }
+ return statements;
+}
+
+/**
+ * Parse module item list
+ *
+ * @see [Link](https://tc39.github.io/ecma262/#prod-ModuleItemList)
+ *
+ * @param parser Parser object
+ * @param context Context masks
+ */
+export function parseModuleItemList(
+ parser: ParserState,
+ context: Context,
+ scope: ScopeState | undefined
+): ReturnType<typeof parseDirective | typeof parseModuleItem>[] {
+ // ecma262/#prod-Module
+ // Module :
+ // ModuleBody?
+ //
+ // ecma262/#prod-ModuleItemList
+ // ModuleBody :
+ // ModuleItem*
+
+ nextToken(parser, context | Context.AllowRegExp);
+
+ const statements: ReturnType<typeof parseDirective | typeof parseModuleItem>[] = [];
+
+ // Avoid this if we're not going to create any directive nodes. This is likely to be the case
+ // most of the time, considering the prevalence of strict mode and the fact modules
+ // are already in strict mode.
+ if (context & Context.OptionsDirectives) {
+ while (parser.token === Token.StringLiteral) {
+ const { tokenPos, linePos, colPos, token } = parser;
+ statements.push(parseDirective(parser, context, parseLiteral(parser, context), token, tokenPos, linePos, colPos));
+ }
+ }
+
+ while (parser.token !== Token.EOF) {
+ statements.push(parseModuleItem(parser, context, scope) as ESTree.Statement);
+ }
+ return statements;
+}
+
+/**
+ * Parse module item
+ *
+ * @see [Link](https://tc39.github.io/ecma262/#prod-ModuleItem)
+ *
+ * @param parser Parser object
+ * @param context Context masks
+ * @param scope Scope object
+ */
+
+export function parseModuleItem(parser: ParserState, context: Context, scope: ScopeState | undefined): any {
+ // Support legacy decorators before export keyword.
+ parser.leadingDecorators = parseDecorators(parser, context);
+
+ // ecma262/#prod-ModuleItem
+ // ModuleItem :
+ // ImportDeclaration
+ // ExportDeclaration
+ // StatementListItem
+
+ let moduleItem;
+ switch (parser.token) {
+ case Token.ExportKeyword:
+ moduleItem = parseExportDeclaration(parser, context, scope);
+ break;
+ case Token.ImportKeyword:
+ moduleItem = parseImportDeclaration(parser, context, scope);
+ break;
+ default:
+ moduleItem = parseStatementListItem(parser, context, scope, Origin.TopLevel, {});
+ }
+
+ if (parser.leadingDecorators.length) {
+ report(parser, Errors.InvalidLeadingDecorator);
+ }
+ return moduleItem;
+}
+
+/**
+ * Parse statement list
+ *
+ * @param parser Parser object
+ * @param context Context masks
+ * @param scope Scope object
+ */
+
+export function parseStatementListItem(
+ parser: ParserState,
+ context: Context,
+ scope: ScopeState | undefined,
+ origin: Origin,
+ labels: ESTree.Labels
+): ESTree.Statement | ESTree.Decorator[] {
+ // ECMA 262 10th Edition
+ // StatementListItem[Yield, Return] :
+ // Statement[?Yield, ?Return]
+ // Declaration[?Yield]
+ //
+ // Declaration[Yield] :
+ // HoistableDeclaration[?Yield]
+ // ClassDeclaration[?Yield]
+ // LexicalDeclaration[In, ?Yield]
+ //
+ // HoistableDeclaration[Yield, Default] :
+ // FunctionDeclaration[?Yield, ?Default]
+ // GeneratorDeclaration[?Yield, ?Default]
+ //
+ // LexicalDeclaration[In, Yield] :
+ // LetOrConst BindingList[?In, ?Yield] ;
+ const start = parser.tokenPos;
+ const line = parser.linePos;
+ const column = parser.colPos;
+
+ switch (parser.token) {
+ // HoistableDeclaration[?Yield, ~Default]
+ case Token.FunctionKeyword:
+ return parseFunctionDeclaration(
+ parser,
+ context,
+ scope,
+ origin,
+ 1,
+ HoistedFunctionFlags.None,
+ 0,
+ start,
+ line,
+ column
+ );
+ // @decorator
+ case Token.Decorator:
+ // ClassDeclaration[?Yield, ~Default]
+ case Token.ClassKeyword:
+ return parseClassDeclaration(parser, context, scope, HoistedClassFlags.None, start, line, column);
+ // LexicalDeclaration[In, ?Yield]
+ // LetOrConst BindingList[?In, ?Yield]
+ case Token.ConstKeyword:
+ return parseLexicalDeclaration(parser, context, scope, BindingKind.Const, Origin.None, start, line, column);
+ case Token.LetKeyword:
+ return parseLetIdentOrVarDeclarationStatement(parser, context, scope, origin, start, line, column);
+ // ExportDeclaration
+ case Token.ExportKeyword:
+ report(parser, Errors.InvalidImportExportSloppy, 'export');
+ // ImportDeclaration
+ case Token.ImportKeyword:
+ nextToken(parser, context);
+ switch (parser.token) {
+ case Token.LeftParen:
+ return parseImportCallDeclaration(parser, context, start, line, column);
+ case Token.Period:
+ return parseImportMetaDeclaration(parser, context, start, line, column);
+ default:
+ report(parser, Errors.InvalidImportExportSloppy, 'import');
+ }
+ // async [no LineTerminator here] AsyncArrowBindingIdentifier ...
+ // async [no LineTerminator here] ArrowFormalParameters ...
+ case Token.AsyncKeyword:
+ return parseAsyncArrowOrAsyncFunctionDeclaration(parser, context, scope, origin, labels, 1, start, line, column);
+ default:
+ return parseStatement(parser, context, scope, origin, labels, 1, start, line, column);
+ }
+}
+
+/**
+ * Parse statement
+ *
+ * @param parser Parser object
+ * @param context Context masks
+ * @param allowFuncDecl Allow / disallow func statement
+ */
+
+export function parseStatement(
+ parser: ParserState,
+ context: Context,
+ scope: ScopeState | undefined,
+ origin: Origin,
+ labels: ESTree.Labels,
+ allowFuncDecl: 0 | 1,
+ start: number,
+ line: number,
+ column: number
+): ESTree.Statement {
+ // Statement ::
+ // Block
+ // VariableStatement
+ // EmptyStatement
+ // ExpressionStatement
+ // IfStatement
+ // IterationStatement
+ // ContinueStatement
+ // BreakStatement
+ // ReturnStatement
+ // WithStatement
+ // LabelledStatement
+ // SwitchStatement
+ // ThrowStatement
+ // TryStatement
+ // DebuggerStatement
+
+ switch (parser.token) {
+ // VariableStatement[?Yield]
+ case Token.VarKeyword:
+ return parseVariableStatement(parser, context, scope, Origin.None, start, line, column);
+ // [+Return] ReturnStatement[?Yield]
+ case Token.ReturnKeyword:
+ return parseReturnStatement(parser, context, start, line, column);
+ case Token.IfKeyword:
+ return parseIfStatement(parser, context, scope, labels, start, line, column);
+ case Token.ForKeyword:
+ return parseForStatement(parser, context, scope, labels, start, line, column);
+ // BreakableStatement[Yield, Return]:
+ // IterationStatement[?Yield, ?Return]
+ // SwitchStatement[?Yield, ?Return]
+ case Token.DoKeyword:
+ return parseDoWhileStatement(parser, context, scope, labels, start, line, column);
+ case Token.WhileKeyword:
+ return parseWhileStatement(parser, context, scope, labels, start, line, column);
+ case Token.SwitchKeyword:
+ return parseSwitchStatement(parser, context, scope, labels, start, line, column);
+ case Token.Semicolon:
+ // EmptyStatement
+ return parseEmptyStatement(parser, context, start, line, column);
+ // BlockStatement[?Yield, ?Return]
+ case Token.LeftBrace:
+ return parseBlock(
+ parser,
+ context,
+ scope ? addChildScope(scope, ScopeKind.Block) : scope,
+ labels,
+ start,
+ line,
+ column
+ ) as ESTree.Statement;
+
+ // ThrowStatement[?Yield]
+ case Token.ThrowKeyword:
+ return parseThrowStatement(parser, context, start, line, column);
+ case Token.BreakKeyword:
+ // BreakStatement[?Yield]
+ return parseBreakStatement(parser, context, labels, start, line, column);
+ // ContinueStatement[?Yield]
+ case Token.ContinueKeyword:
+ return parseContinueStatement(parser, context, labels, start, line, column);
+ // TryStatement[?Yield, ?Return]
+ case Token.TryKeyword:
+ return parseTryStatement(parser, context, scope, labels, start, line, column);
+ // WithStatement[?Yield, ?Return]
+ case Token.WithKeyword:
+ return parseWithStatement(parser, context, scope, labels, start, line, column);
+ case Token.DebuggerKeyword:
+ // DebuggerStatement
+ return parseDebuggerStatement(parser, context, start, line, column);
+ case Token.AsyncKeyword:
+ return parseAsyncArrowOrAsyncFunctionDeclaration(parser, context, scope, origin, labels, 0, start, line, column);
+ // Miscellaneous error cases arguably better caught here than elsewhere
+ case Token.CatchKeyword:
+ report(parser, Errors.CatchWithoutTry);
+ case Token.FinallyKeyword:
+ report(parser, Errors.FinallyWithoutTry);
+ case Token.FunctionKeyword:
+ // FunctionDeclaration & ClassDeclaration is forbidden by lookahead
+ // restriction in an arbitrary statement position.
+ report(
+ parser,
+ context & Context.Strict
+ ? Errors.StrictFunction
+ : (context & Context.OptionsWebCompat) < 1
+ ? Errors.WebCompatFunction
+ : Errors.SloppyFunction
+ );
+ case Token.ClassKeyword:
+ report(parser, Errors.ClassForbiddenAsStatement);
+
+ default:
+ return parseExpressionOrLabelledStatement(
+ parser,
+ context,
+ scope,
+ origin,
+ labels,
+ allowFuncDecl,
+ start,
+ line,
+ column
+ );
+ }
+}
+
+/**
+ * Parses either expression or labeled statement
+ *
+ * @param parser Parser object
+ * @param context Context masks
+ * @param allowFuncDecl Allow / disallow func statement
+ */
+
+export function parseExpressionOrLabelledStatement(
+ parser: ParserState,
+ context: Context,
+ scope: ScopeState | undefined,
+ origin: Origin,
+ labels: ESTree.Labels,
+ allowFuncDecl: 0 | 1,
+ start: number,
+ line: number,
+ column: number
+): ESTree.ExpressionStatement | ESTree.LabeledStatement {
+ // ExpressionStatement | LabelledStatement ::
+ // Expression ';'
+ // Identifier ':' Statement
+ //
+ // ExpressionStatement[Yield] :
+ // [lookahead notin {{, function, class, let [}] Expression[In, ?Yield] ;
+
+ const { tokenValue, token } = parser;
+
+ let expr: ESTree.Expression;
+
+ switch (token) {
+ case Token.LetKeyword:
+ expr = parseIdentifier(parser, context, 0);
+ if (context & Context.Strict) report(parser, Errors.UnexpectedLetStrictReserved);
+
+ // "let" followed by either "[", "{" or an identifier means a lexical
+ // declaration, which should not appear here.
+ // However, ASI may insert a line break before an identifier or a brace.
+ if (parser.token === Token.LeftBracket) report(parser, Errors.RestrictedLetProduction);
+
+ break;
+
+ default:
+ expr = parsePrimaryExpression(
+ parser,
+ context,
+ BindingKind.Empty,
+ 0,
+ 1,
+ 0,
+ 0,
+ 1,
+ parser.tokenPos,
+ parser.linePos,
+ parser.colPos
+ );
+ }
+
+ /** LabelledStatement[Yield, Await, Return]:
+ *
+ * ExpressionStatement | LabelledStatement ::
+ * Expression ';'
+ * Identifier ':' Statement
+ *
+ * ExpressionStatement[Yield] :
+ * [lookahead notin {{, function, class, let [}] Expression[In, ?Yield] ;
+ */
+ if (token & Token.IsIdentifier && parser.token === Token.Colon) {
+ return parseLabelledStatement(
+ parser,
+ context,
+ scope,
+ origin,
+ labels,
+ tokenValue,
+ expr,
+ token,
+ allowFuncDecl,
+ start,
+ line,
+ column
+ );
+ }
+ /** MemberExpression :
+ * 1. PrimaryExpression
+ * 2. MemberExpression [ AssignmentExpression ]
+ * 3. MemberExpression . IdentifierName
+ * 4. MemberExpression TemplateLiteral
+ *
+ * CallExpression :
+ * 1. MemberExpression Arguments
+ * 2. CallExpression ImportCall
+ * 3. CallExpression Arguments
+ * 4. CallExpression [ AssignmentExpression ]
+ * 5. CallExpression . IdentifierName
+ * 6. CallExpression TemplateLiteral
+ *
+ * UpdateExpression ::
+ * ('++' | '--')? LeftHandSideExpression
+ *
+ */
+
+ expr = parseMemberOrUpdateExpression(parser, context, expr, 0, 0, start, line, column);
+
+ /** AssignmentExpression :
+ * 1. ConditionalExpression
+ * 2. LeftHandSideExpression = AssignmentExpression
+ *
+ */
+
+ expr = parseAssignmentExpression(parser, context, 0, 0, start, line, column, expr as ESTree.ArgumentExpression);
+
+ /** Sequence expression
+ *
+ * Note: The comma operator leads to a sequence expression which is not equivalent
+ * to the ES Expression, but it's part of the ESTree specs:
+ *
+ * https://github.com/estree/estree/blob/master/es5.md#sequenceexpression
+ *
+ */
+ if (parser.token === Token.Comma) {
+ expr = parseSequenceExpression(parser, context, 0, start, line, column, expr);
+ }
+
+ /**
+ * ExpressionStatement[Yield, Await]:
+ * [lookahead ∉ { {, function, async [no LineTerminator here] function, class, let [ }]Expression[+In, ?Yield, ?Await]
+ */
+
+ return parseExpressionStatement(parser, context, expr, start, line, column);
+}
+
+/**
+ * Parses block statement
+ *
+ * @see [Link](https://tc39.github.io/ecma262/#prod-BlockStatement)
+ * @see [Link](https://tc39.github.io/ecma262/#prod-Block)
+ *
+ * @param parser Parser object
+ * @param context Context masks
+ * @param scope Scope object
+ * @param labels Labels object
+ * @param start
+ * @param line
+ * @param column
+ *
+ */
+export function parseBlock(
+ parser: ParserState,
+ context: Context,
+ scope: ScopeState | undefined,
+ labels: ESTree.Labels,
+ start: number,
+ line: number,
+ column: number
+): ESTree.BlockStatement {
+ // Block ::
+ // '{' StatementList '}'
+ const body: ESTree.Statement[] = [];
+ consume(parser, context | Context.AllowRegExp, Token.LeftBrace);
+ while (parser.token !== Token.RightBrace) {
+ body.push(parseStatementListItem(parser, context, scope, Origin.BlockStatement, { $: labels }) as any);
+ }
+
+ consume(parser, context | Context.AllowRegExp, Token.RightBrace);
+
+ return finishNode(parser, context, start, line, column, {
+ type: 'BlockStatement',
+ body
+ });
+}
+
+/**
+ * Parses return statement
+ *
+ * @see [Link](https://tc39.github.io/ecma262/#prod-ReturnStatement)
+ *
+ * @param parser Parser object
+ * @param context Context masks
+ * @param start
+ * @param line
+ * @param column
+ */
+export function parseReturnStatement(
+ parser: ParserState,
+ context: Context,
+ start: number,
+ line: number,
+ column: number
+): ESTree.ReturnStatement {
+ // ReturnStatement ::
+ // 'return' [no line terminator] Expression? ';'
+ if ((context & Context.OptionsGlobalReturn) < 1 && context & Context.InGlobal) report(parser, Errors.IllegalReturn);
+
+ nextToken(parser, context | Context.AllowRegExp);
+
+ const argument =
+ parser.flags & Flags.NewLine || parser.token & Token.IsAutoSemicolon
+ ? null
+ : parseExpressions(parser, context, 0, 1, parser.tokenPos, parser.line, parser.column);
+
+ matchOrInsertSemicolon(parser, context | Context.AllowRegExp);
+
+ return finishNode(parser, context, start, line, column, {
+ type: 'ReturnStatement',
+ argument
+ });
+}
+
+/**
+ * Parses an expression statement
+ *
+ * @see [Link](https://tc39.github.io/ecma262/#prod-ExpressionStatement)
+ *
+ * @param parser Parser object
+ * @param context Context masks
+ * @param expression AST node
+ * @param start
+ * @param line
+ * @param column
+ */
+export function parseExpressionStatement(
+ parser: ParserState,
+ context: Context,
+ expression: ESTree.Expression,
+ start: number,
+ line: number,
+ column: number
+): ESTree.ExpressionStatement {
+ matchOrInsertSemicolon(parser, context | Context.AllowRegExp);
+ return finishNode(parser, context, start, line, column, {
+ type: 'ExpressionStatement',
+ expression
+ });
+}
+
+/**
+ * Parses either expression or labeled statement
+ *
+ * @param parser Parser object
+ * @param context Context masks
+ * @param expr ESTree AST node
+ * @param token Token to validate
+ * @param allowFuncDecl Allow / disallow func statement
+ * @param start
+ * @param line
+ * @param column
+ *
+ */
+export function parseLabelledStatement(
+ parser: ParserState,
+ context: Context,
+ scope: ScopeState | undefined,
+ origin: Origin,
+ labels: ESTree.Labels,
+ value: string,
+ expr: ESTree.Identifier | ESTree.Expression,
+ token: Token,
+ allowFuncDecl: 0 | 1,
+ start: number,
+ line: number,
+ column: number
+): ESTree.LabeledStatement {
+ // LabelledStatement ::
+ // Expression ';'
+ // Identifier ':' Statement
+
+ validateBindingIdentifier(parser, context, BindingKind.None, token, 1);
+ validateAndDeclareLabel(parser, labels, value);
+
+ nextToken(parser, context | Context.AllowRegExp); // skip: ':'
+
+ const body =
+ allowFuncDecl &&
+ (context & Context.Strict) < 1 &&
+ context & Context.OptionsWebCompat &&
+ // In sloppy mode, Annex B.3.2 allows labelled function declarations.
+ // Otherwise it's a parse error.
+ parser.token === Token.FunctionKeyword
+ ? parseFunctionDeclaration(
+ parser,
+ context,
+ addChildScope(scope, ScopeKind.Block),
+ origin,
+ 0,
+ HoistedFunctionFlags.None,
+ 0,
+ parser.tokenPos,
+ parser.linePos,
+ parser.colPos
+ )
+ : parseStatement(
+ parser,
+ context,
+ scope,
+ origin,
+ labels,
+ allowFuncDecl,
+ parser.tokenPos,
+ parser.linePos,
+ parser.colPos
+ );
+
+ return finishNode(parser, context, start, line, column, {
+ type: 'LabeledStatement',
+ label: expr as ESTree.Identifier,
+ body
+ });
+}
+
+/**
+ * Parses either async ident, async function or async arrow in
+ * statement position
+ *
+ * @param parser Parser object
+ * @param context Context masks
+ * @param labels
+ * @param allowFuncDecl Allow / disallow func statement
+ * @param start Start position of current AST node
+ * @param start
+ * @param line
+ * @param column
+ */
+
+export function parseAsyncArrowOrAsyncFunctionDeclaration(
+ parser: ParserState,
+ context: Context,
+ scope: ScopeState | undefined,
+ origin: Origin,
+ labels: ESTree.Labels,
+ allowFuncDecl: 0 | 1,
+ start: number,
+ line: number,
+ column: number
+): ESTree.ExpressionStatement | ESTree.LabeledStatement | ESTree.FunctionDeclaration {
+ // AsyncArrowFunction[In, Yield, Await]:
+ // async[no LineTerminator here]AsyncArrowBindingIdentifier[?Yield][no LineTerminator here]=>AsyncConciseBody[?In]
+ // CoverCallExpressionAndAsyncArrowHead[?Yield, ?Await][no LineTerminator here]=>AsyncConciseBody[?In]
+ //
+ // AsyncArrowBindingIdentifier[Yield]:
+ // BindingIdentifier[?Yield, +Await]
+ //
+ // CoverCallExpressionAndAsyncArrowHead[Yield, Await]:
+ // MemberExpression[?Yield, ?Await]Arguments[?Yield, ?Await]
+ //
+ // AsyncFunctionDeclaration[Yield, Await, Default]:
+ // async[no LineTerminator here]functionBindingIdentifier[?Yield, ?Await](FormalParameters[~Yield, +Await]){AsyncFunctionBody}
+ // [+Default]async[no LineTerminator here]function(FormalParameters[~Yield, +Await]){AsyncFunctionBody}
+ //
+ // AsyncFunctionBody:
+ // FunctionBody[~Yield, +Await]
+
+ const { token, tokenValue } = parser;
+
+ let expr: ESTree.Expression = parseIdentifier(parser, context, 0);
+
+ if (parser.token === Token.Colon) {
+ return parseLabelledStatement(
+ parser,
+ context,
+ scope,
+ origin,
+ labels,
+ tokenValue,
+ expr,
+ token,
+ 1,
+ start,
+ line,
+ column
+ );
+ }
+
+ const asyncNewLine = parser.flags & Flags.NewLine;
+
+ if (!asyncNewLine) {
+ // async function ...
+ if (parser.token === Token.FunctionKeyword) {
+ if (!allowFuncDecl) report(parser, Errors.AsyncFunctionInSingleStatementContext);
+
+ return parseFunctionDeclaration(
+ parser,
+ context,
+ scope,
+ origin,
+ 1,
+ HoistedFunctionFlags.None,
+ 1,
+ start,
+ line,
+ column
+ );
+ }
+
+ // async Identifier => ...
+ if ((parser.token & Token.IsIdentifier) === Token.IsIdentifier) {
+ /** ArrowFunction[In, Yield, Await]:
+ * ArrowParameters[?Yield, ?Await][no LineTerminator here]=>ConciseBody[?In]
+ */
+ expr = parseAsyncArrowAfterIdent(parser, context, /* assignable */ 1, start, line, column);
+ if (parser.token === Token.Comma) expr = parseSequenceExpression(parser, context, 0, start, line, column, expr);
+
+ /**
+ * ExpressionStatement[Yield, Await]:
+ * [lookahead ∉ { {, function, async [no LineTerminator here] function, class, let [ }]Expression[+In, ?Yield, ?Await]
+ */
+ return parseExpressionStatement(parser, context, expr, start, line, column);
+ }
+ }
+
+ /** ArrowFunction[In, Yield, Await]:
+ * ArrowParameters[?Yield, ?Await][no LineTerminator here]=>ConciseBody[?In]
+ */
+ if (parser.token === Token.LeftParen) {
+ expr = parseAsyncArrowOrCallExpression(
+ parser,
+ context,
+ expr,
+ 1,
+ BindingKind.ArgumentList,
+ Origin.None,
+ asyncNewLine,
+ start,
+ line,
+ column
+ );
+ } else {
+ if (parser.token === Token.Arrow) {
+ classifyIdentifier(parser, context, token, /* isArrow */ 1);
+ expr = parseArrowFromIdentifier(parser, context, parser.tokenValue, expr, 0, 1, 0, start, line, column);
+ }
+
+ parser.assignable = AssignmentKind.Assignable;
+ }
+
+ /** MemberExpression :
+ * 1. PrimaryExpression
+ * 2. MemberExpression [ AssignmentExpression ]
+ * 3. MemberExpression . IdentifierName
+ * 4. MemberExpression TemplateLiteral
+ *
+ * CallExpression :
+ * 1. MemberExpression Arguments
+ * 2. CallExpression ImportCall
+ * 3. CallExpression Arguments
+ * 4. CallExpression [ AssignmentExpression ]
+ * 5. CallExpression . IdentifierName
+ * 6. CallExpression TemplateLiteral
+ *
+ * UpdateExpression ::
+ * ('++' | '--')? LeftHandSideExpression
+ */
+
+ expr = parseMemberOrUpdateExpression(parser, context, expr, 0, 0, start, line, column);
+ /** Sequence expression
+ *
+ * Note: The comma operator leads to a sequence expression which is not equivalent
+ * to the ES Expression, but it's part of the ESTree specs:
+ *
+ * https://github.com/estree/estree/blob/master/es5.md#sequenceexpression
+ *
+ */
+ if (parser.token === Token.Comma) expr = parseSequenceExpression(parser, context, 0, start, line, column, expr);
+
+ /** AssignmentExpression :
+ *
+ * 1. ConditionalExpression
+ * 2. LeftHandSideExpression = AssignmentExpression
+ *
+ */
+ expr = parseAssignmentExpression(parser, context, 0, 0, start, line, column, expr as ESTree.ArgumentExpression);
+
+ parser.assignable = AssignmentKind.Assignable;
+
+ /**
+ * ExpressionStatement[Yield, Await]:
+ * [lookahead ∉ { {, function, async [no LineTerminator here] function, class, let [ }]Expression[+In, ?Yield, ?Await]
+ */
+ return parseExpressionStatement(parser, context, expr, start, line, column);
+}
+
+/**
+ * Parse directive node
+ *
+ * @see [Link](https://tc39.github.io/ecma262/#sec-directive-prologues-and-the-use-strict-directive)
+ *
+ * @param parser Parser object
+ * @param context Context masks
+ * @param expression AST expression node
+ * @param token
+ * @param start Start pos of node
+ * @param line
+ * @param column
+ */
+
+export function parseDirective(
+ parser: ParserState,
+ context: Context,
+ expression: ESTree.ArgumentExpression | ESTree.SequenceExpression | ESTree.Expression,
+ token: Token,
+ start: number,
+ line: number,
+ column: number
+): ESTree.ExpressionStatement {
+ if (token !== Token.Semicolon) {
+ parser.assignable = AssignmentKind.CannotAssign;
+
+ expression = parseMemberOrUpdateExpression(parser, context, expression, 0, 0, start, line, column);
+
+ if (parser.token !== Token.Semicolon) {
+ expression = parseAssignmentExpression(parser, context, 0, 0, start, line, column, expression);
+
+ if (parser.token === Token.Comma) {
+ expression = parseSequenceExpression(parser, context, 0, start, line, column, expression);
+ }
+ }
+
+ matchOrInsertSemicolon(parser, context | Context.AllowRegExp);
+ }
+
+ return context & Context.OptionsDirectives && expression.type === 'Literal' && typeof expression.value === 'string'
+ ? finishNode(parser, context, start, line, column, {
+ type: 'ExpressionStatement',
+ expression,
+ // OptionsRaw is implicitly turned on by OptionsDirectives.
+ directive: (expression.raw as string).slice(1, -1)
+ })
+ : finishNode(parser, context, start, line, column, {
+ type: 'ExpressionStatement',
+ expression
+ });
+}
+
+/**
+ * Parses empty statement
+ *
+ * @param parser Parser object
+ * @param context Context masks
+ * @param start Start pos of node
+ * @param line
+ * @param column
+ */
+
+export function parseEmptyStatement(
+ parser: ParserState,
+ context: Context,
+ start: number,
+ line: number,
+ column: number
+): ESTree.EmptyStatement {
+ nextToken(parser, context | Context.AllowRegExp);
+ return finishNode(parser, context, start, line, column, {
+ type: 'EmptyStatement'
+ });
+}
+
+/**
+ * Parses throw statement
+ *
+ * @see [Link](https://tc39.github.io/ecma262/#prod-ThrowStatement)
+ *
+ * @param parser Parser object
+ * @param context Context masks
+ * @param start Start pos of node
+* @param line
+* @param column
+
+ */
+export function parseThrowStatement(
+ parser: ParserState,
+ context: Context,
+ start: number,
+ line: number,
+ column: number
+): ESTree.ThrowStatement {
+ // ThrowStatement ::
+ // 'throw' Expression ';'
+ nextToken(parser, context | Context.AllowRegExp);
+ if (parser.flags & Flags.NewLine) report(parser, Errors.NewlineAfterThrow);
+ const argument: ESTree.Expression = parseExpressions(
+ parser,
+ context,
+ 0,
+ 1,
+ parser.tokenPos,
+ parser.linePos,
+ parser.colPos
+ );
+ matchOrInsertSemicolon(parser, context | Context.AllowRegExp);
+ return finishNode(parser, context, start, line, column, {
+ type: 'ThrowStatement',
+ argument
+ });
+}
+
+/**
+ * Parses an if statement with an optional else block
+ *
+ * @see [Link](https://tc39.github.io/ecma262/#sec-if-statement)
+ *
+ * @param parser Parser object
+ * @param context Context masks
+ * @param scope Scope instance
+ * @param start Start pos of node
+* @param line
+* @param column
+
+ */
+export function parseIfStatement(
+ parser: ParserState,
+ context: Context,
+ scope: ScopeState | undefined,
+ labels: ESTree.Labels,
+ start: number,
+ line: number,
+ column: number
+): ESTree.IfStatement {
+ // IfStatement ::
+ // 'if' '(' Expression ')' Statement ('else' Statement)?
+ nextToken(parser, context);
+ consume(parser, context | Context.AllowRegExp, Token.LeftParen);
+ parser.assignable = AssignmentKind.Assignable;
+ const test = parseExpressions(parser, context, 0, 1, parser.tokenPos, parser.line, parser.colPos);
+ consume(parser, context | Context.AllowRegExp, Token.RightParen);
+ const consequent = parseConsequentOrAlternative(
+ parser,
+ context,
+ scope,
+ labels,
+ parser.tokenPos,
+ parser.linePos,
+ parser.colPos
+ );
+ let alternate: ESTree.Statement | null = null;
+ if (parser.token === Token.ElseKeyword) {
+ nextToken(parser, context | Context.AllowRegExp);
+ alternate = parseConsequentOrAlternative(
+ parser,
+ context,
+ scope,
+ labels,
+ parser.tokenPos,
+ parser.linePos,
+ parser.colPos
+ );
+ }
+
+ return finishNode(parser, context, start, line, column, {
+ type: 'IfStatement',
+ test,
+ consequent,
+ alternate
+ });
+}
+
+/**
+ * Parse either consequent or alternate.
+ *
+ * @param parser Parser object
+ * @param context Context masks
+ * @param start Start pos of node
+ * @param line
+ * @param column
+ */
+export function parseConsequentOrAlternative(
+ parser: ParserState,
+ context: Context,
+ scope: ScopeState | undefined,
+ labels: ESTree.Labels,
+ start: number,
+ line: number,
+ column: number
+): ESTree.Statement | ESTree.FunctionDeclaration {
+ return context & Context.Strict ||
+ // Disallow if web compatibility is off
+ (context & Context.OptionsWebCompat) < 1 ||
+ parser.token !== Token.FunctionKeyword
+ ? parseStatement(
+ parser,
+ context,
+ scope,
+ Origin.None,
+ { $: labels },
+ 0,
+ parser.tokenPos,
+ parser.linePos,
+ parser.colPos
+ )
+ : parseFunctionDeclaration(
+ parser,
+ context,
+ addChildScope(scope, ScopeKind.Block),
+ Origin.None,
+ 0,
+ HoistedFunctionFlags.None,
+ 0,
+ start,
+ line,
+ column
+ );
+}
+
+/**
+ * Parses switch statement
+ *
+ * @see [Link](https://tc39.github.io/ecma262/#prod-SwitchStatement)
+ *
+ * @param parser Parser object
+ * @param context Context masks
+ * @param start Start pos of node
+ * @param line
+ * @param column
+ */
+export function parseSwitchStatement(
+ parser: ParserState,
+ context: Context,
+ scope: ScopeState | undefined,
+ labels: ESTree.Labels,
+ start: number,
+ line: number,
+ column: number
+): ESTree.SwitchStatement {
+ // SwitchStatement ::
+ // 'switch' '(' Expression ')' '{' CaseClause* '}'
+ // CaseClause ::
+ // 'case' Expression ':' StatementList
+ // 'default' ':' StatementList
+ nextToken(parser, context);
+ consume(parser, context | Context.AllowRegExp, Token.LeftParen);
+ const discriminant = parseExpressions(parser, context, 0, 1, parser.tokenPos, parser.linePos, parser.colPos);
+ consume(parser, context, Token.RightParen);
+ consume(parser, context, Token.LeftBrace);
+ const cases: ESTree.SwitchCase[] = [];
+ let seenDefault: 0 | 1 = 0;
+ if (scope) scope = addChildScope(scope, ScopeKind.SwitchStatement);
+ while (parser.token !== Token.RightBrace) {
+ const { tokenPos, linePos, colPos } = parser;
+ let test: ESTree.Expression | null = null;
+ const consequent: ESTree.Statement[] = [];
+ if (consumeOpt(parser, context | Context.AllowRegExp, Token.CaseKeyword)) {
+ test = parseExpressions(parser, context, 0, 1, parser.tokenPos, parser.linePos, parser.colPos);
+ } else {
+ consume(parser, context | Context.AllowRegExp, Token.DefaultKeyword);
+ if (seenDefault) report(parser, Errors.MultipleDefaultsInSwitch);
+ seenDefault = 1;
+ }
+ consume(parser, context | Context.AllowRegExp, Token.Colon);
+ while (
+ parser.token !== Token.CaseKeyword &&
+ parser.token !== Token.RightBrace &&
+ parser.token !== Token.DefaultKeyword
+ ) {
+ consequent.push(
+ parseStatementListItem(parser, context | Context.InSwitch, scope, Origin.BlockStatement, {
+ $: labels
+ }) as ESTree.Statement
+ );
+ }
+
+ cases.push(
+ finishNode(parser, context, tokenPos, linePos, colPos, {
+ type: 'SwitchCase',
+ test,
+ consequent
+ })
+ );
+ }
+
+ consume(parser, context | Context.AllowRegExp, Token.RightBrace);
+ return finishNode(parser, context, start, line, column, {
+ type: 'SwitchStatement',
+ discriminant,
+ cases
+ });
+}
+
+/**
+ * Parses while statement
+ *
+ * @see [Link](https://tc39.github.io/ecma262/#prod-grammar-notation-WhileStatement)
+ *
+ * @param parser Parser object
+ * @param context Context masks
+ * @param start
+ * @param start Start pos of node
+ * @param line
+ * @param column
+ */
+export function parseWhileStatement(
+ parser: ParserState,
+ context: Context,
+ scope: ScopeState | undefined,
+ labels: ESTree.Labels,
+ start: number,
+ line: number,
+ column: number
+): ESTree.WhileStatement {
+ // WhileStatement ::
+ // 'while' '(' Expression ')' Statement
+ nextToken(parser, context);
+ consume(parser, context | Context.AllowRegExp, Token.LeftParen);
+ const test = parseExpressions(parser, context, 0, 1, parser.tokenPos, parser.linePos, parser.colPos);
+ consume(parser, context | Context.AllowRegExp, Token.RightParen);
+ const body = parseIterationStatementBody(parser, context, scope, labels);
+ return finishNode(parser, context, start, line, column, {
+ type: 'WhileStatement',
+ test,
+ body
+ });
+}
+
+/**
+ * Parses iteration statement body
+ *
+ * @see [Link](https://tc39.es/ecma262/#sec-iteration-statements)
+ *
+ * @param parser Parser object
+ * @param context Context masks
+ * @param start Start pos of node
+ * @param line
+ * @param column
+ */
+export function parseIterationStatementBody(
+ parser: ParserState,
+ context: Context,
+ scope: ScopeState | undefined,
+ labels: ESTree.Labels
+): ESTree.Statement {
+ return parseStatement(
+ parser,
+ ((context | Context.DisallowIn) ^ Context.DisallowIn) | Context.InIteration,
+ scope,
+ Origin.None,
+ { loop: 1, $: labels },
+ 0,
+ parser.tokenPos,
+ parser.linePos,
+ parser.colPos
+ );
+}
+
+/**
+ * Parses the continue statement production
+ *
+ * @see [Link](https://tc39.github.io/ecma262/#prod-ContinueStatement)
+ *
+ * @param parser Parser object
+ * @param context Context masks
+ */
+export function parseContinueStatement(
+ parser: ParserState,
+ context: Context,
+ labels: ESTree.Labels,
+ start: number,
+ line: number,
+ column: number
+): ESTree.ContinueStatement {
+ // ContinueStatement ::
+ // 'continue' Identifier? ';'
+ if ((context & Context.InIteration) < 1) report(parser, Errors.IllegalContinue);
+ nextToken(parser, context);
+ let label: ESTree.Identifier | undefined | null = null;
+ if ((parser.flags & Flags.NewLine) < 1 && parser.token & Token.IsIdentifier) {
+ const { tokenValue } = parser;
+ label = parseIdentifier(parser, context | Context.AllowRegExp, 0);
+ if (!isValidLabel(parser, labels, tokenValue, /* requireIterationStatement */ 1))
+ report(parser, Errors.UnknownLabel, tokenValue);
+ }
+ matchOrInsertSemicolon(parser, context | Context.AllowRegExp);
+ return finishNode(parser, context, start, line, column, {
+ type: 'ContinueStatement',
+ label
+ });
+}
+
+/**
+ * Parses the break statement production
+ *
+ * @see [Link](https://tc39.github.io/ecma262/#prod-BreakStatement)
+ *
+ * @param parser Parser object
+ * @param context Context masks
+ * @param start Start pos of node
+ * @param line
+ * @param column
+ */
+export function parseBreakStatement(
+ parser: ParserState,
+ context: Context,
+ labels: ESTree.Labels,
+ start: number,
+ line: number,
+ column: number
+): ESTree.BreakStatement {
+ // BreakStatement ::
+ // 'break' Identifier? ';'
+ nextToken(parser, context | Context.AllowRegExp);
+ let label: ESTree.Identifier | undefined | null = null;
+ if ((parser.flags & Flags.NewLine) < 1 && parser.token & Token.IsIdentifier) {
+ const { tokenValue } = parser;
+ label = parseIdentifier(parser, context | Context.AllowRegExp, 0);
+ if (!isValidLabel(parser, labels, tokenValue, /* requireIterationStatement */ 0))
+ report(parser, Errors.UnknownLabel, tokenValue);
+ } else if ((context & (Context.InSwitch | Context.InIteration)) < 1) {
+ report(parser, Errors.IllegalBreak);
+ }
+
+ matchOrInsertSemicolon(parser, context | Context.AllowRegExp);
+ return finishNode(parser, context, start, line, column, {
+ type: 'BreakStatement',
+ label
+ });
+}
+
+/**
+ * Parses with statement
+ *
+ * @see [Link](https://tc39.github.io/ecma262/#prod-WithStatement)
+ *
+ * @param parser Parser object
+ * @param context Context masks
+ * @param scope Scope instance
+ * @param start Start pos of node
+ * @param line
+ * @param column
+ */
+export function parseWithStatement(
+ parser: ParserState,
+ context: Context,
+ scope: ScopeState | undefined,
+ labels: ESTree.Labels,
+ start: number,
+ line: number,
+ column: number
+): ESTree.WithStatement {
+ // WithStatement ::
+ // 'with' '(' Expression ')' Statement
+
+ nextToken(parser, context);
+
+ if (context & Context.Strict) report(parser, Errors.StrictWith);
+
+ consume(parser, context | Context.AllowRegExp, Token.LeftParen);
+ const object = parseExpressions(parser, context, 0, 1, parser.tokenPos, parser.linePos, parser.colPos);
+ consume(parser, context | Context.AllowRegExp, Token.RightParen);
+ const body = parseStatement(
+ parser,
+ context,
+ scope,
+ Origin.BlockStatement,
+ labels,
+ 0,
+ parser.tokenPos,
+ parser.linePos,
+ parser.colPos
+ );
+ return finishNode(parser, context, start, line, column, {
+ type: 'WithStatement',
+ object,
+ body
+ });
+}
+
+/**
+ * Parses the debugger statement production
+ *
+ * @see [Link](https://tc39.github.io/ecma262/#prod-DebuggerStatement)
+ *
+ * @param parser Parser object
+ * @param context Context masks
+ * @param start Start pos of node
+ * @param line
+ * @param column
+ */
+export function parseDebuggerStatement(
+ parser: ParserState,
+ context: Context,
+ start: number,
+ line: number,
+ column: number
+): ESTree.DebuggerStatement {
+ // DebuggerStatement ::
+ // 'debugger' ';'
+ nextToken(parser, context | Context.AllowRegExp);
+ matchOrInsertSemicolon(parser, context | Context.AllowRegExp);
+ return finishNode(parser, context, start, line, column, {
+ type: 'DebuggerStatement'
+ });
+}
+
+/**
+ * Parses try statement
+ *
+ * @see [Link](https://tc39.github.io/ecma262/#prod-TryStatement)
+ *
+ * @param parser Parser object
+ * @param context Context masks
+ * @param scope Scope instance
+ * @param start Start pos of node
+ * @param line
+ * @param column
+ */
+export function parseTryStatement(
+ parser: ParserState,
+ context: Context,
+ scope: ScopeState | undefined,
+ labels: ESTree.Labels,
+ start: number,
+ line: number,
+ column: number
+): ESTree.TryStatement {
+ // TryStatement ::
+ // 'try' Block Catch
+ // 'try' Block Finally
+ // 'try' Block Catch Finally
+ //
+ // Catch ::
+ // 'catch' '(' Identifier ')' Block
+ //
+ // Finally ::
+ // 'finally' Block
+
+ nextToken(parser, context | Context.AllowRegExp);
+
+ const firstScope = scope ? addChildScope(scope, ScopeKind.TryStatement) : void 0;
+
+ const block = parseBlock(parser, context, firstScope, { $: labels }, parser.tokenPos, parser.linePos, parser.colPos);
+ const { tokenPos, linePos, colPos } = parser;
+ const handler = consumeOpt(parser, context | Context.AllowRegExp, Token.CatchKeyword)
+ ? parseCatchBlock(parser, context, scope, labels, tokenPos, linePos, colPos)
+ : null;
+
+ let finalizer: ESTree.BlockStatement | null = null;
+
+ if (parser.token === Token.FinallyKeyword) {
+ nextToken(parser, context | Context.AllowRegExp);
+ const finalizerScope = firstScope ? addChildScope(scope, ScopeKind.CatchStatement) : void 0;
+ finalizer = parseBlock(
+ parser,
+ context,
+ finalizerScope,
+ { $: labels },
+ parser.tokenPos,
+ parser.linePos,
+ parser.colPos
+ );
+ }
+
+ if (!handler && !finalizer) {
+ report(parser, Errors.NoCatchOrFinally);
+ }
+
+ return finishNode(parser, context, start, line, column, {
+ type: 'TryStatement',
+ block,
+ handler,
+ finalizer
+ });
+}
+
+/**
+ * Parses catch block
+ *
+ * @see [Link](https://tc39.github.io/ecma262/#prod-Catch)
+ *
+ * @param parser Parser object
+ * @param context Context masks
+ * @param scope Scope instance
+ * @param start Start pos of node
+ * @param line
+ * @param column
+ */
+export function parseCatchBlock(
+ parser: ParserState,
+ context: Context,
+ scope: ScopeState | undefined,
+ labels: ESTree.Labels,
+ start: number,
+ line: number,
+ column: number
+): ESTree.CatchClause {
+ let param: ESTree.BindingPattern | ESTree.Identifier | null = null;
+ let additionalScope: ScopeState | undefined = scope;
+
+ if (consumeOpt(parser, context, Token.LeftParen)) {
+ /*
+ * Create a lexical scope around the whole catch clause,
+ * including the head.
+ */
+ if (scope) scope = addChildScope(scope, ScopeKind.CatchStatement);
+
+ param = parseBindingPattern(
+ parser,
+ context,
+ scope,
+ (parser.token & Token.IsPatternStart) === Token.IsPatternStart
+ ? BindingKind.CatchPattern
+ : BindingKind.CatchIdentifier,
+ Origin.None,
+ parser.tokenPos,
+ parser.linePos,
+ parser.colPos
+ );
+
+ if (parser.token === Token.Comma) {
+ report(parser, Errors.InvalidCatchParams);
+ } else if (parser.token === Token.Assign) {
+ report(parser, Errors.InvalidCatchParamDefault);
+ }
+
+ consume(parser, context | Context.AllowRegExp, Token.RightParen);
+ // ES 13.15.7 CatchClauseEvaluation
+ //
+ // Step 8 means that the body of a catch block always has an additional
+ // lexical scope.
+ if (scope) additionalScope = addChildScope(scope, ScopeKind.CatchBlock);
+ }
+
+ const body = parseBlock(
+ parser,
+ context,
+ additionalScope,
+ { $: labels },
+ parser.tokenPos,
+ parser.linePos,
+ parser.colPos
+ );
+
+ return finishNode(parser, context, start, line, column, {
+ type: 'CatchClause',
+ param,
+ body
+ });
+}
+
+/**
+ * Parses do while statement
+ *
+ * @param parser Parser object
+ * @param context Context masks
+ * @param scope Scope instance
+ * @param start Start pos of node
+ * @param line
+ * @param column
+ */
+export function parseDoWhileStatement(
+ parser: ParserState,
+ context: Context,
+ scope: ScopeState | undefined,
+ labels: ESTree.Labels,
+ start: number,
+ line: number,
+ column: number
+): ESTree.DoWhileStatement {
+ // DoStatement ::
+ // 'do Statement while ( Expression ) ;'
+
+ nextToken(parser, context | Context.AllowRegExp);
+ const body = parseIterationStatementBody(parser, context, scope, labels);
+ consume(parser, context, Token.WhileKeyword);
+ consume(parser, context | Context.AllowRegExp, Token.LeftParen);
+ const test = parseExpressions(parser, context, 0, 1, parser.tokenPos, parser.linePos, parser.colPos);
+ consume(parser, context | Context.AllowRegExp, Token.RightParen);
+ // ECMA-262, section 11.9
+ // The previous token is ) and the inserted semicolon would then be parsed as the terminating semicolon of a do-while statement (13.7.2).
+ // This cannot be implemented in matchOrInsertSemicolon() because it doesn't know
+ // this RightRaren is the end of a do-while statement.
+ consumeOpt(parser, context, Token.Semicolon);
+ return finishNode(parser, context, start, line, column, {
+ type: 'DoWhileStatement',
+ body,
+ test
+ });
+}
+
+/**
+ * Because we are not doing any backtracking - this parses `let` as an identifier
+ * or a variable declaration statement.
+ *
+ * @see [Link](https://tc39.github.io/ecma262/#sec-declarations-and-the-variable-statement)
+ *
+ * @param parser Parser object
+ * @param context Context masks
+ * @param scope Scope object
+ * @param origin Binding origin
+ * @param start Start pos of node
+ * @param start Start pos of node
+ * @param line
+ * @param column
+ */
+export function parseLetIdentOrVarDeclarationStatement(
+ parser: ParserState,
+ context: Context,
+ scope: ScopeState | undefined,
+ origin: Origin,
+ start: number,
+ line: number,
+ column: number
+): ESTree.VariableDeclaration | ESTree.LabeledStatement | ESTree.ExpressionStatement {
+ const { token, tokenValue } = parser;
+ let expr: ESTree.Identifier | ESTree.Expression = parseIdentifier(parser, context, 0);
+
+ if (parser.token & (Token.IsIdentifier | Token.IsPatternStart)) {
+ /* VariableDeclarations ::
+ * ('let') (Identifier ('=' AssignmentExpression)?)+[',']
+ */
+
+ const declarations = parseVariableDeclarationList(parser, context, scope, BindingKind.Let, Origin.None);
+
+ matchOrInsertSemicolon(parser, context | Context.AllowRegExp);
+
+ return finishNode(parser, context, start, line, column, {
+ type: 'VariableDeclaration',
+ kind: 'let',
+ declarations
+ });
+ }
+ // 'Let' as identifier
+ parser.assignable = AssignmentKind.Assignable;
+
+ if (context & Context.Strict) report(parser, Errors.UnexpectedLetStrictReserved);
+
+ /** LabelledStatement[Yield, Await, Return]:
+ *
+ * ExpressionStatement | LabelledStatement ::
+ * Expression ';'
+ * Identifier ':' Statement
+ *
+ * ExpressionStatement[Yield] :
+ * [lookahead notin {{, function, class, let [}] Expression[In, ?Yield] ;
+ */
+
+ if (parser.token === Token.Colon) {
+ return parseLabelledStatement(parser, context, scope, origin, {}, tokenValue, expr, token, 0, start, line, column);
+ }
+
+ /**
+ * ArrowFunction :
+ * ArrowParameters => ConciseBody
+ *
+ * ConciseBody :
+ * [lookahead not {] AssignmentExpression
+ * { FunctionBody }
+ *
+ */
+ if (parser.token === Token.Arrow) {
+ let scope: ScopeState | undefined = void 0;
+
+ if (context & Context.OptionsLexical) scope = createArrowHeadParsingScope(parser, context, tokenValue);
+
+ parser.flags = (parser.flags | Flags.SimpleParameterList) ^ Flags.SimpleParameterList;
+
+ expr = parseArrowFunctionExpression(parser, context, scope, [expr], /* isAsync */ 0, start, line, column);
+ } else {
+ /**
+ * UpdateExpression ::
+ * ('++' | '--')? LeftHandSideExpression
+ *
+ * MemberExpression ::
+ * (PrimaryExpression | FunctionLiteral | ClassLiteral)
+ * ('[' Expression ']' | '.' Identifier | Arguments | TemplateLiteral)*
+ *
+ * CallExpression ::
+ * (SuperCall | ImportCall)
+ * ('[' Expression ']' | '.' Identifier | Arguments | TemplateLiteral)*
+ *
+ * LeftHandSideExpression ::
+ * (NewExpression | MemberExpression) ...
+ */
+
+ expr = parseMemberOrUpdateExpression(parser, context, expr, 0, 0, start, line, column);
+
+ /**
+ * AssignmentExpression :
+ * 1. ConditionalExpression
+ * 2. LeftHandSideExpression = AssignmentExpression
+ *
+ */
+ expr = parseAssignmentExpression(parser, context, 0, 0, start, line, column, expr as ESTree.ArgumentExpression);
+ }
+
+ /** Sequence expression
+ */
+ if (parser.token === Token.Comma) {
+ expr = parseSequenceExpression(parser, context, 0, start, line, column, expr);
+ }
+
+ /**
+ * ExpressionStatement[Yield, Await]:
+ * [lookahead ∉ { {, function, async [no LineTerminator here] function, class, let [ }]Expression[+In, ?Yield, ?Await]
+ */
+ return parseExpressionStatement(parser, context, expr, start, line, column);
+}
+
+/**
+ * Parses a `const` or `let` lexical declaration statement
+ *
+ * @param parser Parser object
+ * @param context Context masks
+ * @param type Binding kind
+ * @param origin Binding origin
+ * @param type Binding kind
+ * @param start Start pos of node
+ * @param start Start pos of node
+ * @param line
+ * @param column
+ */
+function parseLexicalDeclaration(
+ parser: ParserState,
+ context: Context,
+ scope: ScopeState | undefined,
+ kind: BindingKind,
+ origin: Origin,
+ start: number,
+ line: number,
+ column: number
+): ESTree.VariableDeclaration {
+ // BindingList ::
+ // LexicalBinding
+ // BindingIdentifier
+ // BindingPattern
+ nextToken(parser, context);
+
+ const declarations = parseVariableDeclarationList(parser, context, scope, kind, origin);
+
+ matchOrInsertSemicolon(parser, context | Context.AllowRegExp);
+
+ return finishNode(parser, context, start, line, column, {
+ type: 'VariableDeclaration',
+ kind: kind & BindingKind.Let ? 'let' : 'const',
+ declarations
+ });
+}
+
+/**
+ * Parses a variable declaration statement
+ *
+ * @see [Link](https://tc39.github.io/ecma262/#prod-VariableStatement)
+ *
+ * @param parser Parser object
+ * @param context Context masks
+ * @param scope Scope object
+ * @param origin Binding origin
+ * @param start Start pos of node
+ * @param start Start pos of node
+ * @param line
+ * @param column
+ */
+export function parseVariableStatement(
+ parser: ParserState,
+ context: Context,
+ scope: ScopeState | undefined,
+ origin: Origin,
+ start: number,
+ line: number,
+ column: number
+): ESTree.VariableDeclaration {
+ // VariableDeclarations ::
+ // ('var') (Identifier ('=' AssignmentExpression)?)+[',']
+ //
+ nextToken(parser, context);
+ const declarations = parseVariableDeclarationList(parser, context, scope, BindingKind.Variable, origin);
+
+ matchOrInsertSemicolon(parser, context | Context.AllowRegExp);
+ return finishNode(parser, context, start, line, column, {
+ type: 'VariableDeclaration',
+ kind: 'var',
+ declarations
+ });
+}
+
+/**
+ * Parses variable declaration list
+ *
+ * @see [Link](https://tc39.github.io/ecma262/#prod-VariableDeclarationList)
+ *
+ * @param parser Parser object
+ * @param context Context masks
+ * @param type Binding kind
+ * @param origin Binding origin
+ */
+export function parseVariableDeclarationList(
+ parser: ParserState,
+ context: Context,
+ scope: ScopeState | undefined,
+ kind: BindingKind,
+ origin: Origin
+): ESTree.VariableDeclarator[] {
+ let bindingCount = 1;
+ const list: ESTree.VariableDeclarator[] = [parseVariableDeclaration(parser, context, scope, kind, origin)];
+ while (consumeOpt(parser, context, Token.Comma)) {
+ bindingCount++;
+ list.push(parseVariableDeclaration(parser, context, scope, kind, origin));
+ }
+
+ if (bindingCount > 1 && origin & Origin.ForStatement && parser.token & Token.IsInOrOf) {
+ report(parser, Errors.ForInOfLoopMultiBindings, KeywordDescTable[parser.token & Token.Type]);
+ }
+ return list;
+}
+
+/**
+ * Parses variable declaration
+ *
+ * @see [Link](https://tc39.github.io/ecma262/#prod-VariableDeclaration)
+ *
+ * @param parser Parser object
+ * @param context Context masks
+ * @param start Start pos of node
+ * @param start Start pos of node
+ * @param line
+ * @param column
+ */
+function parseVariableDeclaration(
+ parser: ParserState,
+ context: Context,
+ scope: ScopeState | undefined,
+ kind: BindingKind,
+ origin: Origin
+): ESTree.VariableDeclarator {
+ // VariableDeclaration :
+ // BindingIdentifier Initializeropt
+ // BindingPattern Initializer
+ //
+ // VariableDeclarationNoIn :
+ // BindingIdentifier InitializerNoInopt
+ // BindingPattern InitializerNoIn
+
+ const { token, tokenPos, linePos, colPos } = parser;
+
+ let init: ESTree.Expression | ESTree.BindingPattern | ESTree.Identifier | null = null;
+
+ const id = parseBindingPattern(parser, context, scope, kind, origin, tokenPos, linePos, colPos);
+
+ if (parser.token === Token.Assign) {
+ nextToken(parser, context | Context.AllowRegExp);
+ init = parseExpression(parser, context, 1, 0, 0, parser.tokenPos, parser.linePos, parser.colPos);
+ if (origin & Origin.ForStatement || (token & Token.IsPatternStart) < 1) {
+ // Lexical declarations in for-in / for-of loops can't be initialized
+
+ if (
+ parser.token === Token.OfKeyword ||
+ (parser.token === Token.InKeyword &&
+ (token & Token.IsPatternStart || (kind & BindingKind.Variable) < 1 || context & Context.Strict))
+ ) {
+ reportMessageAt(
+ tokenPos,
+ parser.line,
+ parser.index - 3,
+ Errors.ForInOfLoopInitializer,
+ parser.token === Token.OfKeyword ? 'of' : 'in'
+ );
+ }
+ }
+ // Normal const declarations, and const declarations in for(;;) heads, must be initialized.
+ } else if (
+ (kind & BindingKind.Const || (token & Token.IsPatternStart) > 0) &&
+ (parser.token & Token.IsInOrOf) !== Token.IsInOrOf
+ ) {
+ report(parser, Errors.DeclarationMissingInitializer, kind & BindingKind.Const ? 'const' : 'destructuring');
+ }
+
+ return finishNode(parser, context, tokenPos, linePos, colPos, {
+ type: 'VariableDeclarator',
+ id,
+ init
+ });
+}
+
+/**
+ * Parses either For, ForIn or ForOf statement
+ *
+ * @see [Link](https://tc39.github.io/ecma262/#sec-for-statement)
+ * @see [Link](https://tc39.github.io/ecma262/#sec-for-in-and-for-of-statements)
+ *
+ * @param parser Parser object
+ * @param context Context masks
+ * @param start Start pos of node
+ * @param line
+ * @param column
+
+ */
+export function parseForStatement(
+ parser: ParserState,
+ context: Context,
+ scope: ScopeState | undefined,
+ labels: ESTree.Labels,
+ start: number,
+ line: number,
+ column: number
+): ESTree.ForStatement | ESTree.ForInStatement | ESTree.ForOfStatement {
+ nextToken(parser, context);
+
+ const forAwait = (context & Context.InAwaitContext) > 0 && consumeOpt(parser, context, Token.AwaitKeyword);
+
+ consume(parser, context | Context.AllowRegExp, Token.LeftParen);
+
+ if (scope) scope = addChildScope(scope, ScopeKind.ForStatement);
+
+ let test: ESTree.Expression | null = null;
+ let update: ESTree.Expression | null = null;
+ let destructible: AssignmentKind | DestructuringKind = 0;
+ let init = null;
+ let isVarDecl =
+ parser.token === Token.VarKeyword || parser.token === Token.LetKeyword || parser.token === Token.ConstKeyword;
+ let right;
+
+ const { token, tokenPos, linePos, colPos } = parser;
+
+ if (isVarDecl) {
+ if (token === Token.LetKeyword) {
+ init = parseIdentifier(parser, context, 0);
+ if (parser.token & (Token.IsIdentifier | Token.IsPatternStart)) {
+ if (parser.token === Token.InKeyword) {
+ if (context & Context.Strict) report(parser, Errors.DisallowedLetInStrict);
+ } else {
+ init = finishNode(parser, context, tokenPos, linePos, colPos, {
+ type: 'VariableDeclaration',
+ kind: 'let',
+ declarations: parseVariableDeclarationList(
+ parser,
+ context | Context.DisallowIn,
+ scope,
+ BindingKind.Let,
+ Origin.ForStatement
+ )
+ });
+ }
+
+ parser.assignable = AssignmentKind.Assignable;
+ } else if (context & Context.Strict) {
+ report(parser, Errors.DisallowedLetInStrict);
+ } else {
+ isVarDecl = false;
+ parser.assignable = AssignmentKind.Assignable;
+ init = parseMemberOrUpdateExpression(parser, context, init, 0, 0, tokenPos, linePos, colPos);
+
+ // `for of` only allows LeftHandSideExpressions which do not start with `let`, and no other production matches
+ if (parser.token === Token.OfKeyword) report(parser, Errors.ForOfLet);
+ }
+ } else {
+ nextToken(parser, context);
+
+ init = finishNode(
+ parser,
+ context,
+ tokenPos,
+ linePos,
+ colPos,
+ token === Token.VarKeyword
+ ? {
+ type: 'VariableDeclaration',
+ kind: 'var',
+ declarations: parseVariableDeclarationList(
+ parser,
+ context | Context.DisallowIn,
+ scope,
+ BindingKind.Variable,
+ Origin.ForStatement
+ )
+ }
+ : {
+ type: 'VariableDeclaration',
+ kind: 'const',
+ declarations: parseVariableDeclarationList(
+ parser,
+ context | Context.DisallowIn,
+ scope,
+ BindingKind.Const,
+ Origin.ForStatement
+ )
+ }
+ );
+
+ parser.assignable = AssignmentKind.Assignable;
+ }
+ } else if (token === Token.Semicolon) {
+ if (forAwait) report(parser, Errors.InvalidForAwait);
+ } else if ((token & Token.IsPatternStart) === Token.IsPatternStart) {
+ init =
+ token === Token.LeftBrace
+ ? parseObjectLiteralOrPattern(
+ parser,
+ context,
+ void 0,
+ 1,
+ 0,
+ 0,
+ BindingKind.Empty,
+ Origin.ForStatement,
+ tokenPos,
+ linePos,
+ colPos
+ )
+ : parseArrayExpressionOrPattern(
+ parser,
+ context,
+ void 0,
+ 1,
+ 0,
+ 0,
+ BindingKind.Empty,
+ Origin.ForStatement,
+ tokenPos,
+ linePos,
+ colPos
+ );
+
+ destructible = parser.destructible;
+
+ if (context & Context.OptionsWebCompat && destructible & DestructuringKind.SeenProto) {
+ report(parser, Errors.DuplicateProto);
+ }
+
+ parser.assignable =
+ destructible & DestructuringKind.CannotDestruct ? AssignmentKind.CannotAssign : AssignmentKind.Assignable;
+
+ init = parseMemberOrUpdateExpression(
+ parser,
+ context | Context.DisallowIn,
+ init as ESTree.Expression,
+ 0,
+ 0,
+ parser.tokenPos,
+ parser.linePos,
+ parser.colPos
+ );
+ } else {
+ init = parseLeftHandSideExpression(parser, context | Context.DisallowIn, 1, 0, 1, tokenPos, linePos, colPos);
+ }
+
+ if ((parser.token & Token.IsInOrOf) === Token.IsInOrOf) {
+ if (parser.token === Token.OfKeyword) {
+ if (parser.assignable & AssignmentKind.CannotAssign)
+ report(parser, Errors.CantAssignToInOfForLoop, forAwait ? 'await' : 'of');
+
+ reinterpretToPattern(parser, init);
+ nextToken(parser, context | Context.AllowRegExp);
+
+ // IterationStatement:
+ // for(LeftHandSideExpression of AssignmentExpression) Statement
+ // forawait(LeftHandSideExpression of AssignmentExpression) Statement
+ right = parseExpression(parser, context, 1, 0, 0, parser.tokenPos, parser.linePos, parser.colPos);
+
+ consume(parser, context | Context.AllowRegExp, Token.RightParen);
+
+ const body = parseIterationStatementBody(parser, context, scope, labels);
+
+ return finishNode(parser, context, start, line, column, {
+ type: 'ForOfStatement',
+ left: init,
+ right,
+ body,
+ await: forAwait
+ });
+ }
+
+ if (parser.assignable & AssignmentKind.CannotAssign) report(parser, Errors.CantAssignToInOfForLoop, 'in');
+
+ reinterpretToPattern(parser, init);
+ nextToken(parser, context | Context.AllowRegExp);
+
+ // `for await` only accepts the `for-of` type
+ if (forAwait) report(parser, Errors.InvalidForAwait);
+
+ // IterationStatement:
+ // for(LeftHandSideExpression in Expression) Statement
+ right = parseExpressions(parser, context, 0, 1, parser.tokenPos, parser.linePos, parser.colPos);
+
+ consume(parser, context | Context.AllowRegExp, Token.RightParen);
+ const body = parseIterationStatementBody(parser, context, scope, labels);
+
+ return finishNode(parser, context, start, line, column, {
+ type: 'ForInStatement',
+ body,
+ left: init,
+ right
+ });
+ }
+
+ if (forAwait) report(parser, Errors.InvalidForAwait);
+
+ if (!isVarDecl) {
+ if (destructible & DestructuringKind.HasToDestruct && parser.token !== Token.Assign) {
+ report(parser, Errors.CantAssignToInOfForLoop, 'loop');
+ }
+
+ init = parseAssignmentExpression(parser, context | Context.DisallowIn, 0, 0, tokenPos, linePos, colPos, init);
+ }
+
+ if (parser.token === Token.Comma)
+ init = parseSequenceExpression(parser, context, 0, parser.tokenPos, parser.linePos, parser.colPos, init);
+
+ consume(parser, context | Context.AllowRegExp, Token.Semicolon);
+
+ if (parser.token !== Token.Semicolon)
+ test = parseExpressions(parser, context, 0, 1, parser.tokenPos, parser.linePos, parser.colPos);
+
+ consume(parser, context | Context.AllowRegExp, Token.Semicolon);
+
+ if (parser.token !== Token.RightParen)
+ update = parseExpressions(parser, context, 0, 1, parser.tokenPos, parser.linePos, parser.colPos);
+
+ consume(parser, context | Context.AllowRegExp, Token.RightParen);
+
+ const body = parseIterationStatementBody(parser, context, scope, labels);
+
+ return finishNode(parser, context, start, line, column, {
+ type: 'ForStatement',
+ init,
+ test,
+ update,
+ body
+ });
+}
+
+/**
+ * Parses restricted identifier in import & export declaration
+ *
+ * @param parser Parser object
+ * @param context Context masks
+ * @param scope Scope object
+ */
+
+export function parseRestrictedIdentifier(
+ parser: ParserState,
+ context: Context,
+ scope: ScopeState | undefined
+): ESTree.Identifier {
+ if (!isValidIdentifier(context, parser.token)) report(parser, Errors.UnexpectedStrictReserved);
+ if ((parser.token & Token.IsEvalOrArguments) === Token.IsEvalOrArguments) report(parser, Errors.StrictEvalArguments);
+ if (scope) addBlockName(parser, context, scope, parser.tokenValue, BindingKind.Let, Origin.None);
+ return parseIdentifier(parser, context, 0);
+}
+
+/**
+ * Parse import declaration
+ *
+ * @see [Link](https://tc39.github.io/ecma262/#prod-ImportDeclaration)
+ *
+ * @param parser Parser object
+ * @param context Context masks
+ * @param scope Scope object
+ */
+function parseImportDeclaration(
+ parser: ParserState,
+ context: Context,
+ scope: ScopeState | undefined
+): ESTree.ImportDeclaration | ESTree.ExpressionStatement {
+ // ImportDeclaration :
+ // 'import' ImportClause 'from' ModuleSpecifier ';'
+ // 'import' ModuleSpecifier ';'
+ //
+ // ImportClause :
+ // ImportedDefaultBinding
+ // NameSpaceImport
+ // NamedImports
+ // ImportedDefaultBinding ',' NameSpaceImport
+ // ImportedDefaultBinding ',' NamedImports
+ //
+ // NameSpaceImport :
+ // '*' 'as' ImportedBinding
+ const start = parser.tokenPos;
+ const line = parser.linePos;
+ const column = parser.colPos;
+
+ nextToken(parser, context);
+
+ let source: ESTree.Literal | null = null;
+
+ const { tokenPos, linePos, colPos } = parser;
+
+ let specifiers: (ESTree.ImportSpecifier | ESTree.ImportDefaultSpecifier | ESTree.ImportNamespaceSpecifier)[] = [];
+
+ // 'import' ModuleSpecifier ';'
+ if (parser.token === Token.StringLiteral) {
+ source = parseLiteral(parser, context);
+ } else {
+ if (parser.token & Token.IsIdentifier) {
+ const local = parseRestrictedIdentifier(parser, context, scope);
+ specifiers = [
+ finishNode(parser, context, tokenPos, linePos, colPos, {
+ type: 'ImportDefaultSpecifier',
+ local
+ })
+ ];
+
+ // NameSpaceImport
+ if (consumeOpt(parser, context, Token.Comma)) {
+ switch (parser.token) {
+ case Token.Multiply:
+ specifiers.push(parseImportNamespaceSpecifier(parser, context, scope));
+ break;
+
+ case Token.LeftBrace:
+ parseImportSpecifierOrNamedImports(parser, context, scope, specifiers);
+ break;
+
+ default:
+ report(parser, Errors.InvalidDefaultImport);
+ }
+ }
+ } else {
+ // Parse NameSpaceImport or NamedImports if present
+ switch (parser.token) {
+ case Token.Multiply:
+ specifiers = [parseImportNamespaceSpecifier(parser, context, scope)];
+ break;
+ case Token.LeftBrace:
+ parseImportSpecifierOrNamedImports(parser, context, scope, specifiers);
+ break;
+ case Token.LeftParen:
+ return parseImportCallDeclaration(parser, context, start, line, column);
+ case Token.Period:
+ return parseImportMetaDeclaration(parser, context, start, line, column);
+ default:
+ report(parser, Errors.UnexpectedToken, KeywordDescTable[parser.token & Token.Type]);
+ }
+ }
+
+ source = parseModuleSpecifier(parser, context);
+ }
+
+ matchOrInsertSemicolon(parser, context | Context.AllowRegExp);
+
+ return finishNode(parser, context, start, line, column, {
+ type: 'ImportDeclaration',
+ specifiers,
+ source
+ });
+}
+
+/**
+ * Parse binding identifier
+ *
+ * @see [Link](https://tc39.github.io/ecma262/#prod-NameSpaceImport)
+ *
+ * @param parser Parser object
+ * @param context Context masks
+ * @param specifiers Array of import specifiers
+ */
+function parseImportNamespaceSpecifier(
+ parser: ParserState,
+ context: Context,
+ scope: ScopeState | undefined
+): ESTree.ImportNamespaceSpecifier {
+ // NameSpaceImport:
+ // * as ImportedBinding
+ const { tokenPos, linePos, colPos } = parser;
+ nextToken(parser, context);
+ consume(parser, context, Token.AsKeyword);
+
+ // 'import * as class from "foo":'
+ if ((parser.token & Token.IsStringOrNumber) === Token.IsStringOrNumber) {
+ reportMessageAt(
+ tokenPos,
+ parser.line,
+ parser.index,
+ Errors.UnexpectedToken,
+ KeywordDescTable[parser.token & Token.Type]
+ );
+ }
+
+ return finishNode(parser, context, tokenPos, linePos, colPos, {
+ type: 'ImportNamespaceSpecifier',
+ local: parseRestrictedIdentifier(parser, context, scope)
+ });
+}
+
+/**
+ * Parse module specifier
+ *
+ * @see [Link](https://tc39.github.io/ecma262/#prod-ModuleSpecifier)
+ *
+ * @param parser Parser object
+ * @param context Context masks
+ */
+function parseModuleSpecifier(parser: ParserState, context: Context): ESTree.Literal {
+ // ModuleSpecifier :
+ // StringLiteral
+ consumeOpt(parser, context, Token.FromKeyword);
+
+ if (parser.token !== Token.StringLiteral) report(parser, Errors.InvalidExportImportSource, 'Import');
+
+ return parseLiteral(parser, context);
+}
+
+function parseImportSpecifierOrNamedImports(
+ parser: ParserState,
+ context: Context,
+ scope: ScopeState | undefined,
+ specifiers: (ESTree.ImportSpecifier | ESTree.ImportDefaultSpecifier | ESTree.ImportNamespaceSpecifier)[]
+): (ESTree.ImportSpecifier | ESTree.ImportDefaultSpecifier | ESTree.ImportNamespaceSpecifier)[] {
+ // NamedImports :
+ // '{' '}'
+ // '{' ImportsList '}'
+ // '{' ImportsList ',' '}'
+ //
+ // ImportsList :
+ // ImportSpecifier
+ // ImportsList ',' ImportSpecifier
+ //
+ // ImportSpecifier :
+ // BindingIdentifier
+ // IdentifierName 'as' BindingIdentifier
+
+ nextToken(parser, context);
+
+ while (parser.token & Token.IsIdentifier) {
+ let { token, tokenValue, tokenPos, linePos, colPos } = parser;
+ const imported = parseIdentifier(parser, context, 0);
+ let local: ESTree.Identifier;
+
+ if (consumeOpt(parser, context, Token.AsKeyword)) {
+ if ((parser.token & Token.IsStringOrNumber) === Token.IsStringOrNumber || parser.token === Token.Comma) {
+ report(parser, Errors.InvalidKeywordAsAlias);
+ } else {
+ validateBindingIdentifier(parser, context, BindingKind.Const, parser.token, 0);
+ }
+ tokenValue = parser.tokenValue;
+ local = parseIdentifier(parser, context, 0);
+ } else {
+ // Keywords cannot be bound to themselves, so an import name
+ // that is a keyword is a syntax error if it is not followed
+ // by the keyword 'as'.
+ // See the ImportSpecifier production in ES6 section 15.2.2.
+ validateBindingIdentifier(parser, context, BindingKind.Const, token, 0);
+ local = imported;
+ }
+
+ if (scope) addBlockName(parser, context, scope, tokenValue, BindingKind.Let, Origin.None);
+
+ specifiers.push(
+ finishNode(parser, context, tokenPos, linePos, colPos, {
+ type: 'ImportSpecifier',
+ local,
+ imported
+ })
+ );
+
+ if (parser.token !== Token.RightBrace) consume(parser, context, Token.Comma);
+ }
+
+ consume(parser, context, Token.RightBrace);
+
+ return specifiers;
+}
+
+/**
+ * Parse import meta declaration
+ *
+ * @param parser Parser object
+ * @param context Context masks
+ * @param meta ESTree AST node
+ * @param start
+ * @param line
+ * @param column
+ */
+export function parseImportMetaDeclaration(
+ parser: ParserState,
+ context: Context,
+ start: number,
+ line: number,
+ column: number
+): ESTree.ExpressionStatement {
+ let expr: ESTree.Expression = parseImportMetaExpression(
+ parser,
+ context,
+ finishNode(parser, context, start, line, column, {
+ type: 'Identifier',
+ name: 'import'
+ }),
+ start,
+ line,
+ column
+ );
+
+ /** MemberExpression :
+ * 1. PrimaryExpression
+ * 2. MemberExpression [ AssignmentExpression ]
+ * 3. MemberExpression . IdentifierName
+ * 4. MemberExpression TemplateLiteral
+ *
+ * CallExpression :
+ * 1. MemberExpression Arguments
+ * 2. CallExpression ImportCall
+ * 3. CallExpression Arguments
+ * 4. CallExpression [ AssignmentExpression ]
+ * 5. CallExpression . IdentifierName
+ * 6. CallExpression TemplateLiteral
+ *
+ * UpdateExpression ::
+ * ('++' | '--')? LeftHandSideExpression
+ *
+ */
+
+ expr = parseMemberOrUpdateExpression(parser, context, expr, 0, 0, start, line, column);
+
+ /** AssignmentExpression :
+ * 1. ConditionalExpression
+ * 2. LeftHandSideExpression = AssignmentExpression
+ */
+
+ expr = parseAssignmentExpression(parser, context, 0, 0, start, line, column, expr as ESTree.Expression);
+
+ /**
+ * ExpressionStatement[Yield, Await]:
+ * [lookahead ∉ { {, function, async [no LineTerminator here] function, class, let [ }]Expression[+In, ?Yield, ?Await]
+ */
+ return parseExpressionStatement(parser, context, expr, start, line, column);
+}
+
+/**
+ * Parse dynamic import declaration
+ *
+ * @see [Link](https://github.com/tc39/proposal-dynamic-import)
+ *
+ * @param parser Parser object
+ * @param context Context masks
+ * @param number
+ */
+function parseImportCallDeclaration(
+ parser: ParserState,
+ context: Context,
+ start: number,
+ line: number,
+ column: number
+): ESTree.ExpressionStatement {
+ let expr = parseImportExpression(parser, context, /* inGroup */ 0, start, line, column);
+
+ /** MemberExpression :
+ * 1. PrimaryExpression
+ * 2. MemberExpression [ AssignmentExpression ]
+ * 3. MemberExpression . IdentifierName
+ * 4. MemberExpression TemplateLiteral
+ *
+ * CallExpression :
+ * 1. MemberExpression Arguments
+ * 2. CallExpression ImportCall
+ * 3. CallExpression Arguments
+ * 4. CallExpression [ AssignmentExpression ]
+ * 5. CallExpression . IdentifierName
+ * 6. CallExpression TemplateLiteral
+ *
+ * UpdateExpression ::
+ * ('++' | '--')? LeftHandSideExpression
+ *
+ */
+
+ expr = parseMemberOrUpdateExpression(parser, context, expr, 0, 0, start, line, column);
+
+ /**
+ * ExpressionStatement[Yield, Await]:
+ * [lookahead ∉ { {, function, async [no LineTerminator here] function, class, let [ }]Expression[+In, ?Yield, ?Await]
+ */
+ return parseExpressionStatement(parser, context, expr, start, line, column);
+}
+
+/**
+ * Parse export declaration
+ *
+ * @see [Link](https://tc39.github.io/ecma262/#prod-ExportDeclaration)
+ *
+ * @param parser Parser object
+ * @param context Context masks
+ */
+function parseExportDeclaration(
+ parser: ParserState,
+ context: Context,
+ scope: ScopeState | undefined
+): ESTree.ExportAllDeclaration | ESTree.ExportNamedDeclaration | ESTree.ExportDefaultDeclaration {
+ // ExportDeclaration:
+ // 'export' '*' 'from' ModuleSpecifier ';'
+ // 'export' '*' 'as' IdentifierName 'from' ModuleSpecifier ';'
+ // 'export' ExportClause ('from' ModuleSpecifier)? ';'
+ // 'export' VariableStatement
+ // 'export' Declaration
+ // 'export' 'default'
+ const start = parser.tokenPos;
+ const line = parser.linePos;
+ const column = parser.colPos;
+
+ // https://tc39.github.io/ecma262/#sec-exports
+ nextToken(parser, context | Context.AllowRegExp);
+
+ const specifiers: ESTree.ExportSpecifier[] = [];
+
+ let declaration: ESTree.ExportDeclaration | ESTree.Expression | null = null;
+ let source: ESTree.Literal | null = null;
+ let key: string;
+
+ if (consumeOpt(parser, context | Context.AllowRegExp, Token.DefaultKeyword)) {
+ // export default HoistableDeclaration[Default]
+ // export default ClassDeclaration[Default]
+ // export default [lookahead not-in {function, class}] AssignmentExpression[In] ;
+
+ switch (parser.token) {
+ // export default HoistableDeclaration[Default]
+ case Token.FunctionKeyword: {
+ declaration = parseFunctionDeclaration(
+ parser,
+ context,
+ scope,
+ Origin.TopLevel,
+ 1,
+ HoistedFunctionFlags.Hoisted,
+ 0,
+ parser.tokenPos,
+ parser.linePos,
+ parser.colPos
+ );
+ break;
+ }
+ // export default ClassDeclaration[Default]
+ // export default @decl ClassDeclaration[Default]
+ case Token.Decorator:
+ case Token.ClassKeyword:
+ declaration = parseClassDeclaration(
+ parser,
+ context,
+ scope,
+ HoistedClassFlags.Hoisted,
+ parser.tokenPos,
+ parser.linePos,
+ parser.colPos
+ );
+ break;
+
+ // export default HoistableDeclaration[Default]
+ case Token.AsyncKeyword:
+ const { tokenPos, linePos, colPos } = parser;
+
+ declaration = parseIdentifier(parser, context, 0);
+
+ const { flags } = parser;
+
+ if ((flags & Flags.NewLine) < 1) {
+ if (parser.token === Token.FunctionKeyword) {
+ declaration = parseFunctionDeclaration(
+ parser,
+ context,
+ scope,
+ Origin.TopLevel,
+ 1,
+ HoistedFunctionFlags.Hoisted,
+ 1,
+ tokenPos,
+ linePos,
+ colPos
+ );
+ } else {
+ if (parser.token === Token.LeftParen) {
+ declaration = parseAsyncArrowOrCallExpression(
+ parser,
+ context,
+ declaration,
+ 1,
+ BindingKind.ArgumentList,
+ Origin.None,
+ flags,
+ tokenPos,
+ linePos,
+ colPos
+ );
+ declaration = parseMemberOrUpdateExpression(
+ parser,
+ context,
+ declaration as any,
+ 0,
+ 0,
+ tokenPos,
+ linePos,
+ colPos
+ );
+ declaration = parseAssignmentExpression(
+ parser,
+ context,
+ 0,
+ 0,
+ tokenPos,
+ linePos,
+ colPos,
+ declaration as any
+ );
+ } else if (parser.token & Token.IsIdentifier) {
+ if (scope) scope = createArrowHeadParsingScope(parser, context, parser.tokenValue);
+
+ declaration = parseIdentifier(parser, context, 0);
+ declaration = parseArrowFunctionExpression(
+ parser,
+ context,
+ scope,
+ [declaration],
+ 1,
+ tokenPos,
+ linePos,
+ colPos
+ );
+ }
+ }
+ }
+ break;
+
+ default:
+ // export default [lookahead ∉ {function, class}] AssignmentExpression[In] ;
+ declaration = parseExpression(parser, context, 1, 0, 0, parser.tokenPos, parser.linePos, parser.colPos);
+ matchOrInsertSemicolon(parser, context | Context.AllowRegExp);
+ }
+
+ // See: https://www.ecma-international.org/ecma-262/9.0/index.html#sec-exports-static-semantics-exportednames
+ if (scope) declareUnboundVariable(parser, 'default');
+
+ return finishNode(parser, context, start, line, column, {
+ type: 'ExportDefaultDeclaration',
+ declaration
+ });
+ }
+
+ switch (parser.token) {
+ case Token.Multiply: {
+ //
+ // 'export' '*' 'as' IdentifierName 'from' ModuleSpecifier ';'
+ //
+ // See: https://github.com/tc39/ecma262/pull/1174
+ nextToken(parser, context); // Skips: '*'
+
+ let exported: ESTree.Identifier | null = null;
+ const isNamedDeclaration = consumeOpt(parser, context, Token.AsKeyword);
+
+ if (isNamedDeclaration) {
+ if (scope) declareUnboundVariable(parser, parser.tokenValue);
+ exported = parseIdentifier(parser, context, 0);
+ }
+
+ consume(parser, context, Token.FromKeyword);
+
+ if (parser.token !== Token.StringLiteral) report(parser, Errors.InvalidExportImportSource, 'Export');
+
+ source = parseLiteral(parser, context);
+
+ matchOrInsertSemicolon(parser, context | Context.AllowRegExp);
+
+ return finishNode(parser, context, start, line, column, {
+ type: 'ExportAllDeclaration',
+ source,
+ exported
+ } as any);
+ }
+ case Token.LeftBrace: {
+ // ExportClause :
+ // '{' '}'
+ // '{' ExportsList '}'
+ // '{' ExportsList ',' '}'
+ //
+ // ExportsList :
+ // ExportSpecifier
+ // ExportsList ',' ExportSpecifier
+ //
+ // ExportSpecifier :
+ // IdentifierName
+ // IdentifierName 'as' IdentifierName
+
+ nextToken(parser, context); // Skips: '{'
+
+ const tmpExportedNames: string[] = [];
+ const tmpExportedBindings: string[] = [];
+
+ while (parser.token & Token.IsIdentifier) {
+ const { tokenPos, tokenValue, linePos, colPos } = parser;
+ const local = parseIdentifier(parser, context, 0);
+
+ let exported: ESTree.Identifier | null;
+
+ if (parser.token === Token.AsKeyword) {
+ nextToken(parser, context);
+ if ((parser.token & Token.IsStringOrNumber) === Token.IsStringOrNumber) {
+ report(parser, Errors.InvalidKeywordAsAlias);
+ }
+ if (scope) {
+ tmpExportedNames.push(parser.tokenValue);
+ tmpExportedBindings.push(tokenValue);
+ }
+ exported = parseIdentifier(parser, context, 0);
+ } else {
+ if (scope) {
+ tmpExportedNames.push(parser.tokenValue);
+ tmpExportedBindings.push(parser.tokenValue);
+ }
+ exported = local;
+ }
+
+ specifiers.push(
+ finishNode(parser, context, tokenPos, linePos, colPos, {
+ type: 'ExportSpecifier',
+ local,
+ exported
+ })
+ );
+
+ if (parser.token !== Token.RightBrace) consume(parser, context, Token.Comma);
+ }
+
+ consume(parser, context, Token.RightBrace);
+
+ if (consumeOpt(parser, context, Token.FromKeyword)) {
+ // The left hand side can't be a keyword where there is no
+ // 'from' keyword since it references a local binding.
+ if (parser.token !== Token.StringLiteral) report(parser, Errors.InvalidExportImportSource, 'Export');
+
+ source = parseLiteral(parser, context);
+ } else if (scope) {
+ let i = 0;
+ let iMax = tmpExportedNames.length;
+ for (; i < iMax; i++) {
+ declareUnboundVariable(parser, tmpExportedNames[i]);
+ }
+ i = 0;
+ iMax = tmpExportedBindings.length;
+
+ for (; i < iMax; i++) {
+ addBindingToExports(parser, tmpExportedBindings[i]);
+ }
+ }
+
+ matchOrInsertSemicolon(parser, context | Context.AllowRegExp);
+
+ break;
+ }
+
+ case Token.ClassKeyword:
+ declaration = parseClassDeclaration(
+ parser,
+ context,
+ scope,
+ HoistedClassFlags.Export,
+ parser.tokenPos,
+ parser.linePos,
+ parser.colPos
+ );
+ break;
+ case Token.FunctionKeyword:
+ declaration = parseFunctionDeclaration(
+ parser,
+ context,
+ scope,
+ Origin.TopLevel,
+ 1,
+ HoistedFunctionFlags.Export,
+ 0,
+ parser.tokenPos,
+ parser.linePos,
+ parser.colPos
+ );
+ break;
+
+ case Token.LetKeyword:
+ declaration = parseLexicalDeclaration(
+ parser,
+ context,
+ scope,
+ BindingKind.Let,
+ Origin.Export,
+ parser.tokenPos,
+ parser.linePos,
+ parser.colPos
+ );
+ break;
+ case Token.ConstKeyword:
+ declaration = parseLexicalDeclaration(
+ parser,
+ context,
+ scope,
+ BindingKind.Const,
+ Origin.Export,
+ parser.tokenPos,
+ parser.linePos,
+ parser.colPos
+ );
+ break;
+ case Token.VarKeyword:
+ declaration = parseVariableStatement(
+ parser,
+ context,
+ scope,
+ Origin.Export,
+ parser.tokenPos,
+ parser.linePos,
+ parser.colPos
+ );
+ break;
+ case Token.AsyncKeyword:
+ const { tokenPos, linePos, colPos } = parser;
+
+ nextToken(parser, context);
+
+ if ((parser.flags & Flags.NewLine) < 1 && parser.token === Token.FunctionKeyword) {
+ declaration = parseFunctionDeclaration(
+ parser,
+ context,
+ scope,
+ Origin.TopLevel,
+ 1,
+ HoistedFunctionFlags.Export,
+ 1,
+ tokenPos,
+ linePos,
+ colPos
+ );
+ if (scope) {
+ key = declaration.id ? declaration.id.name : '';
+ declareUnboundVariable(parser, key);
+ }
+ break;
+ }
+ // falls through
+ default:
+ report(parser, Errors.UnexpectedToken, KeywordDescTable[parser.token & Token.Type]);
+ }
+
+ return finishNode(parser, context, start, line, column, {
+ type: 'ExportNamedDeclaration',
+ declaration,
+ specifiers,
+ source
+ });
+}
+
+/**
+ * Parses an expression
+ *
+ * @param parser Parser object
+ * @param context Context masks
+ * @param assignable
+ */
+export function parseExpression(
+ parser: ParserState,
+ context: Context,
+ canAssign: 0 | 1,
+ isPattern: 0 | 1,
+ inGroup: 0 | 1,
+ start: number,
+ line: number,
+ column: number
+): ESTree.Expression {
+ // Expression ::
+ // AssignmentExpression
+ // Expression ',' AssignmentExpression
+
+ let expr = parsePrimaryExpression(
+ parser,
+ context,
+ BindingKind.Empty,
+ 0,
+ canAssign,
+ isPattern,
+ inGroup,
+ 1,
+ start,
+ line,
+ column
+ );
+
+ expr = parseMemberOrUpdateExpression(parser, context, expr, inGroup, 0, start, line, column);
+
+ return parseAssignmentExpression(parser, context, inGroup, 0, start, line, column, expr);
+}
+
+/**
+ * Parse sequence expression
+ *
+ * @param parser Parser object
+ * @param context Context masks
+ * @param expr ESTree AST node
+ */
+export function parseSequenceExpression(
+ parser: ParserState,
+ context: Context,
+ inGroup: 0 | 1,
+ start: number,
+ line: number,
+ column: number,
+ expr: ESTree.AssignmentExpression | ESTree.Expression
+): ESTree.SequenceExpression {
+ // Expression ::
+ // AssignmentExpression
+ // Expression ',' AssignmentExpression
+ const expressions: ESTree.Expression[] = [expr];
+ while (consumeOpt(parser, context | Context.AllowRegExp, Token.Comma)) {
+ expressions.push(parseExpression(parser, context, 1, 0, inGroup, parser.tokenPos, parser.linePos, parser.colPos));
+ }
+
+ return finishNode(parser, context, start, line, column, {
+ type: 'SequenceExpression',
+ expressions
+ });
+}
+
+/**
+ * Parse expression or sequence expression
+ *
+ * @param parser Parser object
+ * @param context Context masks
+ * @param canAssign
+ */
+export function parseExpressions(
+ parser: ParserState,
+ context: Context,
+ inGroup: 0 | 1,
+ canAssign: 0 | 1,
+ start: number,
+ line: number,
+ column: number
+): ESTree.SequenceExpression | ESTree.Expression {
+ const expr = parseExpression(parser, context, canAssign, 0, inGroup, start, line, column);
+ return parser.token === Token.Comma
+ ? parseSequenceExpression(parser, context, inGroup, start, line, column, expr)
+ : expr;
+}
+
+/**
+ * Parse assignment expression
+ *
+ * @param parser Parser object
+ * @param context Context masks
+ * @param inGroup
+ * @param isPattern
+ * @param start
+ * @param line
+ * @param column
+ * @param left
+ *
+ * * @param left ESTree AST node
+ */
+export function parseAssignmentExpression(
+ parser: ParserState,
+ context: Context,
+ inGroup: 0 | 1,
+ isPattern: 0 | 1,
+ start: number,
+ line: number,
+ column: number,
+ left: ESTree.ArgumentExpression | ESTree.Expression | null
+): ESTree.ArgumentExpression | ESTree.Expression {
+ /**
+ * AssignmentExpression ::
+ * ConditionalExpression
+ * ArrowFunction
+ * AsyncArrowFunction
+ * YieldExpression
+ * LeftHandSideExpression AssignmentOperator AssignmentExpression
+ */
+
+ const { token } = parser;
+
+ if ((token & Token.IsAssignOp) === Token.IsAssignOp) {
+ if (parser.assignable & AssignmentKind.CannotAssign) report(parser, Errors.CantAssignTo);
+ if (
+ (!isPattern && token === Token.Assign && ((left as ESTree.Expression).type as string) === 'ArrayExpression') ||
+ ((left as ESTree.Expression).type as string) === 'ObjectExpression'
+ ) {
+ reinterpretToPattern(parser, left);
+ }
+
+ nextToken(parser, context | Context.AllowRegExp);
+
+ const right = parseExpression(parser, context, 1, 1, inGroup, parser.tokenPos, parser.linePos, parser.colPos);
+
+ parser.assignable = AssignmentKind.CannotAssign;
+
+ return finishNode(
+ parser,
+ context,
+ start,
+ line,
+ column,
+ isPattern
+ ? {
+ type: 'AssignmentPattern',
+ left,
+ right
+ }
+ : ({
+ type: 'AssignmentExpression',
+ left,
+ operator: KeywordDescTable[token & Token.Type],
+ right
+ } as any)
+ );
+ }
+
+ /** Binary expression
+ *
+ * https://tc39.github.io/ecma262/#sec-multiplicative-operators
+ *
+ */
+ if ((token & Token.IsBinaryOp) === Token.IsBinaryOp) {
+ // We start using the binary expression parser for prec >= 4 only!
+ left = parseBinaryExpression(parser, context, inGroup, start, line, column, 4, token, left as ESTree.Expression);
+ }
+
+ /**
+ * Conditional expression
+ * https://tc39.github.io/ecma262/#prod-ConditionalExpression
+ *
+ */
+ if (consumeOpt(parser, context | Context.AllowRegExp, Token.QuestionMark)) {
+ left = parseConditionalExpression(parser, context, left as ESTree.Expression, start, line, column);
+ }
+
+ return left as ESTree.Expression;
+}
+
+/**
+ * Parse assignment expression or assignment pattern
+ *
+ * @param parser Parser object
+ * @param context Context masks
+ * @param inGroup
+ * @param isPattern
+ * @param start
+ * @param line
+ * @param column
+ * @param left
+ */
+
+export function parseAssignmentExpressionOrPattern(
+ parser: ParserState,
+ context: Context,
+ inGroup: 0 | 1,
+ isPattern: 0 | 1,
+ start: number,
+ line: number,
+ column: number,
+ left: any
+): any {
+ const { token } = parser;
+
+ nextToken(parser, context | Context.AllowRegExp);
+
+ const right = parseExpression(parser, context, 1, 1, inGroup, parser.tokenPos, parser.linePos, parser.colPos);
+
+ left = finishNode(
+ parser,
+ context,
+ start,
+ line,
+ column,
+ isPattern
+ ? {
+ type: 'AssignmentPattern',
+ left,
+ right
+ }
+ : ({
+ type: 'AssignmentExpression',
+ left,
+ operator: KeywordDescTable[token & Token.Type],
+ right
+ } as any)
+ );
+
+ parser.assignable = AssignmentKind.CannotAssign;
+
+ return left as ESTree.Expression;
+}
+
+/**
+ * Parse conditional expression
+ *
+ * @param parser Parser object
+ * @param context Context masks
+ * @param test ESTree AST node
+ */
+export function parseConditionalExpression(
+ parser: ParserState,
+ context: Context,
+ test: ESTree.Expression,
+ start: number,
+ line: number,
+ column: number
+): ESTree.ConditionalExpression {
+ // ConditionalExpression ::
+ // LogicalOrExpression
+ // LogicalOrExpression '?' AssignmentExpression ':' AssignmentExpression
+ const consequent = parseExpression(
+ parser,
+ (context | Context.DisallowIn) ^ Context.DisallowIn,
+ 1,
+ 0,
+ 0,
+ parser.tokenPos,
+ parser.linePos,
+ parser.colPos
+ );
+ consume(parser, context | Context.AllowRegExp, Token.Colon);
+ parser.assignable = AssignmentKind.Assignable;
+ // In parsing the first assignment expression in conditional
+ // expressions we always accept the 'in' keyword; see ECMA-262,
+ // section 11.12, page 58.
+ const alternate = parseExpression(parser, context, 1, 0, 0, parser.tokenPos, parser.linePos, parser.colPos);
+ parser.assignable = AssignmentKind.CannotAssign;
+ return finishNode(parser, context, start, line, column, {
+ type: 'ConditionalExpression',
+ test,
+ consequent,
+ alternate
+ });
+}
+
+/**
+ * Parses binary and unary expressions recursively
+ * based on the precedence of the operators encountered.
+ *
+ * @param parser Parser object
+ * @param context Context masks
+ * @param minPrec The precedence of the last binary expression parsed
+ * @param left ESTree AST node
+ */
+export function parseBinaryExpression(
+ parser: ParserState,
+ context: Context,
+ inGroup: 0 | 1,
+ start: number,
+ line: number,
+ column: number,
+ minPrec: number,
+ operator: Token,
+ left: ESTree.ArgumentExpression | ESTree.Expression
+): ESTree.ArgumentExpression | ESTree.Expression {
+ const bit = -((context & Context.DisallowIn) > 0) & Token.InKeyword;
+ let t: Token;
+ let prec: number;
+
+ parser.assignable = AssignmentKind.CannotAssign;
+
+ while (parser.token & Token.IsBinaryOp) {
+ t = parser.token;
+ prec = t & Token.Precedence;
+
+ if ((t & Token.IsLogical && operator & Token.IsCoalesc) || (operator & Token.IsLogical && t & Token.IsCoalesc)) {
+ report(parser, Errors.InvalidCoalescing);
+ }
+
+ // 0 precedence will terminate binary expression parsing
+
+ if (prec + (((t === Token.Exponentiate) as any) << 8) - (((bit === t) as any) << 12) <= minPrec) break;
+ nextToken(parser, context | Context.AllowRegExp);
+
+ left = finishNode(parser, context, start, line, column, {
+ type: t & Token.IsLogical || t & Token.IsCoalesc ? 'LogicalExpression' : 'BinaryExpression',
+ left,
+ right: parseBinaryExpression(
+ parser,
+ context,
+ inGroup,
+ parser.tokenPos,
+ parser.linePos,
+ parser.colPos,
+ prec,
+ t,
+ parseLeftHandSideExpression(parser, context, 0, inGroup, 1, parser.tokenPos, parser.linePos, parser.colPos)
+ ),
+ operator: KeywordDescTable[t & Token.Type]
+ });
+ }
+
+ if (parser.token === Token.Assign) report(parser, Errors.CantAssignTo);
+
+ return left;
+}
+
+/**
+ * Parses unary expression
+ *
+ * @param parser Parser object
+ * @param context Context masks
+ */
+export function parseUnaryExpression(
+ parser: ParserState,
+ context: Context,
+ isLHS: 0 | 1,
+ start: number,
+ line: number,
+ column: number,
+ inGroup: 0 | 1
+): ESTree.UnaryExpression {
+ /**
+ * UnaryExpression ::
+ * 1) UpdateExpression
+ * 2) delete UnaryExpression
+ * 3) void UnaryExpression
+ * 4) typeof UnaryExpression
+ * 5) + UnaryExpression
+ * 6) - UnaryExpression
+ * 7) ~ UnaryExpression
+ * 8) ! UnaryExpression
+ * 9) AwaitExpression
+ */
+ if (!isLHS) report(parser, Errors.Unexpected);
+ const unaryOperator = parser.token;
+ nextToken(parser, context | Context.AllowRegExp);
+ const arg = parseLeftHandSideExpression(
+ parser,
+ context,
+ 0,
+ inGroup,
+ 1,
+ parser.tokenPos,
+ parser.linePos,
+ parser.colPos
+ );
+ if (parser.token === Token.Exponentiate) report(parser, Errors.InvalidExponentiationLHS);
+ if (context & Context.Strict && unaryOperator === Token.DeleteKeyword) {
+ if (arg.type === 'Identifier') {
+ report(parser, Errors.StrictDelete);
+ // Prohibit delete of private class elements
+ } else if (isPropertyWithPrivateFieldKey(arg)) {
+ report(parser, Errors.DeletePrivateField);
+ }
+ }
+
+ parser.assignable = AssignmentKind.CannotAssign;
+
+ return finishNode(parser, context, start, line, column, {
+ type: 'UnaryExpression',
+ operator: KeywordDescTable[unaryOperator & Token.Type] as ESTree.UnaryOperator,
+ argument: arg,
+ prefix: true
+ });
+}
+
+/**
+ * Parse async expression
+ *
+ * @param parser Parser object
+ * @param context Context masks
+ */
+export function parseAsyncExpression(
+ parser: ParserState,
+ context: Context,
+ inGroup: 0 | 1,
+ isLHS: 0 | 1,
+ canAssign: 0 | 1,
+ isPattern: 0 | 1,
+ inNew: 0 | 1,
+ start: number,
+ line: number,
+ column: number
+): ESTree.FunctionExpression | ESTree.ArrowFunctionExpression | ESTree.CallExpression | ESTree.Identifier {
+ const { token } = parser;
+ const expr = parseIdentifier(parser, context, isPattern);
+ const { flags } = parser;
+
+ if ((flags & Flags.NewLine) < 1) {
+ // async function ...
+ if (parser.token === Token.FunctionKeyword) {
+ return parseFunctionExpression(parser, context, /* isAsync */ 1, inGroup, start, line, column);
+ }
+
+ // async Identifier => ...
+ if ((parser.token & Token.IsIdentifier) === Token.IsIdentifier) {
+ if (!isLHS) report(parser, Errors.Unexpected);
+ return parseAsyncArrowAfterIdent(parser, context, canAssign, start, line, column);
+ }
+ }
+
+ // async (...) => ...
+ if (!inNew && parser.token === Token.LeftParen) {
+ return parseAsyncArrowOrCallExpression(
+ parser,
+ context,
+ expr,
+ canAssign,
+ BindingKind.ArgumentList,
+ Origin.None,
+ flags,
+ start,
+ line,
+ column
+ );
+ }
+
+ if (parser.token === Token.Arrow) {
+ classifyIdentifier(parser, context, token, /* isArrow */ 1);
+ if (inNew) report(parser, Errors.InvalidAsyncArrow);
+ return parseArrowFromIdentifier(parser, context, parser.tokenValue, expr, inNew, canAssign, 0, start, line, column);
+ }
+ return expr;
+}
+
+/**
+ * Parse yield expression
+ *
+ * @param parser Parser object
+ * @param context Context masks
+ */
+export function parseYieldExpression(
+ parser: ParserState,
+ context: Context,
+ inGroup: 0 | 1,
+ canAssign: 0 | 1,
+ start: number,
+ line: number,
+ column: number
+): ESTree.YieldExpression | ESTree.Identifier | ESTree.ArrowFunctionExpression {
+ // YieldExpression[In] :
+ // yield
+ // yield [no LineTerminator here] AssignmentExpression[?In, Yield]
+ // yield [no LineTerminator here] * AssignmentExpression[?In, Yield]
+
+ if (inGroup) parser.destructible |= DestructuringKind.Yield;
+ if (context & Context.InYieldContext) {
+ nextToken(parser, context | Context.AllowRegExp);
+ if (context & Context.InArgumentList) report(parser, Errors.YieldInParameter);
+ if (!canAssign) report(parser, Errors.CantAssignTo);
+ if (parser.token === Token.QuestionMark) report(parser, Errors.InvalidTernaryYield);
+
+ let argument: ESTree.Expression | null = null;
+ let delegate = false; // yield*
+
+ if ((parser.flags & Flags.NewLine) < 1) {
+ delegate = consumeOpt(parser, context | Context.AllowRegExp, Token.Multiply);
+ if (parser.token & (Token.Contextual | Token.IsExpressionStart) || delegate) {
+ argument = parseExpression(parser, context, 1, 0, 0, parser.tokenPos, parser.linePos, parser.colPos);
+ }
+ }
+
+ parser.assignable = AssignmentKind.CannotAssign;
+
+ return finishNode(parser, context, start, line, column, {
+ type: 'YieldExpression',
+ argument,
+ delegate
+ });
+ }
+
+ if (context & Context.Strict) report(parser, Errors.DisallowedInContext, 'yield');
+
+ return parseIdentifierOrArrow(parser, context, start, line, column);
+}
+
+/**
+ * Parse await expression
+ *
+ * @param parser Parser object
+ * @param context Context masks
+ * @param inNew
+ */
+export function parseAwaitExpression(
+ parser: ParserState,
+ context: Context,
+ inNew: 0 | 1,
+ inGroup: 0 | 1,
+ start: number,
+ line: number,
+ column: number
+): ESTree.IdentifierOrExpression | ESTree.AwaitExpression {
+ if (inGroup) parser.destructible |= DestructuringKind.Await;
+ if (context & Context.InAwaitContext || (context & Context.Module && context & Context.InGlobal)) {
+ if (inNew) report(parser, Errors.Unexpected);
+
+ if (context & Context.InArgumentList) {
+ reportMessageAt(parser.index, parser.line, parser.index, Errors.AwaitInParameter);
+ }
+
+ nextToken(parser, context | Context.AllowRegExp);
+
+ const argument = parseLeftHandSideExpression(
+ parser,
+ context,
+ 0,
+ 0,
+ 1,
+ parser.tokenPos,
+ parser.linePos,
+ parser.colPos
+ );
+
+ if (parser.token === Token.Exponentiate) report(parser, Errors.InvalidExponentiationLHS);
+
+ parser.assignable = AssignmentKind.CannotAssign;
+
+ return finishNode(parser, context, start, line, column, {
+ type: 'AwaitExpression',
+ argument
+ });
+ }
+
+ if (context & Context.Module) report(parser, Errors.AwaitOutsideAsync);
+ return parseIdentifierOrArrow(parser, context, start, line, column);
+}
+
+/**
+ * Parses function body
+ *
+ * @param parser Parser object
+ * @param context Context masks
+ * @param scope Scope object | null
+ * @param origin Binding origin
+ * @param firstRestricted
+ * @param scopeError
+ */
+export function parseFunctionBody(
+ parser: ParserState,
+ context: Context,
+ scope: ScopeState | undefined,
+ origin: Origin,
+ firstRestricted: Token | undefined,
+ scopeError: any
+): ESTree.BlockStatement {
+ const { tokenPos, linePos, colPos } = parser;
+
+ consume(parser, context | Context.AllowRegExp, Token.LeftBrace);
+
+ const body: ESTree.Statement[] = [];
+ const prevContext = context;
+
+ if (parser.token !== Token.RightBrace) {
+ while (parser.token === Token.StringLiteral) {
+ const { index, tokenPos, tokenValue, token } = parser;
+ const expr = parseLiteral(parser, context);
+ if (isValidStrictMode(parser, index, tokenPos, tokenValue)) {
+ context |= Context.Strict;
+ // TC39 deemed "use strict" directives to be an error when occurring
+ // in the body of a function with non-simple parameter list, on
+ // 29/7/2015. https://goo.gl/ueA7Ln
+ if (parser.flags & Flags.SimpleParameterList) {
+ reportMessageAt(parser.index, parser.line, parser.tokenPos, Errors.IllegalUseStrict);
+ }
+
+ if (parser.flags & Flags.Octals) {
+ reportMessageAt(parser.index, parser.line, parser.tokenPos, Errors.StrictOctalLiteral);
+ }
+ }
+ body.push(parseDirective(parser, context, expr, token, tokenPos, parser.linePos, parser.colPos));
+ }
+ if (context & Context.Strict) {
+ if (firstRestricted) {
+ if ((firstRestricted & Token.IsEvalOrArguments) === Token.IsEvalOrArguments) {
+ report(parser, Errors.StrictEvalArguments);
+ }
+ if ((firstRestricted & Token.FutureReserved) === Token.FutureReserved) {
+ report(parser, Errors.StrictFunctionName);
+ }
+ }
+ if (parser.flags & Flags.StrictEvalArguments) report(parser, Errors.StrictEvalArguments);
+ if (parser.flags & Flags.HasStrictReserved) report(parser, Errors.UnexpectedStrictReserved);
+ }
+
+ if (
+ context & Context.OptionsLexical &&
+ scope &&
+ scopeError !== void 0 &&
+ (prevContext & Context.Strict) < 1 &&
+ (context & Context.InGlobal) < 1
+ ) {
+ reportScopeError(scopeError);
+ }
+ }
+
+ parser.flags =
+ (parser.flags | Flags.StrictEvalArguments | Flags.HasStrictReserved | Flags.Octals) ^
+ (Flags.StrictEvalArguments | Flags.HasStrictReserved | Flags.Octals);
+
+ parser.destructible = (parser.destructible | DestructuringKind.Yield) ^ DestructuringKind.Yield;
+
+ while (parser.token !== Token.RightBrace) {
+ body.push(parseStatementListItem(parser, context, scope, Origin.TopLevel, {}) as ESTree.Statement);
+ }
+
+ consume(
+ parser,
+ origin & (Origin.Arrow | Origin.Declaration) ? context | Context.AllowRegExp : context,
+ Token.RightBrace
+ );
+
+ parser.flags &= ~(Flags.SimpleParameterList | Flags.Octals);
+
+ if (parser.token === Token.Assign) report(parser, Errors.CantAssignTo);
+
+ return finishNode(parser, context, tokenPos, linePos, colPos, {
+ type: 'BlockStatement',
+ body
+ });
+}
+
+/**
+ * Parse super expression
+ *
+ * @param parser Parser object
+ * @param context Context masks
+ */
+export function parseSuperExpression(
+ parser: ParserState,
+ context: Context,
+ start: number,
+ line: number,
+ column: number
+): ESTree.Super {
+ nextToken(parser, context);
+
+ switch (parser.token) {
+ case Token.QuestionMarkPeriod:
+ report(parser, Errors.OptionalChainingNoSuper);
+ case Token.LeftParen: {
+ // The super property has to be within a class constructor
+ if ((context & Context.SuperCall) < 1) report(parser, Errors.SuperNoConstructor);
+ if (context & Context.InClass) report(parser, Errors.UnexpectedPrivateField);
+ parser.assignable = AssignmentKind.CannotAssign;
+ break;
+ }
+ case Token.LeftBracket:
+ case Token.Period: {
+ // new super() is never allowed.
+ // super() is only allowed in derived constructor
+ if ((context & Context.SuperProperty) < 1) report(parser, Errors.InvalidSuperProperty);
+ if (context & Context.InClass) report(parser, Errors.UnexpectedPrivateField);
+ parser.assignable = AssignmentKind.Assignable;
+ break;
+ }
+ default:
+ report(parser, Errors.UnexpectedToken, 'super');
+ }
+
+ return finishNode(parser, context, start, line, column, { type: 'Super' });
+}
+
+/**
+ * Parses left hand side
+ *
+ * @param parser Parser object
+ * @param context Context masks
+ * @param canAssign
+ * @param start
+ * @param line
+ * @param column
+ */
+export function parseLeftHandSideExpression(
+ parser: ParserState,
+ context: Context,
+ canAssign: 0 | 1,
+ inGroup: 0 | 1,
+ isLHS: 0 | 1,
+ start: number,
+ line: number,
+ column: number
+): ESTree.Expression {
+ // LeftHandSideExpression ::
+ // (PrimaryExpression | MemberExpression) ...
+
+ const expression = parsePrimaryExpression(
+ parser,
+ context,
+ BindingKind.Empty,
+ 0,
+ canAssign,
+ 0,
+ inGroup,
+ isLHS,
+ start,
+ line,
+ column
+ );
+
+ return parseMemberOrUpdateExpression(parser, context, expression, inGroup, 0, start, line, column);
+}
+
+/**
+ * Parse update expression
+ *
+ * @param parser Parser object
+ * @param context Context masks
+ * @param inNew
+ * @param start
+ * @param line
+ * @param column
+ */
+function parseUpdateExpression(
+ parser: ParserState,
+ context: Context,
+ expr: ESTree.Expression,
+ start: number,
+ line: number,
+ column: number
+) {
+ if (parser.assignable & AssignmentKind.CannotAssign) report(parser, Errors.InvalidIncDecTarget);
+
+ const { token } = parser;
+
+ nextToken(parser, context);
+
+ parser.assignable = AssignmentKind.CannotAssign;
+
+ return finishNode(parser, context, start, line, column, {
+ type: 'UpdateExpression',
+ argument: expr,
+ operator: KeywordDescTable[token & Token.Type] as ESTree.UpdateOperator,
+ prefix: false
+ });
+}
+/**
+ * Parses member or update expression
+ *
+ * @param parser Parser object
+ * @param context Context masks
+ * @param expr ESTree AST node
+ * @param inGroup
+ * @param start
+ * @param line
+ * @param column
+ */
+export function parseMemberOrUpdateExpression(
+ parser: ParserState,
+ context: Context,
+ expr: ESTree.Expression,
+ inGroup: 0 | 1,
+ inChain: 0 | 1,
+ start: number,
+ line: number,
+ column: number
+): any {
+ if ((parser.token & Token.IsUpdateOp) === Token.IsUpdateOp && (parser.flags & Flags.NewLine) < 1) {
+ expr = parseUpdateExpression(parser, context, expr, start, line, column);
+ } else if ((parser.token & Token.IsMemberOrCallExpression) === Token.IsMemberOrCallExpression) {
+ context = (context | Context.DisallowIn | Context.InGlobal) ^ (Context.DisallowIn | Context.InGlobal);
+
+ switch (parser.token) {
+ /* Property */
+ case Token.Period: {
+ nextToken(parser, context | Context.AllowEscapedKeyword);
+
+ parser.assignable = AssignmentKind.Assignable;
+
+ const property = parsePropertyOrPrivatePropertyName(parser, context);
+
+ expr = finishNode(parser, context, start, line, column, {
+ type: 'MemberExpression',
+ object: expr,
+ computed: false,
+ property
+ });
+ break;
+ }
+
+ /* Property */
+ case Token.LeftBracket: {
+ let restoreHasOptionalChaining = false;
+ if ((parser.flags & Flags.HasOptionalChaining) === Flags.HasOptionalChaining) {
+ restoreHasOptionalChaining = true;
+ parser.flags = (parser.flags | Flags.HasOptionalChaining) ^ Flags.HasOptionalChaining;
+ }
+
+ nextToken(parser, context | Context.AllowRegExp);
+
+ const { tokenPos, linePos, colPos } = parser;
+ const property = parseExpressions(parser, context, inGroup, 1, tokenPos, linePos, colPos);
+
+ consume(parser, context, Token.RightBracket);
+
+ parser.assignable = AssignmentKind.Assignable;
+
+ expr = finishNode(parser, context, start, line, column, {
+ type: 'MemberExpression',
+ object: expr,
+ computed: true,
+ property
+ });
+
+ if (restoreHasOptionalChaining) {
+ parser.flags |= Flags.HasOptionalChaining;
+ }
+ break;
+ }
+
+ /* Call */
+ case Token.LeftParen: {
+ if ((parser.flags & Flags.DisallowCall) === Flags.DisallowCall) {
+ parser.flags = (parser.flags | Flags.DisallowCall) ^ Flags.DisallowCall;
+ return expr;
+ }
+
+ let restoreHasOptionalChaining = false;
+ if ((parser.flags & Flags.HasOptionalChaining) === Flags.HasOptionalChaining) {
+ restoreHasOptionalChaining = true;
+ parser.flags = (parser.flags | Flags.HasOptionalChaining) ^ Flags.HasOptionalChaining;
+ }
+
+ const args = parseArguments(parser, context, inGroup);
+
+ parser.assignable = AssignmentKind.CannotAssign;
+
+ expr = finishNode(parser, context, start, line, column, {
+ type: 'CallExpression',
+ callee: expr,
+ arguments: args
+ });
+
+ if (restoreHasOptionalChaining) {
+ parser.flags |= Flags.HasOptionalChaining;
+ }
+ break;
+ }
+
+ /* Optional chaining */
+ case Token.QuestionMarkPeriod: {
+ nextToken(parser, context); // skips: '?.'
+ parser.flags |= Flags.HasOptionalChaining;
+ parser.assignable = AssignmentKind.CannotAssign;
+ expr = parseOptionalChain(parser, context, expr, start, line, column);
+ break;
+ }
+
+ default:
+ if ((parser.flags & Flags.HasOptionalChaining) === Flags.HasOptionalChaining) {
+ report(parser, Errors.OptionalChainingNoTemplate);
+ }
+ /* Tagged Template */
+ parser.assignable = AssignmentKind.CannotAssign;
+
+ expr = finishNode(parser, context, start, line, column, {
+ type: 'TaggedTemplateExpression',
+ tag: expr,
+ quasi:
+ parser.token === Token.TemplateContinuation
+ ? parseTemplate(parser, context | Context.TaggedTemplate)
+ : parseTemplateLiteral(parser, context, parser.tokenPos, parser.linePos, parser.colPos)
+ });
+ }
+
+ expr = parseMemberOrUpdateExpression(parser, context, expr, 0, 1, start, line, column);
+ }
+
+ // Finalize ChainExpression
+ // FIXME: current implementation does not invalidate destructuring like `({ a: x?.obj['a'] } = {})`
+ if (inChain === 0 && (parser.flags & Flags.HasOptionalChaining) === Flags.HasOptionalChaining) {
+ parser.flags = (parser.flags | Flags.HasOptionalChaining) ^ Flags.HasOptionalChaining;
+
+ expr = finishNode(parser, context, start, line, column, {
+ type: 'ChainExpression',
+ expression: expr as ESTree.CallExpression | ESTree.MemberExpression
+ });
+ }
+
+ return expr;
+}
+
+/**
+ * Parses optional chain
+ *
+ * @param parser Parser object
+ * @param context Context masks
+ * @param expr ESTree AST node
+ */
+export function parseOptionalChain(
+ parser: ParserState,
+ context: Context,
+ expr: ESTree.Expression,
+ start: number,
+ line: number,
+ column: number
+): ESTree.MemberExpression | ESTree.CallExpression {
+ let restoreHasOptionalChaining = false;
+ let node;
+ if (parser.token === Token.LeftBracket || parser.token === Token.LeftParen) {
+ if ((parser.flags & Flags.HasOptionalChaining) === Flags.HasOptionalChaining) {
+ restoreHasOptionalChaining = true;
+ parser.flags = (parser.flags | Flags.HasOptionalChaining) ^ Flags.HasOptionalChaining;
+ }
+ }
+ if (parser.token === Token.LeftBracket) {
+ nextToken(parser, context | Context.AllowRegExp);
+ const { tokenPos, linePos, colPos } = parser;
+ const property = parseExpressions(parser, context, 0, 1, tokenPos, linePos, colPos);
+ consume(parser, context, Token.RightBracket);
+ parser.assignable = AssignmentKind.CannotAssign;
+ node = finishNode(parser, context, start, line, column, {
+ type: 'MemberExpression',
+ object: expr,
+ computed: true,
+ optional: true,
+ property
+ });
+ } else if (parser.token === Token.LeftParen) {
+ const args = parseArguments(parser, context, 0);
+
+ parser.assignable = AssignmentKind.CannotAssign;
+
+ node = finishNode(parser, context, start, line, column, {
+ type: 'CallExpression',
+ callee: expr,
+ arguments: args,
+ optional: true
+ });
+ } else {
+ if ((parser.token & (Token.IsIdentifier | Token.Keyword)) < 1) report(parser, Errors.InvalidDotProperty);
+ const property = parseIdentifier(parser, context, 0);
+ parser.assignable = AssignmentKind.CannotAssign;
+ node = finishNode(parser, context, start, line, column, {
+ type: 'MemberExpression',
+ object: expr,
+ computed: false,
+ optional: true,
+ property
+ });
+ }
+
+ if (restoreHasOptionalChaining) {
+ parser.flags |= Flags.HasOptionalChaining;
+ }
+ return node;
+}
+
+/**
+ * Parses property or private property name
+ *
+ * @param parser Parser object
+ * @param context Context masks
+ */
+export function parsePropertyOrPrivatePropertyName(parser: ParserState, context: Context): any {
+ if ((parser.token & (Token.IsIdentifier | Token.Keyword)) < 1 && parser.token !== Token.PrivateField) {
+ report(parser, Errors.InvalidDotProperty);
+ }
+
+ return context & Context.OptionsNext && parser.token === Token.PrivateField
+ ? parsePrivateIdentifier(parser, context, parser.tokenPos, parser.linePos, parser.colPos)
+ : parseIdentifier(parser, context, 0);
+}
+
+/**
+ * Parse update expression
+ *
+ * @param parser Parser object
+ * @param context Context masks
+ * @param inNew
+ * @param start
+ * @param line
+ * @param column
+ */
+export function parseUpdateExpressionPrefixed(
+ parser: ParserState,
+ context: Context,
+ inNew: 0 | 1,
+ isLHS: 0 | 1,
+ start: number,
+ line: number,
+ column: number
+): ESTree.UpdateExpression {
+ // UpdateExpression ::
+ // LeftHandSideExpression ('++' | '--')?
+
+ if (inNew) report(parser, Errors.InvalidIncDecNew);
+ if (!isLHS) report(parser, Errors.Unexpected);
+
+ const { token } = parser;
+
+ nextToken(parser, context | Context.AllowRegExp);
+
+ const arg = parseLeftHandSideExpression(parser, context, 0, 0, 1, parser.tokenPos, parser.linePos, parser.colPos);
+
+ if (parser.assignable & AssignmentKind.CannotAssign) {
+ report(parser, Errors.InvalidIncDecTarget);
+ }
+
+ parser.assignable = AssignmentKind.CannotAssign;
+
+ return finishNode(parser, context, start, line, column, {
+ type: 'UpdateExpression',
+ argument: arg,
+ operator: KeywordDescTable[token & Token.Type] as ESTree.UpdateOperator,
+ prefix: true
+ });
+}
+
+/**
+ * Parses expressions such as a literal expression
+ * and update expression.
+ *
+ * @param parser Parser object
+ * @param context Context masks
+ * @param kind Binding kind
+ * @param inNew
+ * @param canAssign
+ * @param isPattern
+ * @param inGroup
+ * @param start
+ * @param line
+ * @param column
+ */
+
+export function parsePrimaryExpression(
+ parser: ParserState,
+ context: Context,
+ kind: BindingKind,
+ inNew: 0 | 1,
+ canAssign: 0 | 1,
+ isPattern: 0 | 1,
+ inGroup: 0 | 1,
+ isLHS: 0 | 1,
+ start: number,
+ line: number,
+ column: number
+): any {
+ // PrimaryExpression ::
+ // 'this'
+ // 'null'
+ // 'true'
+ // 'false'
+ // Identifier
+ // Number
+ // String
+ // BigIntLiteral
+ // ArrayLiteral
+ // ObjectLiteral
+ // RegExpLiteral
+ // ClassLiteral
+ // ImportCall
+ // ImportMeta
+ // '(' Expression ')'
+ // TemplateLiteral
+ // AsyncFunctionLiteral
+ // YieldExpression
+ // AwaitExpression
+ // PrivateField
+ // Decorator
+ // Intrinsic
+ // JSX
+
+ if ((parser.token & Token.IsIdentifier) === Token.IsIdentifier) {
+ switch (parser.token) {
+ case Token.AwaitKeyword:
+ return parseAwaitExpression(parser, context, inNew, inGroup, start, line, column);
+ case Token.YieldKeyword:
+ return parseYieldExpression(parser, context, inGroup, canAssign, start, line, column);
+ case Token.AsyncKeyword:
+ return parseAsyncExpression(parser, context, inGroup, isLHS, canAssign, isPattern, inNew, start, line, column);
+ default: // ignore
+ }
+
+ const { token, tokenValue } = parser;
+
+ const expr = parseIdentifier(parser, context | Context.TaggedTemplate, isPattern);
+
+ if (parser.token === Token.Arrow) {
+ if (!isLHS) report(parser, Errors.Unexpected);
+ classifyIdentifier(parser, context, token, /* isArrow */ 1);
+ return parseArrowFromIdentifier(parser, context, tokenValue, expr, inNew, canAssign, 0, start, line, column);
+ }
+
+ if (context & Context.InClass && token === Token.Arguments) report(parser, Errors.InvalidClassFieldArgEval);
+
+ // Only a "simple validation" is done here to handle 'let' edge cases
+
+ if (token === Token.LetKeyword) {
+ if (context & Context.Strict) report(parser, Errors.StrictInvalidLetInExprPos);
+ if (kind & (BindingKind.Let | BindingKind.Const)) report(parser, Errors.InvalidLetConstBinding);
+ }
+
+ parser.assignable =
+ context & Context.Strict && (token & Token.IsEvalOrArguments) === Token.IsEvalOrArguments
+ ? AssignmentKind.CannotAssign
+ : AssignmentKind.Assignable;
+
+ return expr;
+ }
+
+ if ((parser.token & Token.IsStringOrNumber) === Token.IsStringOrNumber) {
+ return parseLiteral(parser, context);
+ }
+
+ // Update + Unary + Primary expression
+ switch (parser.token) {
+ case Token.Increment:
+ case Token.Decrement:
+ return parseUpdateExpressionPrefixed(parser, context, inNew, isLHS, start, line, column);
+ case Token.DeleteKeyword:
+ case Token.Negate:
+ case Token.Complement:
+ case Token.Add:
+ case Token.Subtract:
+ case Token.TypeofKeyword:
+ case Token.VoidKeyword:
+ return parseUnaryExpression(parser, context, isLHS, start, line, column, inGroup);
+ case Token.FunctionKeyword:
+ return parseFunctionExpression(parser, context, /* isAsync */ 0, inGroup, start, line, column);
+ case Token.LeftBrace:
+ return parseObjectLiteral(parser, context, canAssign ? 0 : 1, inGroup, start, line, column);
+ case Token.LeftBracket:
+ return parseArrayLiteral(parser, context, canAssign ? 0 : 1, inGroup, start, line, column);
+ case Token.LeftParen:
+ return parseParenthesizedExpression(
+ parser,
+ context,
+ canAssign,
+ BindingKind.ArgumentList,
+ Origin.None,
+ start,
+ line,
+ column
+ );
+ case Token.FalseKeyword:
+ case Token.TrueKeyword:
+ case Token.NullKeyword:
+ return parseNullOrTrueOrFalseLiteral(parser, context, start, line, column);
+ case Token.ThisKeyword:
+ return parseThisExpression(parser, context);
+ case Token.RegularExpression:
+ return parseRegExpLiteral(parser, context, start, line, column);
+ case Token.Decorator:
+ case Token.ClassKeyword:
+ return parseClassExpression(parser, context, inGroup, start, line, column);
+ case Token.SuperKeyword:
+ return parseSuperExpression(parser, context, start, line, column);
+ case Token.TemplateSpan:
+ return parseTemplateLiteral(parser, context, start, line, column);
+ case Token.TemplateContinuation:
+ return parseTemplate(parser, context);
+ case Token.NewKeyword:
+ return parseNewExpression(parser, context, inGroup, start, line, column);
+ case Token.BigIntLiteral:
+ return parseBigIntLiteral(parser, context, start, line, column);
+ case Token.PrivateField:
+ return parsePrivateIdentifier(parser, context, start, line, column);
+ case Token.ImportKeyword:
+ return parseImportCallOrMetaExpression(parser, context, inNew, inGroup, start, line, column);
+ case Token.LessThan:
+ if (context & Context.OptionsJSX)
+ return parseJSXRootElementOrFragment(parser, context, /*inJSXChild*/ 1, start, line, column);
+ default:
+ if (isValidIdentifier(context, parser.token)) return parseIdentifierOrArrow(parser, context, start, line, column);
+ report(parser, Errors.UnexpectedToken, KeywordDescTable[parser.token & Token.Type]);
+ }
+}
+
+/**
+ * Parses Import call expression
+ *
+ * @param parser Parser object
+ * @param context Context masks
+ * @param inGroup
+ * @param start
+ * @param line
+ * @param column
+ */
+function parseImportCallOrMetaExpression(
+ parser: ParserState,
+ context: Context,
+ inNew: 0 | 1,
+ inGroup: 0 | 1,
+ start: number,
+ line: number,
+ column: number
+): ESTree.ImportExpression | ESTree.MetaProperty {
+ // ImportCall[Yield, Await]:
+ // import(AssignmentExpression[+In, ?Yield, ?Await])
+
+ let expr: ESTree.Identifier | ESTree.ImportExpression = parseIdentifier(parser, context, 0);
+
+ if (parser.token === Token.Period) {
+ return parseImportMetaExpression(parser, context, expr, start, line, column);
+ }
+
+ if (inNew) report(parser, Errors.InvalidImportNew);
+
+ expr = parseImportExpression(parser, context, inGroup, start, line, column);
+
+ parser.assignable = AssignmentKind.CannotAssign;
+
+ return parseMemberOrUpdateExpression(parser, context, expr, inGroup, 0, start, line, column);
+}
+
+/**
+ * Parses import meta expression
+ *
+ * @param parser Parser object
+ * @param context Context masks
+ * @param meta ESTree AST node
+ * @param start
+ * @param line
+ * @param column
+ */
+
+export function parseImportMetaExpression(
+ parser: ParserState,
+ context: Context,
+ meta: ESTree.Identifier,
+ start: number,
+ line: number,
+ column: number
+): ESTree.MetaProperty {
+ if ((context & Context.Module) === 0) report(parser, Errors.ImportMetaOutsideModule);
+
+ nextToken(parser, context); // skips: '.'
+
+ if (parser.token !== Token.Meta && parser.tokenValue !== 'meta')
+ report(parser, Errors.UnexpectedToken, KeywordDescTable[parser.token & Token.Type]);
+
+ parser.assignable = AssignmentKind.CannotAssign;
+
+ return finishNode(parser, context, start, line, column, {
+ type: 'MetaProperty',
+ meta,
+ property: parseIdentifier(parser, context, 0)
+ });
+}
+
+/**
+ * Parses import expression
+ *
+ * @param parser Parser object
+ * @param context Context masks
+ * @param inGroup
+ * @param start
+ * @param line
+ * @param column
+ */
+
+export function parseImportExpression(
+ parser: ParserState,
+ context: Context,
+ inGroup: 0 | 1,
+ start: number,
+ line: number,
+ column: number
+): ESTree.ImportExpression {
+ consume(parser, context | Context.AllowRegExp, Token.LeftParen);
+
+ if (parser.token === Token.Ellipsis) report(parser, Errors.InvalidSpreadInImport);
+
+ const source = parseExpression(parser, context, 1, 0, inGroup, parser.tokenPos, parser.linePos, parser.colPos);
+
+ consume(parser, context, Token.RightParen);
+
+ return finishNode(parser, context, start, line, column, {
+ type: 'ImportExpression',
+ source
+ });
+}
+
+/**
+ * Parses BigInt literal
+ *
+ * @param parser Parser object
+ * @param context Context masks
+ */
+export function parseBigIntLiteral(
+ parser: ParserState,
+ context: Context,
+ start: number,
+ line: number,
+ column: number
+): ESTree.BigIntLiteral {
+ const { tokenRaw, tokenValue } = parser;
+ nextToken(parser, context);
+ parser.assignable = AssignmentKind.CannotAssign;
+ return finishNode(
+ parser,
+ context,
+ start,
+ line,
+ column,
+ context & Context.OptionsRaw
+ ? {
+ type: 'Literal',
+ value: tokenValue,
+ bigint: tokenRaw.slice(0, -1), // without the ending "n"
+ raw: tokenRaw
+ }
+ : {
+ type: 'Literal',
+ value: tokenValue,
+ bigint: tokenRaw.slice(0, -1) // without the ending "n"
+ }
+ );
+}
+
+/**
+ * Parses template literal
+ *
+ * @param parser Parser object
+ * @param context Context masks
+ */
+export function parseTemplateLiteral(
+ parser: ParserState,
+ context: Context,
+ start: number,
+ line: number,
+ column: number
+): ESTree.TemplateLiteral {
+ /**
+ * Template Literals
+ *
+ * Template ::
+ * FullTemplate
+ * TemplateHead
+ *
+ * FullTemplate ::
+ * `TemplateCharactersopt`
+ *
+ * TemplateHead ::
+ * ` TemplateCharactersopt ${
+ *
+ * TemplateSubstitutionTail ::
+ * TemplateMiddle
+ * TemplateTail
+ *
+ * TemplateMiddle ::
+ * } TemplateCharactersopt ${
+ *
+ * TemplateTail ::
+ * } TemplateCharactersopt `
+ *
+ * TemplateCharacters ::
+ * TemplateCharacter TemplateCharactersopt
+ *
+ * TemplateCharacter ::
+ * SourceCharacter but not one of ` or \ or $
+ * $ [lookahead not { ]
+ * \ EscapeSequence
+ * LineContinuation
+ */
+
+ parser.assignable = AssignmentKind.CannotAssign;
+ const { tokenValue, tokenRaw, tokenPos, linePos, colPos } = parser;
+ consume(parser, context, Token.TemplateSpan);
+ const quasis = [parseTemplateElement(parser, context, tokenValue, tokenRaw, tokenPos, linePos, colPos, true)];
+
+ return finishNode(parser, context, start, line, column, {
+ type: 'TemplateLiteral',
+ expressions: [],
+ quasis
+ });
+}
+
+/**
+ * Parses template
+ *
+ * @param parser Parser object
+ * @param context Context masks
+ */
+export function parseTemplate(parser: ParserState, context: Context): ESTree.TemplateLiteral {
+ context = (context | Context.DisallowIn) ^ Context.DisallowIn;
+
+ const { tokenValue, tokenRaw, tokenPos, linePos, colPos } = parser;
+ consume(parser, context | Context.AllowRegExp, Token.TemplateContinuation);
+ const quasis = [
+ parseTemplateElement(parser, context, tokenValue, tokenRaw, tokenPos, linePos, colPos, /* tail */ false)
+ ];
+
+ const expressions = [parseExpressions(parser, context, 0, 1, parser.tokenPos, parser.linePos, parser.colPos)];
+
+ if (parser.token !== Token.RightBrace) report(parser, Errors.InvalidTemplateContinuation);
+
+ while ((parser.token = scanTemplateTail(parser, context)) !== Token.TemplateSpan) {
+ const { tokenValue, tokenRaw, tokenPos, linePos, colPos } = parser;
+ consume(parser, context | Context.AllowRegExp, Token.TemplateContinuation);
+ quasis.push(
+ parseTemplateElement(parser, context, tokenValue, tokenRaw, tokenPos, linePos, colPos, /* tail */ false)
+ );
+
+ expressions.push(parseExpressions(parser, context, 0, 1, parser.tokenPos, parser.linePos, parser.colPos));
+ if (parser.token !== Token.RightBrace) report(parser, Errors.InvalidTemplateContinuation);
+ }
+
+ {
+ const { tokenValue, tokenRaw, tokenPos, linePos, colPos } = parser;
+ consume(parser, context, Token.TemplateSpan);
+ quasis.push(
+ parseTemplateElement(parser, context, tokenValue, tokenRaw, tokenPos, linePos, colPos, /* tail */ true)
+ );
+ }
+
+ return finishNode(parser, context, tokenPos, linePos, colPos, {
+ type: 'TemplateLiteral',
+ expressions,
+ quasis
+ });
+}
+
+/**
+ * Parses template spans
+ *
+ * @param parser Parser object
+ * @param tail
+ */
+export function parseTemplateElement(
+ parser: ParserState,
+ context: Context,
+ cooked: string | null,
+ raw: string,
+ start: number,
+ line: number,
+ col: number,
+ tail: boolean
+): ESTree.TemplateElement {
+ const node = finishNode(parser, context, start, line, col, {
+ type: 'TemplateElement',
+ value: {
+ cooked,
+ raw
+ },
+ tail
+ }) as ESTree.TemplateElement;
+
+ const tailSize = tail ? 1 : 2;
+
+ // Patch range
+ if (context & Context.OptionsRanges) {
+ // skip the front "`" or "}"
+ (node.start as number) += 1;
+ (node.range as [number, number])[0] += 1;
+ // skip the tail "`" or "${"
+ (node.end as number) -= tailSize;
+ (node.range as [number, number])[1] -= tailSize;
+ }
+
+ // Patch loc
+ if (context & Context.OptionsLoc) {
+ // skip the front "`" or "}"
+ (node.loc as ESTree.SourceLocation).start.column += 1;
+ // skip the tail "`" or "${"
+ (node.loc as ESTree.SourceLocation).end.column -= tailSize;
+ }
+
+ return node;
+}
+
+/**
+ * Parses spread element
+ *
+ * @param parser Parser object
+ * @param context Context masks
+ */
+function parseSpreadElement(
+ parser: ParserState,
+ context: Context,
+ start: number,
+ line: number,
+ column: number
+): ESTree.SpreadElement {
+ context = (context | Context.DisallowIn) ^ Context.DisallowIn;
+ consume(parser, context | Context.AllowRegExp, Token.Ellipsis);
+ const argument = parseExpression(parser, context, 1, 0, 0, parser.tokenPos, parser.linePos, parser.colPos);
+ parser.assignable = AssignmentKind.Assignable;
+ return finishNode(parser, context, start, line, column, {
+ type: 'SpreadElement',
+ argument
+ });
+}
+
+/**
+ * Parses arguments
+ *
+ * @param parser Parser object
+ * @param context Context masks
+ */
+export function parseArguments(
+ parser: ParserState,
+ context: Context,
+ inGroup: 0 | 1
+): (ESTree.SpreadElement | ESTree.Expression)[] {
+ // Arguments ::
+ // '(' (AssignmentExpression)*[','] ')'
+ nextToken(parser, context | Context.AllowRegExp);
+
+ const args: (ESTree.Expression | ESTree.SpreadElement)[] = [];
+
+ if (parser.token === Token.RightParen) {
+ nextToken(parser, context);
+ return args;
+ }
+
+ while (parser.token !== Token.RightParen) {
+ if (parser.token === Token.Ellipsis) {
+ args.push(parseSpreadElement(parser, context, parser.tokenPos, parser.linePos, parser.colPos));
+ } else {
+ args.push(parseExpression(parser, context, 1, 0, inGroup, parser.tokenPos, parser.linePos, parser.colPos));
+ }
+
+ if (parser.token !== Token.Comma) break;
+
+ nextToken(parser, context | Context.AllowRegExp);
+
+ if (parser.token === Token.RightParen) break;
+ }
+
+ consume(parser, context, Token.RightParen);
+
+ return args;
+}
+
+/**
+ * Parses an identifier expression
+ *
+ * @param parser Parser object
+ * @param context Context masks
+ */
+export function parseIdentifier(parser: ParserState, context: Context, isPattern: 0 | 1): ESTree.Identifier {
+ const { tokenValue, tokenPos, linePos, colPos } = parser;
+ nextToken(parser, context);
+
+ return finishNode(
+ parser,
+ context,
+ tokenPos,
+ linePos,
+ colPos,
+ context & Context.OptionsIdentifierPattern
+ ? {
+ type: 'Identifier',
+ name: tokenValue,
+ pattern: isPattern === 1
+ }
+ : {
+ type: 'Identifier',
+ name: tokenValue
+ }
+ );
+}
+
+/**
+ * Parses an literal expression such as string literal
+ *
+ * @param parser Parser object
+ * @param context Context masks
+ */
+export function parseLiteral(parser: ParserState, context: Context): ESTree.Literal {
+ const { tokenValue, tokenRaw, tokenPos, linePos, colPos } = parser;
+ if (parser.token === Token.BigIntLiteral) {
+ return parseBigIntLiteral(parser, context, tokenPos, linePos, colPos);
+ }
+
+ nextToken(parser, context);
+ parser.assignable = AssignmentKind.CannotAssign;
+ return finishNode(
+ parser,
+ context,
+ tokenPos,
+ linePos,
+ colPos,
+ context & Context.OptionsRaw
+ ? {
+ type: 'Literal',
+ value: tokenValue,
+ raw: tokenRaw
+ }
+ : {
+ type: 'Literal',
+ value: tokenValue
+ }
+ );
+}
+
+/**
+ * Parses null and boolean expressions
+ *
+ * @param parser Parser object
+ * @param context Context masks
+ */
+export function parseNullOrTrueOrFalseLiteral(
+ parser: ParserState,
+ context: Context,
+ start: number,
+ line: number,
+ column: number
+): ESTree.Literal {
+ const raw = KeywordDescTable[parser.token & Token.Type];
+ const value = parser.token === Token.NullKeyword ? null : raw === 'true';
+
+ nextToken(parser, context);
+ parser.assignable = AssignmentKind.CannotAssign;
+ return finishNode(
+ parser,
+ context,
+ start,
+ line,
+ column,
+ context & Context.OptionsRaw
+ ? {
+ type: 'Literal',
+ value,
+ raw
+ }
+ : {
+ type: 'Literal',
+ value
+ }
+ );
+}
+
+/**
+ * Parses this expression
+ *
+ * @param parser Parser object
+ * @param context Context masks
+ */
+export function parseThisExpression(parser: ParserState, context: Context): ESTree.ThisExpression {
+ const { tokenPos, linePos, colPos } = parser;
+ nextToken(parser, context);
+ parser.assignable = AssignmentKind.CannotAssign;
+ return finishNode(parser, context, tokenPos, linePos, colPos, {
+ type: 'ThisExpression'
+ });
+}
+
+/**
+ * Parse function declaration
+ *
+ * @param parser Parser object
+ * @param context Context masks
+ * @param scope
+ * @param allowGen
+ * @param ExportDefault
+ * @param isAsync
+ * @param start
+ */
+export function parseFunctionDeclaration(
+ parser: ParserState,
+ context: Context,
+ scope: ScopeState | undefined,
+ origin: Origin,
+ allowGen: 0 | 1,
+ flags: HoistedFunctionFlags,
+ isAsync: 0 | 1,
+ start: number,
+ line: number,
+ column: number
+): ESTree.FunctionDeclaration {
+ // FunctionDeclaration ::
+ // function BindingIdentifier ( FormalParameters ) { FunctionBody }
+ // function ( FormalParameters ) { FunctionBody }
+ //
+ // GeneratorDeclaration ::
+ // function * BindingIdentifier ( FormalParameters ) { FunctionBody }
+ // function * ( FormalParameters ) { FunctionBody }
+ //
+ // AsyncFunctionDeclaration ::
+ // async function BindingIdentifier ( FormalParameters ) { FunctionBody }
+ // async function ( FormalParameters ) { FunctionBody }
+ //
+ // AsyncGeneratorDeclaration ::
+ // async function * BindingIdentifier ( FormalParameters ) { FunctionBody }
+ // async function * ( FormalParameters ) { FunctionBody }
+
+ nextToken(parser, context | Context.AllowRegExp);
+
+ const isGenerator = allowGen ? optionalBit(parser, context, Token.Multiply) : 0;
+
+ let id: ESTree.Identifier | null = null;
+ let firstRestricted: Token | undefined;
+
+ // Create a new function scope
+ let functionScope = scope ? createScope() : void 0;
+
+ if (parser.token === Token.LeftParen) {
+ if ((flags & HoistedClassFlags.Hoisted) < 1) report(parser, Errors.DeclNoName, 'Function');
+ } else {
+ // In ES6, a function behaves as a lexical binding, except in
+ // a script scope, or the initial scope of eval or another function.
+ const kind =
+ origin & Origin.TopLevel && ((context & Context.InGlobal) < 1 || (context & Context.Module) < 1)
+ ? BindingKind.Variable
+ : BindingKind.FunctionLexical;
+
+ validateFunctionName(parser, context | ((context & 0b0000000000000000000_1100_00000000) << 11), parser.token);
+
+ if (scope) {
+ if (kind & BindingKind.Variable) {
+ addVarName(parser, context, scope as ScopeState, parser.tokenValue, kind);
+ } else {
+ addBlockName(parser, context, scope, parser.tokenValue, kind, origin);
+ }
+
+ functionScope = addChildScope(functionScope, ScopeKind.FunctionRoot);
+
+ if (flags) {
+ if (flags & HoistedClassFlags.Export) {
+ declareUnboundVariable(parser, parser.tokenValue);
+ }
+ }
+ }
+
+ firstRestricted = parser.token;
+
+ if (parser.token & Token.IsIdentifier) {
+ id = parseIdentifier(parser, context, 0);
+ } else {
+ report(parser, Errors.UnexpectedToken, KeywordDescTable[parser.token & Token.Type]);
+ }
+ }
+
+ context =
+ ((context | 0b0000001111011000000_0000_00000000) ^ 0b0000001111011000000_0000_00000000) |
+ Context.AllowNewTarget |
+ ((isAsync * 2 + isGenerator) << 21) |
+ (isGenerator ? 0 : Context.AllowEscapedKeyword);
+
+ if (scope) functionScope = addChildScope(functionScope, ScopeKind.FunctionParams);
+
+ const params = parseFormalParametersOrFormalList(
+ parser,
+ context | Context.InArgumentList,
+ functionScope,
+ 0,
+ BindingKind.ArgumentList
+ );
+
+ const body = parseFunctionBody(
+ parser,
+ (context | Context.InGlobal | Context.InSwitch | Context.InIteration) ^
+ (Context.InGlobal | Context.InSwitch | Context.InIteration),
+ scope ? addChildScope(functionScope, ScopeKind.FunctionBody) : functionScope,
+ Origin.Declaration,
+ firstRestricted,
+ scope ? (functionScope as ScopeState).scopeError : void 0
+ );
+
+ return finishNode(parser, context, start, line, column, {
+ type: 'FunctionDeclaration',
+ id,
+ params,
+ body,
+ async: isAsync === 1,
+ generator: isGenerator === 1
+ });
+}
+
+/**
+ * Parse function expression
+ *
+ * @param parser Parser object
+ * @param context Context masks
+ * @param isAsync
+ */
+export function parseFunctionExpression(
+ parser: ParserState,
+ context: Context,
+ isAsync: 0 | 1,
+ inGroup: 0 | 1,
+ start: number,
+ line: number,
+ column: number
+): ESTree.FunctionExpression {
+ // GeneratorExpression:
+ // function* BindingIdentifier [Yield][opt](FormalParameters[Yield]){ GeneratorBody }
+ //
+ // FunctionExpression:
+ // function BindingIdentifier[opt](FormalParameters){ FunctionBody }
+
+ nextToken(parser, context | Context.AllowRegExp);
+
+ const isGenerator = optionalBit(parser, context, Token.Multiply);
+ const generatorAndAsyncFlags = (isAsync * 2 + isGenerator) << 21;
+
+ let id: ESTree.Identifier | null = null;
+ let firstRestricted: Token | undefined;
+
+ // Create a new function scope
+ let scope = context & Context.OptionsLexical ? createScope() : void 0;
+
+ if ((parser.token & (Token.IsIdentifier | Token.Keyword | Token.FutureReserved)) > 0) {
+ validateFunctionName(parser, ((context | 0x1ec0000) ^ 0x1ec0000) | generatorAndAsyncFlags, parser.token);
+
+ if (scope) scope = addChildScope(scope, ScopeKind.FunctionRoot);
+
+ firstRestricted = parser.token;
+ id = parseIdentifier(parser, context, /* isPattern */ 0);
+ }
+
+ context =
+ ((context | 0b0000001111011000000_0000_00000000) ^ 0b0000001111011000000_0000_00000000) |
+ Context.AllowNewTarget |
+ generatorAndAsyncFlags |
+ (isGenerator ? 0 : Context.AllowEscapedKeyword);
+
+ if (scope) scope = addChildScope(scope, ScopeKind.FunctionParams);
+
+ const params = parseFormalParametersOrFormalList(
+ parser,
+ context | Context.InArgumentList,
+ scope,
+ inGroup,
+ BindingKind.ArgumentList
+ );
+
+ const body = parseFunctionBody(
+ parser,
+ context & ~(0x8001000 | Context.InGlobal | Context.InSwitch | Context.InIteration | Context.InClass),
+ scope ? addChildScope(scope, ScopeKind.FunctionBody) : scope,
+ 0,
+ firstRestricted,
+ void 0
+ );
+
+ parser.assignable = AssignmentKind.CannotAssign;
+
+ return finishNode(parser, context, start, line, column, {
+ type: 'FunctionExpression',
+ id,
+ params,
+ body,
+ async: isAsync === 1,
+ generator: isGenerator === 1
+ });
+}
+
+/**
+ * Parses array literal expression
+ *
+ * @param parser Parser object
+ * @param context Context masks
+ * @param skipInitializer
+ */
+function parseArrayLiteral(
+ parser: ParserState,
+ context: Context,
+ skipInitializer: 0 | 1,
+ inGroup: 0 | 1,
+ start: number,
+ line: number,
+ column: number
+): ESTree.ArrayExpression {
+ /* ArrayLiteral :
+ * [ Elisionopt ]
+ * [ ElementList ]
+ * [ ElementList , Elisionopt ]
+ *
+ * ElementList :
+ * Elisionopt AssignmentExpression
+ * Elisionopt ... AssignmentExpression
+ * ElementList , Elisionopt AssignmentExpression
+ * ElementList , Elisionopt SpreadElement
+ *
+ * Elision :
+ * ,
+ * Elision ,
+ *
+ * SpreadElement :
+ * ... AssignmentExpression
+ *
+ */
+ const expr = parseArrayExpressionOrPattern(
+ parser,
+ context,
+ void 0,
+ skipInitializer,
+ inGroup,
+ 0,
+ BindingKind.Empty,
+ Origin.None,
+ start,
+ line,
+ column
+ );
+
+ if (context & Context.OptionsWebCompat && parser.destructible & DestructuringKind.SeenProto) {
+ report(parser, Errors.DuplicateProto);
+ }
+
+ if (parser.destructible & DestructuringKind.HasToDestruct) {
+ report(parser, Errors.InvalidShorthandPropInit);
+ }
+
+ return expr as ESTree.ArrayExpression;
+}
+
+/**
+ * Parse array expression or pattern
+ *
+ * @param parser Parser object
+ * @param context Context masks
+ * @param skipInitializer
+ * @param BindingKind
+ */
+
+export function parseArrayExpressionOrPattern(
+ parser: ParserState,
+ context: Context,
+ scope: ScopeState | undefined,
+ skipInitializer: 0 | 1,
+ inGroup: 0 | 1,
+ isPattern: 0 | 1,
+ kind: BindingKind,
+ origin: Origin,
+ start: number,
+ line: number,
+ column: number
+): ESTree.ArrayExpression | ESTree.ArrayPattern | ESTree.AssignmentExpression {
+ /* ArrayLiteral :
+ * [ Elisionopt ]
+ * [ ElementList ]
+ * [ ElementList , Elisionopt ]
+ *
+ * ElementList :
+ * Elisionopt AssignmentExpression
+ * Elisionopt ... AssignmentExpression
+ * ElementList , Elisionopt AssignmentExpression
+ * ElementList , Elisionopt SpreadElement
+ *
+ * Elision :
+ * ,
+ * Elision ,
+ *
+ * SpreadElement :
+ * ... AssignmentExpression
+ *
+ * ArrayAssignmentPattern[Yield] :
+ * [ Elisionopt AssignmentRestElement[?Yield]opt ]
+ * [ AssignmentElementList[?Yield] ]
+ * [ AssignmentElementList[?Yield] , Elisionopt AssignmentRestElement[?Yield]opt ]
+ *
+ * AssignmentRestElement[Yield] :
+ * ... DestructuringAssignmentTarget[?Yield]
+ *
+ * AssignmentElementList[Yield] :
+ * AssignmentElisionElement[?Yield]
+ * AssignmentElementList[?Yield] , AssignmentElisionElement[?Yield]
+ *
+ * AssignmentElisionElement[Yield] :
+ * Elisionopt AssignmentElement[?Yield]
+ *
+ * AssignmentElement[Yield] :
+ * DestructuringAssignmentTarget[?Yield] Initializer[In,?Yield]opt
+ *
+ * DestructuringAssignmentTarget[Yield] :
+ * LeftHandSideExpression[?Yield]
+ */
+
+ nextToken(parser, context | Context.AllowRegExp);
+
+ const elements: (ESTree.Identifier | ESTree.AssignmentExpression | null)[] = [];
+ let destructible: AssignmentKind | DestructuringKind = 0;
+
+ context = (context | Context.DisallowIn) ^ Context.DisallowIn;
+
+ while (parser.token !== Token.RightBracket) {
+ if (consumeOpt(parser, context | Context.AllowRegExp, Token.Comma)) {
+ elements.push(null);
+ } else {
+ let left: any;
+
+ const { token, tokenPos, linePos, colPos, tokenValue } = parser;
+
+ if (token & Token.IsIdentifier) {
+ left = parsePrimaryExpression(parser, context, kind, 0, 1, 0, inGroup, 1, tokenPos, linePos, colPos);
+
+ if (parser.token === Token.Assign) {
+ if (parser.assignable & AssignmentKind.CannotAssign) report(parser, Errors.CantAssignTo);
+
+ nextToken(parser, context | Context.AllowRegExp);
+
+ if (scope) addVarOrBlock(parser, context, scope, tokenValue, kind, origin);
+
+ const right = parseExpression(parser, context, 1, 1, inGroup, parser.tokenPos, parser.linePos, parser.colPos);
+
+ left = finishNode(
+ parser,
+ context,
+ tokenPos,
+ linePos,
+ colPos,
+ isPattern
+ ? {
+ type: 'AssignmentPattern',
+ left,
+ right
+ }
+ : ({
+ type: 'AssignmentExpression',
+ operator: '=',
+ left,
+ right
+ } as any)
+ );
+
+ destructible |=
+ parser.destructible & DestructuringKind.Yield
+ ? DestructuringKind.Yield
+ : 0 | (parser.destructible & DestructuringKind.Await)
+ ? DestructuringKind.Await
+ : 0;
+ } else if (parser.token === Token.Comma || parser.token === Token.RightBracket) {
+ if (parser.assignable & AssignmentKind.CannotAssign) {
+ destructible |= DestructuringKind.CannotDestruct;
+ } else if (scope) {
+ addVarOrBlock(parser, context, scope, tokenValue, kind, origin);
+ }
+ destructible |=
+ parser.destructible & DestructuringKind.Yield
+ ? DestructuringKind.Yield
+ : 0 | (parser.destructible & DestructuringKind.Await)
+ ? DestructuringKind.Await
+ : 0;
+ } else {
+ destructible |=
+ kind & BindingKind.ArgumentList
+ ? DestructuringKind.Assignable
+ : (kind & BindingKind.Empty) < 1
+ ? DestructuringKind.CannotDestruct
+ : 0;
+
+ left = parseMemberOrUpdateExpression(parser, context, left, inGroup, 0, tokenPos, linePos, colPos);
+
+ if (parser.token !== Token.Comma && parser.token !== Token.RightBracket) {
+ if (parser.token !== Token.Assign) destructible |= DestructuringKind.CannotDestruct;
+ left = parseAssignmentExpression(parser, context, inGroup, isPattern, tokenPos, linePos, colPos, left);
+ } else if (parser.token !== Token.Assign) {
+ destructible |=
+ parser.assignable & AssignmentKind.CannotAssign
+ ? DestructuringKind.CannotDestruct
+ : DestructuringKind.Assignable;
+ }
+ }
+ } else if (token & Token.IsPatternStart) {
+ left =
+ parser.token === Token.LeftBrace
+ ? parseObjectLiteralOrPattern(
+ parser,
+ context,
+ scope,
+ 0,
+ inGroup,
+ isPattern,
+ kind,
+ origin,
+ tokenPos,
+ linePos,
+ colPos
+ )
+ : parseArrayExpressionOrPattern(
+ parser,
+ context,
+ scope,
+ 0,
+ inGroup,
+ isPattern,
+ kind,
+ origin,
+ tokenPos,
+ linePos,
+ colPos
+ );
+
+ destructible |= parser.destructible;
+
+ parser.assignable =
+ parser.destructible & DestructuringKind.CannotDestruct
+ ? AssignmentKind.CannotAssign
+ : AssignmentKind.Assignable;
+
+ if (parser.token === Token.Comma || parser.token === Token.RightBracket) {
+ if (parser.assignable & AssignmentKind.CannotAssign) {
+ destructible |= DestructuringKind.CannotDestruct;
+ }
+ } else if (parser.destructible & DestructuringKind.HasToDestruct) {
+ report(parser, Errors.InvalidDestructuringTarget);
+ } else {
+ left = parseMemberOrUpdateExpression(parser, context, left, inGroup, 0, tokenPos, linePos, colPos);
+ destructible = parser.assignable & AssignmentKind.CannotAssign ? DestructuringKind.CannotDestruct : 0;
+
+ if (parser.token !== Token.Comma && parser.token !== Token.RightBracket) {
+ left = parseAssignmentExpression(parser, context, inGroup, isPattern, tokenPos, linePos, colPos, left);
+ } else if (parser.token !== Token.Assign) {
+ destructible |=
+ parser.assignable & AssignmentKind.CannotAssign
+ ? DestructuringKind.CannotDestruct
+ : DestructuringKind.Assignable;
+ }
+ }
+ } else if (token === Token.Ellipsis) {
+ left = parseSpreadOrRestElement(
+ parser,
+ context,
+ scope,
+ Token.RightBracket,
+ kind,
+ origin,
+ 0,
+ inGroup,
+ isPattern,
+ tokenPos,
+ linePos,
+ colPos
+ );
+ destructible |= parser.destructible;
+ if (parser.token !== Token.Comma && parser.token !== Token.RightBracket)
+ report(parser, Errors.UnexpectedToken, KeywordDescTable[parser.token & Token.Type]);
+ } else {
+ left = parseLeftHandSideExpression(parser, context, 1, 0, 1, tokenPos, linePos, colPos);
+
+ if (parser.token !== Token.Comma && parser.token !== Token.RightBracket) {
+ left = parseAssignmentExpression(parser, context, inGroup, isPattern, tokenPos, linePos, colPos, left);
+ if ((kind & (BindingKind.Empty | BindingKind.ArgumentList)) < 1 && token === Token.LeftParen)
+ destructible |= DestructuringKind.CannotDestruct;
+ } else if (parser.assignable & AssignmentKind.CannotAssign) {
+ destructible |= DestructuringKind.CannotDestruct;
+ } else if (token === Token.LeftParen) {
+ destructible |=
+ parser.assignable & AssignmentKind.Assignable && kind & (BindingKind.Empty | BindingKind.ArgumentList)
+ ? DestructuringKind.Assignable
+ : DestructuringKind.CannotDestruct;
+ }
+ }
+
+ elements.push(left);
+
+ if (consumeOpt(parser, context | Context.AllowRegExp, Token.Comma)) {
+ if (parser.token === Token.RightBracket) break;
+ } else break;
+ }
+ }
+
+ consume(parser, context, Token.RightBracket);
+
+ const node = finishNode(parser, context, start, line, column, {
+ type: isPattern ? 'ArrayPattern' : 'ArrayExpression',
+ elements
+ } as any);
+
+ if (!skipInitializer && parser.token & Token.IsAssignOp) {
+ return parseArrayOrObjectAssignmentPattern(
+ parser,
+ context,
+ destructible,
+ inGroup,
+ isPattern,
+ start,
+ line,
+ column,
+ node
+ );
+ }
+
+ parser.destructible = destructible;
+
+ return node;
+}
+
+/**
+ * Parses array or object assignment pattern
+ *
+ * @param parser Parser object
+ * @param context Context masks
+ * @param destructible
+ * @param inGroup
+ * @param start Start index
+ * @param line Start line
+ * @param column Start of column
+ * @param node ESTree AST node
+ */
+
+function parseArrayOrObjectAssignmentPattern(
+ parser: ParserState,
+ context: Context,
+ destructible: AssignmentKind | DestructuringKind,
+ inGroup: 0 | 1,
+ isPattern: 0 | 1,
+ start: number,
+ line: number,
+ column: number,
+ node: ESTree.ArrayExpression | ESTree.ObjectExpression | ESTree.ObjectPattern
+): ESTree.AssignmentExpression {
+ // 12.15.5 Destructuring Assignment
+ //
+ // AssignmentElement[Yield, Await]:
+ // DestructuringAssignmentTarget[?Yield, ?Await]
+ // DestructuringAssignmentTarget[?Yield, ?Await] Initializer[+In, ?Yield, ?Await]
+ //
+
+ if (parser.token !== Token.Assign) report(parser, Errors.CantAssignTo);
+
+ nextToken(parser, context | Context.AllowRegExp);
+
+ if (destructible & DestructuringKind.CannotDestruct) report(parser, Errors.CantAssignTo);
+
+ if (!isPattern) reinterpretToPattern(parser, node);
+
+ const { tokenPos, linePos, colPos } = parser;
+
+ const right = parseExpression(parser, context, 1, 1, inGroup, tokenPos, linePos, colPos);
+
+ parser.destructible =
+ ((destructible | DestructuringKind.SeenProto | DestructuringKind.HasToDestruct) ^
+ (DestructuringKind.HasToDestruct | DestructuringKind.SeenProto)) |
+ (parser.destructible & DestructuringKind.Await ? DestructuringKind.Await : 0) |
+ (parser.destructible & DestructuringKind.Yield ? DestructuringKind.Yield : 0);
+
+ return finishNode(
+ parser,
+ context,
+ start,
+ line,
+ column,
+ isPattern
+ ? {
+ type: 'AssignmentPattern',
+ left: node,
+ right
+ }
+ : ({
+ type: 'AssignmentExpression',
+ left: node,
+ operator: '=',
+ right
+ } as any)
+ );
+}
+
+/**
+ * Parses rest or spread element
+ *
+ * @param parser Parser object
+ * @param context Context masks
+ * @param closingToken
+ * @param type Binding kind
+ * @param origin Binding origin
+ * @param isAsync
+ * @param isGroup
+ * @param start Start index
+ * @param line Start line
+ * @param column Start of column
+ */
+function parseSpreadOrRestElement(
+ parser: ParserState,
+ context: Context,
+ scope: ScopeState | undefined,
+ closingToken: Token,
+ kind: BindingKind,
+ origin: Origin,
+ isAsync: 0 | 1,
+ inGroup: 0 | 1,
+ isPattern: 0 | 1,
+ start: number,
+ line: number,
+ column: number
+): ESTree.SpreadElement | ESTree.RestElement {
+ nextToken(parser, context | Context.AllowRegExp); // skip '...'
+
+ let argument: ESTree.Expression | null = null;
+ let destructible: AssignmentKind | DestructuringKind = DestructuringKind.None;
+
+ let { token, tokenValue, tokenPos, linePos, colPos } = parser;
+
+ if (token & (Token.Keyword | Token.IsIdentifier)) {
+ parser.assignable = AssignmentKind.Assignable;
+
+ argument = parsePrimaryExpression(parser, context, kind, 0, 1, 0, inGroup, 1, tokenPos, linePos, colPos);
+
+ token = parser.token;
+
+ argument = parseMemberOrUpdateExpression(
+ parser,
+ context,
+ argument as ESTree.Expression,
+ inGroup,
+ 0,
+ tokenPos,
+ linePos,
+ colPos
+ );
+
+ if (parser.token !== Token.Comma && parser.token !== closingToken) {
+ if (parser.assignable & AssignmentKind.CannotAssign && parser.token === Token.Assign)
+ report(parser, Errors.InvalidDestructuringTarget);
+
+ destructible |= DestructuringKind.CannotDestruct;
+
+ argument = parseAssignmentExpression(parser, context, inGroup, isPattern, tokenPos, linePos, colPos, argument);
+ }
+
+ if (parser.assignable & AssignmentKind.CannotAssign) {
+ destructible |= DestructuringKind.CannotDestruct;
+ } else if (token === closingToken || token === Token.Comma) {
+ if (scope) addVarOrBlock(parser, context, scope, tokenValue, kind, origin);
+ } else {
+ destructible |= DestructuringKind.Assignable;
+ }
+
+ destructible |= parser.destructible & DestructuringKind.Await ? DestructuringKind.Await : 0;
+ } else if (token === closingToken) {
+ report(parser, Errors.RestMissingArg);
+ } else if (token & Token.IsPatternStart) {
+ argument =
+ parser.token === Token.LeftBrace
+ ? parseObjectLiteralOrPattern(
+ parser,
+ context,
+ scope,
+ 1,
+ inGroup,
+ isPattern,
+ kind,
+ origin,
+ tokenPos,
+ linePos,
+ colPos
+ )
+ : parseArrayExpressionOrPattern(
+ parser,
+ context,
+ scope,
+ 1,
+ inGroup,
+ isPattern,
+ kind,
+ origin,
+ tokenPos,
+ linePos,
+ colPos
+ );
+
+ token = parser.token;
+
+ if (token !== Token.Assign && token !== closingToken && token !== Token.Comma) {
+ if (parser.destructible & DestructuringKind.HasToDestruct) report(parser, Errors.InvalidDestructuringTarget);
+
+ argument = parseMemberOrUpdateExpression(parser, context, argument, inGroup, 0, tokenPos, linePos, colPos);
+
+ destructible |= parser.assignable & AssignmentKind.CannotAssign ? DestructuringKind.CannotDestruct : 0;
+
+ if ((parser.token & Token.IsAssignOp) === Token.IsAssignOp) {
+ if (parser.token !== Token.Assign) destructible |= DestructuringKind.CannotDestruct;
+ argument = parseAssignmentExpression(parser, context, inGroup, isPattern, tokenPos, linePos, colPos, argument);
+ } else {
+ if ((parser.token & Token.IsBinaryOp) === Token.IsBinaryOp) {
+ argument = parseBinaryExpression(parser, context, 1, tokenPos, linePos, colPos, 4, token, argument as any);
+ }
+ if (consumeOpt(parser, context | Context.AllowRegExp, Token.QuestionMark)) {
+ argument = parseConditionalExpression(parser, context, argument as any, tokenPos, linePos, colPos);
+ }
+ destructible |=
+ parser.assignable & AssignmentKind.CannotAssign
+ ? DestructuringKind.CannotDestruct
+ : DestructuringKind.Assignable;
+ }
+ } else {
+ destructible |=
+ closingToken === Token.RightBrace && token !== Token.Assign
+ ? DestructuringKind.CannotDestruct
+ : parser.destructible;
+ }
+ } else {
+ destructible |= DestructuringKind.Assignable;
+
+ argument = parseLeftHandSideExpression(
+ parser,
+ context,
+ 1,
+ inGroup,
+ 1,
+ parser.tokenPos,
+ parser.linePos,
+ parser.colPos
+ );
+
+ const { token, tokenPos, linePos, colPos } = parser;
+
+ if (token === Token.Assign && token !== closingToken && token !== Token.Comma) {
+ if (parser.assignable & AssignmentKind.CannotAssign) report(parser, Errors.CantAssignTo);
+
+ argument = parseAssignmentExpression(parser, context, inGroup, isPattern, tokenPos, linePos, colPos, argument);
+
+ destructible |= DestructuringKind.CannotDestruct;
+ } else {
+ if (token === Token.Comma) {
+ destructible |= DestructuringKind.CannotDestruct;
+ } else if (token !== closingToken) {
+ argument = parseAssignmentExpression(parser, context, inGroup, isPattern, tokenPos, linePos, colPos, argument);
+ }
+
+ destructible |=
+ parser.assignable & AssignmentKind.Assignable ? DestructuringKind.Assignable : DestructuringKind.CannotDestruct;
+ }
+
+ parser.destructible = destructible;
+
+ if (parser.token !== closingToken && parser.token !== Token.Comma) report(parser, Errors.UnclosedSpreadElement);
+
+ return finishNode(parser, context, start, line, column, {
+ type: isPattern ? 'RestElement' : 'SpreadElement',
+ argument: argument as ESTree.SpreadArgument
+ } as any);
+ }
+
+ if (parser.token !== closingToken) {
+ if (kind & BindingKind.ArgumentList)
+ destructible |= isAsync ? DestructuringKind.CannotDestruct : DestructuringKind.Assignable;
+
+ if (consumeOpt(parser, context | Context.AllowRegExp, Token.Assign)) {
+ if (destructible & DestructuringKind.CannotDestruct) report(parser, Errors.CantAssignTo);
+
+ reinterpretToPattern(parser, argument);
+
+ const right = parseExpression(parser, context, 1, 1, inGroup, parser.tokenPos, parser.linePos, parser.colPos);
+
+ argument = finishNode(
+ parser,
+ context,
+ tokenPos,
+ linePos,
+ colPos,
+ isPattern
+ ? {
+ type: 'AssignmentPattern',
+ left: argument as ESTree.SpreadArgument,
+ right
+ }
+ : ({
+ type: 'AssignmentExpression',
+ left: argument as ESTree.SpreadArgument,
+ operator: '=',
+ right
+ } as any)
+ );
+
+ destructible = DestructuringKind.CannotDestruct;
+ } else {
+ // Note the difference between '|=' and '=' above
+ destructible |= DestructuringKind.CannotDestruct;
+ }
+ }
+
+ parser.destructible = destructible;
+
+ return finishNode(parser, context, start, line, column, {
+ type: isPattern ? 'RestElement' : 'SpreadElement',
+ argument: argument as ESTree.SpreadArgument
+ } as any);
+}
+
+/**
+ * Parses method definition
+ *
+ * @param parser Parser object
+ * @param context Context masks
+ * @param kind
+ * @param inGroup
+ * @param start Start index
+ * @param line Start line
+ * @param column Start of column
+ */
+export function parseMethodDefinition(
+ parser: ParserState,
+ context: Context,
+ kind: PropertyKind,
+ inGroup: 0 | 1,
+ start: number,
+ line: number,
+ column: number
+): ESTree.FunctionExpression {
+ const modifierFlags =
+ (kind & PropertyKind.Constructor) < 1 ? 0b0000001111010000000_0000_00000000 : 0b0000000111000000000_0000_00000000;
+
+ context =
+ ((context | modifierFlags) ^ modifierFlags) |
+ ((kind & 0b0000000000000000000_0000_01011000) << 18) |
+ 0b0000110000001000000_0000_00000000;
+
+ let scope = context & Context.OptionsLexical ? addChildScope(createScope(), ScopeKind.FunctionParams) : void 0;
+
+ const params = parseMethodFormals(
+ parser,
+ context | Context.InArgumentList,
+ scope,
+ kind,
+ BindingKind.ArgumentList,
+ inGroup
+ );
+
+ if (scope) scope = addChildScope(scope, ScopeKind.FunctionBody);
+
+ const body = parseFunctionBody(parser, context & ~(0x8001000 | Context.InGlobal), scope, Origin.None, void 0, void 0);
+
+ return finishNode(parser, context, start, line, column, {
+ type: 'FunctionExpression',
+ params,
+ body,
+ async: (kind & PropertyKind.Async) > 0,
+ generator: (kind & PropertyKind.Generator) > 0,
+ id: null
+ });
+}
+
+/**
+ * Parse object literal or object pattern
+ *
+ * @param parser Parser object
+ * @param context Context masks
+ * @param skipInitializer
+ * @param inGroup
+ * @param start Start index
+ * @param line Start line
+ * @param column Start of column
+
+ */
+function parseObjectLiteral(
+ parser: ParserState,
+ context: Context,
+ skipInitializer: 0 | 1,
+ inGroup: 0 | 1,
+ start: number,
+ line: number,
+ column: number
+): ESTree.ObjectExpression {
+ /**
+ * ObjectLiteral
+ * {}
+ * {PropertyDefinitionList }
+ *
+ * {PropertyDefinitionList }
+ *
+ * PropertyDefinitionList:
+ * PropertyDefinition
+ * PropertyDefinitionList, PropertyDefinition
+ *
+ * PropertyDefinition:
+ * { IdentifierReference }
+ * { CoverInitializedName }
+ * { PropertyName:AssignmentExpression }
+ *
+ * MethodDefinition:
+ * ...AssignmentExpression
+ *
+ * PropertyName:
+ * LiteralPropertyName
+ * ComputedPropertyName
+ * LiteralPropertyName:
+ * IdentifierName
+ * StringLiteral
+ * NumericLiteral
+ *
+ * ComputedPropertyName: AssignmentExpression
+ *
+ * CoverInitializedName:
+ * IdentifierReference , Initializer
+ *
+ * Initializer:
+ * =AssignmentExpression
+ */
+ const expr = parseObjectLiteralOrPattern(
+ parser,
+ context,
+ void 0,
+ skipInitializer,
+ inGroup,
+ 0,
+ BindingKind.Empty,
+ Origin.None,
+ start,
+ line,
+ column
+ );
+
+ if (context & Context.OptionsWebCompat && parser.destructible & DestructuringKind.SeenProto) {
+ report(parser, Errors.DuplicateProto);
+ }
+
+ if (parser.destructible & DestructuringKind.HasToDestruct) {
+ report(parser, Errors.InvalidShorthandPropInit);
+ }
+
+ return expr as ESTree.ObjectExpression;
+}
+
+/**
+ * Parse object literal or object pattern
+ *
+ * @param parser Parser object
+ * @param context Context masks
+ * @param skipInitializer Context masks
+ * @param inGroup
+ * @param kind Binding kind
+ * @param origin Binding origin
+ * @param start
+ * @param line
+ * @param column
+ */
+export function parseObjectLiteralOrPattern(
+ parser: ParserState,
+ context: Context,
+ scope: ScopeState | undefined,
+ skipInitializer: 0 | 1,
+ inGroup: 0 | 1,
+ isPattern: 0 | 1,
+ kind: BindingKind,
+ origin: Origin,
+ start: number,
+ line: number,
+ column: number
+): ESTree.ObjectExpression | ESTree.ObjectPattern | ESTree.AssignmentExpression {
+ /**
+ *
+ * ObjectLiteral :
+ * { }
+ * { PropertyDefinitionList }
+ *
+ * PropertyDefinitionList :
+ * PropertyDefinition
+ * PropertyDefinitionList, PropertyDefinition
+ *
+ * PropertyDefinition :
+ * IdentifierName
+ * PropertyName : AssignmentExpression
+ *
+ * PropertyName :
+ * IdentifierName
+ * StringLiteral
+ * NumericLiteral
+ *
+ *
+ * ObjectBindingPattern :
+ * {}
+ * { BindingPropertyList }
+ * { BindingPropertyList , }
+ *
+ * BindingPropertyList :
+ * BindingProperty
+ * BindingPropertyList , BindingProperty
+ *
+ * BindingProperty :
+ * SingleNameBinding
+ * PropertyName : BindingElement
+ *
+ * SingleNameBinding :
+ * BindingIdentifier Initializeropt
+ *
+ * PropertyDefinition :
+ * IdentifierName
+ * CoverInitializedName
+ * PropertyName : AssignmentExpression
+ * MethodDefinition
+ */
+
+ nextToken(parser, context);
+
+ const properties: (ESTree.Property | ESTree.SpreadElement | ESTree.RestElement)[] = [];
+ let destructible: DestructuringKind | AssignmentKind = 0;
+ let prototypeCount = 0;
+
+ context = (context | Context.DisallowIn) ^ Context.DisallowIn;
+
+ while (parser.token !== Token.RightBrace) {
+ const { token, tokenValue, linePos, colPos, tokenPos } = parser;
+
+ if (token === Token.Ellipsis) {
+ properties.push(
+ parseSpreadOrRestElement(
+ parser,
+ context,
+ scope,
+ Token.RightBrace,
+ kind,
+ origin,
+ 0,
+ inGroup,
+ isPattern,
+ tokenPos,
+ linePos,
+ colPos
+ )
+ );
+ } else {
+ let state = PropertyKind.None;
+ let key: ESTree.Expression | null = null;
+ let value;
+ const t = parser.token;
+ if (parser.token & (Token.IsIdentifier | Token.Keyword) || parser.token === Token.EscapedReserved) {
+ key = parseIdentifier(parser, context, 0);
+
+ if (parser.token === Token.Comma || parser.token === Token.RightBrace || parser.token === Token.Assign) {
+ state |= PropertyKind.Shorthand;
+
+ if (context & Context.Strict && (token & Token.IsEvalOrArguments) === Token.IsEvalOrArguments) {
+ destructible |= DestructuringKind.CannotDestruct;
+ } else {
+ validateBindingIdentifier(parser, context, kind, token, 0);
+ }
+
+ if (scope) addVarOrBlock(parser, context, scope, tokenValue, kind, origin);
+
+ if (consumeOpt(parser, context | Context.AllowRegExp, Token.Assign)) {
+ destructible |= DestructuringKind.HasToDestruct;
+
+ const right = parseExpression(
+ parser,
+ context,
+ 1,
+ 1,
+ inGroup,
+ parser.tokenPos,
+ parser.linePos,
+ parser.colPos
+ );
+
+ destructible |=
+ parser.destructible & DestructuringKind.Yield
+ ? DestructuringKind.Yield
+ : 0 | (parser.destructible & DestructuringKind.Await)
+ ? DestructuringKind.Await
+ : 0;
+
+ value = finishNode(parser, context, tokenPos, linePos, colPos, {
+ type: 'AssignmentPattern',
+ left: context & Context.OptionsUniqueKeyInPattern ? Object.assign({}, key) : key,
+ right
+ });
+ } else {
+ destructible |=
+ (token === Token.AwaitKeyword ? DestructuringKind.Await : 0) |
+ (token === Token.EscapedReserved ? DestructuringKind.CannotDestruct : 0);
+ value = context & Context.OptionsUniqueKeyInPattern ? Object.assign({}, key) : key;
+ }
+ } else if (consumeOpt(parser, context | Context.AllowRegExp, Token.Colon)) {
+ const { tokenPos, linePos, colPos } = parser;
+
+ if (tokenValue === '__proto__') prototypeCount++;
+
+ if (parser.token & Token.IsIdentifier) {
+ const tokenAfterColon = parser.token;
+ const valueAfterColon = parser.tokenValue;
+ // A reserved word is an IdentifierName that cannot be used as an Identifier
+ destructible |= t === Token.EscapedReserved ? DestructuringKind.CannotDestruct : 0;
+
+ value = parsePrimaryExpression(parser, context, kind, 0, 1, 0, inGroup, 1, tokenPos, linePos, colPos);
+
+ const { token } = parser;
+
+ value = parseMemberOrUpdateExpression(parser, context, value, inGroup, 0, tokenPos, linePos, colPos);
+
+ if (parser.token === Token.Comma || parser.token === Token.RightBrace) {
+ if (token === Token.Assign || token === Token.RightBrace || token === Token.Comma) {
+ destructible |= parser.destructible & DestructuringKind.Await ? DestructuringKind.Await : 0;
+ if (parser.assignable & AssignmentKind.CannotAssign) {
+ destructible |= DestructuringKind.CannotDestruct;
+ } else if (scope && (tokenAfterColon & Token.IsIdentifier) === Token.IsIdentifier) {
+ addVarOrBlock(parser, context, scope, valueAfterColon, kind, origin);
+ }
+ } else {
+ destructible |=
+ parser.assignable & AssignmentKind.Assignable
+ ? DestructuringKind.Assignable
+ : DestructuringKind.CannotDestruct;
+ }
+ } else if ((parser.token & Token.IsAssignOp) === Token.IsAssignOp) {
+ if (parser.assignable & AssignmentKind.CannotAssign) {
+ destructible |= DestructuringKind.CannotDestruct;
+ } else if (token !== Token.Assign) {
+ destructible |= DestructuringKind.Assignable;
+ } else if (scope) {
+ addVarOrBlock(parser, context, scope, valueAfterColon, kind, origin);
+ }
+ value = parseAssignmentExpression(parser, context, inGroup, isPattern, tokenPos, linePos, colPos, value);
+ } else {
+ destructible |= DestructuringKind.CannotDestruct;
+ if ((parser.token & Token.IsBinaryOp) === Token.IsBinaryOp) {
+ value = parseBinaryExpression(parser, context, 1, tokenPos, linePos, colPos, 4, token, value);
+ }
+ if (consumeOpt(parser, context | Context.AllowRegExp, Token.QuestionMark)) {
+ value = parseConditionalExpression(parser, context, value, tokenPos, linePos, colPos);
+ }
+ }
+ } else if ((parser.token & Token.IsPatternStart) === Token.IsPatternStart) {
+ value =
+ parser.token === Token.LeftBracket
+ ? parseArrayExpressionOrPattern(
+ parser,
+ context,
+ scope,
+ 0,
+ inGroup,
+ isPattern,
+ kind,
+ origin,
+ tokenPos,
+ linePos,
+ colPos
+ )
+ : parseObjectLiteralOrPattern(
+ parser,
+ context,
+ scope,
+ 0,
+ inGroup,
+ isPattern,
+ kind,
+ origin,
+ tokenPos,
+ linePos,
+ colPos
+ );
+
+ destructible = parser.destructible;
+
+ parser.assignable =
+ destructible & DestructuringKind.CannotDestruct ? AssignmentKind.CannotAssign : AssignmentKind.Assignable;
+
+ if (parser.token === Token.Comma || parser.token === Token.RightBrace) {
+ if (parser.assignable & AssignmentKind.CannotAssign) destructible |= DestructuringKind.CannotDestruct;
+ } else if (parser.destructible & DestructuringKind.HasToDestruct) {
+ report(parser, Errors.InvalidDestructuringTarget);
+ } else {
+ value = parseMemberOrUpdateExpression(parser, context, value, inGroup, 0, tokenPos, linePos, colPos);
+
+ destructible = parser.assignable & AssignmentKind.CannotAssign ? DestructuringKind.CannotDestruct : 0;
+
+ if ((parser.token & Token.IsAssignOp) === Token.IsAssignOp) {
+ value = parseAssignmentExpressionOrPattern(
+ parser,
+ context,
+ inGroup,
+ isPattern,
+ tokenPos,
+ linePos,
+ colPos,
+ value
+ );
+ } else {
+ if ((parser.token & Token.IsBinaryOp) === Token.IsBinaryOp) {
+ value = parseBinaryExpression(parser, context, 1, tokenPos, linePos, colPos, 4, token, value);
+ }
+ if (consumeOpt(parser, context | Context.AllowRegExp, Token.QuestionMark)) {
+ value = parseConditionalExpression(parser, context, value, tokenPos, linePos, colPos);
+ }
+ destructible |=
+ parser.assignable & AssignmentKind.CannotAssign
+ ? DestructuringKind.CannotDestruct
+ : DestructuringKind.Assignable;
+ }
+ }
+ } else {
+ value = parseLeftHandSideExpression(parser, context, 1, inGroup, 1, tokenPos, linePos, colPos);
+
+ destructible |=
+ parser.assignable & AssignmentKind.Assignable
+ ? DestructuringKind.Assignable
+ : DestructuringKind.CannotDestruct;
+
+ if (parser.token === Token.Comma || parser.token === Token.RightBrace) {
+ if (parser.assignable & AssignmentKind.CannotAssign) destructible |= DestructuringKind.CannotDestruct;
+ } else {
+ value = parseMemberOrUpdateExpression(parser, context, value, inGroup, 0, tokenPos, linePos, colPos);
+
+ destructible = parser.assignable & AssignmentKind.CannotAssign ? DestructuringKind.CannotDestruct : 0;
+
+ if (parser.token !== Token.Comma && token !== Token.RightBrace) {
+ if (parser.token !== Token.Assign) destructible |= DestructuringKind.CannotDestruct;
+ value = parseAssignmentExpression(
+ parser,
+ context,
+ inGroup,
+ isPattern,
+ tokenPos,
+ linePos,
+ colPos,
+ value
+ );
+ }
+ }
+ }
+ } else if (parser.token === Token.LeftBracket) {
+ destructible |= DestructuringKind.CannotDestruct;
+ if (token === Token.AsyncKeyword) state |= PropertyKind.Async;
+
+ state |=
+ (token === Token.GetKeyword
+ ? PropertyKind.Getter
+ : token === Token.SetKeyword
+ ? PropertyKind.Setter
+ : PropertyKind.Method) | PropertyKind.Computed;
+
+ key = parseComputedPropertyName(parser, context, inGroup);
+ destructible |= parser.assignable;
+
+ value = parseMethodDefinition(
+ parser,
+ context,
+ state,
+ inGroup,
+ parser.tokenPos,
+ parser.linePos,
+ parser.colPos
+ );
+ } else if (parser.token & (Token.IsIdentifier | Token.Keyword)) {
+ destructible |= DestructuringKind.CannotDestruct;
+ if (token === Token.EscapedReserved) report(parser, Errors.InvalidEscapedKeyword);
+ if (token === Token.AsyncKeyword) {
+ if (parser.flags & Flags.NewLine) report(parser, Errors.AsyncRestrictedProd);
+ state |= PropertyKind.Async;
+ }
+ key = parseIdentifier(parser, context, 0);
+
+ state |=
+ token === Token.GetKeyword
+ ? PropertyKind.Getter
+ : token === Token.SetKeyword
+ ? PropertyKind.Setter
+ : PropertyKind.Method;
+
+ value = parseMethodDefinition(
+ parser,
+ context,
+ state,
+ inGroup,
+ parser.tokenPos,
+ parser.linePos,
+ parser.colPos
+ );
+ } else if (parser.token === Token.LeftParen) {
+ destructible |= DestructuringKind.CannotDestruct;
+ state |= PropertyKind.Method;
+ value = parseMethodDefinition(
+ parser,
+ context,
+ state,
+ inGroup,
+ parser.tokenPos,
+ parser.linePos,
+ parser.colPos
+ );
+ } else if (parser.token === Token.Multiply) {
+ destructible |= DestructuringKind.CannotDestruct;
+
+ if (token === Token.GetKeyword || token === Token.SetKeyword) {
+ report(parser, Errors.InvalidGeneratorGetter);
+ } else if (token === Token.AnyIdentifier) {
+ report(parser, Errors.InvalidEscapedKeyword);
+ }
+
+ nextToken(parser, context);
+
+ state |=
+ PropertyKind.Generator | PropertyKind.Method | (token === Token.AsyncKeyword ? PropertyKind.Async : 0);
+
+ if (parser.token & Token.IsIdentifier) {
+ key = parseIdentifier(parser, context, 0);
+ } else if ((parser.token & Token.IsStringOrNumber) === Token.IsStringOrNumber) {
+ key = parseLiteral(parser, context);
+ } else if (parser.token === Token.LeftBracket) {
+ state |= PropertyKind.Computed;
+ key = parseComputedPropertyName(parser, context, inGroup);
+ destructible |= parser.assignable;
+ } else {
+ report(parser, Errors.UnexpectedToken, KeywordDescTable[parser.token & Token.Type]);
+ }
+ value = parseMethodDefinition(
+ parser,
+ context,
+ state,
+ inGroup,
+ parser.tokenPos,
+ parser.linePos,
+ parser.colPos
+ );
+ } else if ((parser.token & Token.IsStringOrNumber) === Token.IsStringOrNumber) {
+ if (token === Token.AsyncKeyword) state |= PropertyKind.Async;
+
+ state |=
+ token === Token.GetKeyword
+ ? PropertyKind.Getter
+ : token === Token.SetKeyword
+ ? PropertyKind.Setter
+ : PropertyKind.Method;
+
+ destructible |= DestructuringKind.CannotDestruct;
+
+ key = parseLiteral(parser, context);
+
+ value = parseMethodDefinition(
+ parser,
+ context,
+ state,
+ inGroup,
+ parser.tokenPos,
+ parser.linePos,
+ parser.colPos
+ );
+ } else {
+ report(parser, Errors.UnexpectedCharAfterObjLit);
+ }
+ } else if ((parser.token & Token.IsStringOrNumber) === Token.IsStringOrNumber) {
+ key = parseLiteral(parser, context);
+
+ if (parser.token === Token.Colon) {
+ consume(parser, context | Context.AllowRegExp, Token.Colon);
+
+ const { tokenPos, linePos, colPos } = parser;
+
+ if (tokenValue === '__proto__') prototypeCount++;
+
+ if (parser.token & Token.IsIdentifier) {
+ value = parsePrimaryExpression(parser, context, kind, 0, 1, 0, inGroup, 1, tokenPos, linePos, colPos);
+
+ const { token, tokenValue: valueAfterColon } = parser;
+
+ value = parseMemberOrUpdateExpression(parser, context, value, inGroup, 0, tokenPos, linePos, colPos);
+
+ if (parser.token === Token.Comma || parser.token === Token.RightBrace) {
+ if (token === Token.Assign || token === Token.RightBrace || token === Token.Comma) {
+ if (parser.assignable & AssignmentKind.CannotAssign) {
+ destructible |= DestructuringKind.CannotDestruct;
+ } else if (scope) {
+ addVarOrBlock(parser, context, scope, valueAfterColon, kind, origin);
+ }
+ } else {
+ destructible |=
+ parser.assignable & AssignmentKind.Assignable
+ ? DestructuringKind.Assignable
+ : DestructuringKind.CannotDestruct;
+ }
+ } else if (parser.token === Token.Assign) {
+ if (parser.assignable & AssignmentKind.CannotAssign) destructible |= DestructuringKind.CannotDestruct;
+ value = parseAssignmentExpression(parser, context, inGroup, isPattern, tokenPos, linePos, colPos, value);
+ } else {
+ destructible |= DestructuringKind.CannotDestruct;
+ value = parseAssignmentExpression(parser, context, inGroup, isPattern, tokenPos, linePos, colPos, value);
+ }
+ } else if ((parser.token & Token.IsPatternStart) === Token.IsPatternStart) {
+ value =
+ parser.token === Token.LeftBracket
+ ? parseArrayExpressionOrPattern(
+ parser,
+ context,
+ scope,
+ 0,
+ inGroup,
+ isPattern,
+ kind,
+ origin,
+ tokenPos,
+ linePos,
+ colPos
+ )
+ : parseObjectLiteralOrPattern(
+ parser,
+ context,
+ scope,
+ 0,
+ inGroup,
+ isPattern,
+ kind,
+ origin,
+ tokenPos,
+ linePos,
+ colPos
+ );
+
+ destructible = parser.destructible;
+
+ parser.assignable =
+ destructible & DestructuringKind.CannotDestruct ? AssignmentKind.CannotAssign : AssignmentKind.Assignable;
+
+ if (parser.token === Token.Comma || parser.token === Token.RightBrace) {
+ if (parser.assignable & AssignmentKind.CannotAssign) {
+ destructible |= DestructuringKind.CannotDestruct;
+ }
+ } else if ((parser.destructible & DestructuringKind.HasToDestruct) !== DestructuringKind.HasToDestruct) {
+ value = parseMemberOrUpdateExpression(parser, context, value, inGroup, 0, tokenPos, linePos, colPos);
+ destructible = parser.assignable & AssignmentKind.CannotAssign ? DestructuringKind.CannotDestruct : 0;
+
+ if ((parser.token & Token.IsAssignOp) === Token.IsAssignOp) {
+ value = parseAssignmentExpressionOrPattern(
+ parser,
+ context,
+ inGroup,
+ isPattern,
+ tokenPos,
+ linePos,
+ colPos,
+ value
+ );
+ } else {
+ if ((parser.token & Token.IsBinaryOp) === Token.IsBinaryOp) {
+ value = parseBinaryExpression(parser, context, 1, tokenPos, linePos, colPos, 4, token, value);
+ }
+ if (consumeOpt(parser, context | Context.AllowRegExp, Token.QuestionMark)) {
+ value = parseConditionalExpression(parser, context, value, tokenPos, linePos, colPos);
+ }
+ destructible |=
+ parser.assignable & AssignmentKind.CannotAssign
+ ? DestructuringKind.CannotDestruct
+ : DestructuringKind.Assignable;
+ }
+ }
+ } else {
+ value = parseLeftHandSideExpression(parser, context, 1, 0, 1, tokenPos, linePos, colPos);
+
+ destructible |=
+ parser.assignable & AssignmentKind.Assignable
+ ? DestructuringKind.Assignable
+ : DestructuringKind.CannotDestruct;
+
+ if (parser.token === Token.Comma || parser.token === Token.RightBrace) {
+ if (parser.assignable & AssignmentKind.CannotAssign) {
+ destructible |= DestructuringKind.CannotDestruct;
+ }
+ } else {
+ value = parseMemberOrUpdateExpression(parser, context, value, inGroup, 0, tokenPos, linePos, colPos);
+
+ destructible = parser.assignable & AssignmentKind.Assignable ? 0 : DestructuringKind.CannotDestruct;
+
+ if (parser.token !== Token.Comma && parser.token !== Token.RightBrace) {
+ if (parser.token !== Token.Assign) destructible |= DestructuringKind.CannotDestruct;
+ value = parseAssignmentExpression(
+ parser,
+ context,
+ inGroup,
+ isPattern,
+ tokenPos,
+ linePos,
+ colPos,
+ value
+ );
+ }
+ }
+ }
+ } else if (parser.token === Token.LeftParen) {
+ state |= PropertyKind.Method;
+ value = parseMethodDefinition(
+ parser,
+ context,
+ state,
+ inGroup,
+ parser.tokenPos,
+ parser.linePos,
+ parser.colPos
+ );
+ destructible = parser.assignable | DestructuringKind.CannotDestruct;
+ } else {
+ report(parser, Errors.InvalidObjLitKey);
+ }
+ } else if (parser.token === Token.LeftBracket) {
+ key = parseComputedPropertyName(parser, context, inGroup);
+
+ destructible |= parser.destructible & DestructuringKind.Yield ? DestructuringKind.Yield : 0;
+
+ state |= PropertyKind.Computed;
+
+ if (parser.token === Token.Colon) {
+ nextToken(parser, context | Context.AllowRegExp); // skip ':'
+
+ const { tokenPos, linePos, colPos, tokenValue, token: tokenAfterColon } = parser;
+
+ if (parser.token & Token.IsIdentifier) {
+ value = parsePrimaryExpression(parser, context, kind, 0, 1, 0, inGroup, 1, tokenPos, linePos, colPos);
+
+ const { token } = parser;
+
+ value = parseMemberOrUpdateExpression(parser, context, value, inGroup, 0, tokenPos, linePos, colPos);
+
+ if ((parser.token & Token.IsAssignOp) === Token.IsAssignOp) {
+ destructible |=
+ parser.assignable & AssignmentKind.CannotAssign
+ ? DestructuringKind.CannotDestruct
+ : token === Token.Assign
+ ? 0
+ : DestructuringKind.Assignable;
+ value = parseAssignmentExpressionOrPattern(
+ parser,
+ context,
+ inGroup,
+ isPattern,
+ tokenPos,
+ linePos,
+ colPos,
+ value
+ );
+ } else if (parser.token === Token.Comma || parser.token === Token.RightBrace) {
+ if (token === Token.Assign || token === Token.RightBrace || token === Token.Comma) {
+ if (parser.assignable & AssignmentKind.CannotAssign) {
+ destructible |= DestructuringKind.CannotDestruct;
+ } else if (scope && (tokenAfterColon & Token.IsIdentifier) === Token.IsIdentifier) {
+ addVarOrBlock(parser, context, scope, tokenValue, kind, origin);
+ }
+ } else {
+ destructible |=
+ parser.assignable & AssignmentKind.Assignable
+ ? DestructuringKind.Assignable
+ : DestructuringKind.CannotDestruct;
+ }
+ } else {
+ destructible |= DestructuringKind.CannotDestruct;
+ value = parseAssignmentExpression(parser, context, inGroup, isPattern, tokenPos, linePos, colPos, value);
+ }
+ } else if ((parser.token & Token.IsPatternStart) === Token.IsPatternStart) {
+ value =
+ parser.token === Token.LeftBracket
+ ? parseArrayExpressionOrPattern(
+ parser,
+ context,
+ scope,
+ 0,
+ inGroup,
+ isPattern,
+ kind,
+ origin,
+ tokenPos,
+ linePos,
+ colPos
+ )
+ : parseObjectLiteralOrPattern(
+ parser,
+ context,
+ scope,
+ 0,
+ inGroup,
+ isPattern,
+ kind,
+ origin,
+ tokenPos,
+ linePos,
+ colPos
+ );
+
+ destructible = parser.destructible;
+
+ parser.assignable =
+ destructible & DestructuringKind.CannotDestruct ? AssignmentKind.CannotAssign : AssignmentKind.Assignable;
+
+ if (parser.token === Token.Comma || parser.token === Token.RightBrace) {
+ if (parser.assignable & AssignmentKind.CannotAssign) destructible |= DestructuringKind.CannotDestruct;
+ } else if (destructible & DestructuringKind.HasToDestruct) {
+ report(parser, Errors.InvalidShorthandPropInit);
+ } else {
+ value = parseMemberOrUpdateExpression(parser, context, value, inGroup, 0, tokenPos, linePos, colPos);
+
+ destructible =
+ parser.assignable & AssignmentKind.CannotAssign ? destructible | DestructuringKind.CannotDestruct : 0;
+
+ if ((parser.token & Token.IsAssignOp) === Token.IsAssignOp) {
+ if (parser.token !== Token.Assign) destructible |= DestructuringKind.CannotDestruct;
+ value = parseAssignmentExpressionOrPattern(
+ parser,
+ context,
+ inGroup,
+ isPattern,
+ tokenPos,
+ linePos,
+ colPos,
+ value
+ );
+ } else {
+ if ((parser.token & Token.IsBinaryOp) === Token.IsBinaryOp) {
+ value = parseBinaryExpression(parser, context, 1, tokenPos, linePos, colPos, 4, token, value);
+ }
+ if (consumeOpt(parser, context | Context.AllowRegExp, Token.QuestionMark)) {
+ value = parseConditionalExpression(parser, context, value, tokenPos, linePos, colPos);
+ }
+ destructible |=
+ parser.assignable & AssignmentKind.CannotAssign
+ ? DestructuringKind.CannotDestruct
+ : DestructuringKind.Assignable;
+ }
+ }
+ } else {
+ value = parseLeftHandSideExpression(parser, context, 1, 0, 1, tokenPos, linePos, colPos);
+
+ destructible |=
+ parser.assignable & AssignmentKind.Assignable
+ ? DestructuringKind.Assignable
+ : DestructuringKind.CannotDestruct;
+
+ if (parser.token === Token.Comma || parser.token === Token.RightBrace) {
+ if (parser.assignable & AssignmentKind.CannotAssign) destructible |= DestructuringKind.CannotDestruct;
+ } else {
+ value = parseMemberOrUpdateExpression(parser, context, value, inGroup, 0, tokenPos, linePos, colPos);
+
+ destructible = parser.assignable & AssignmentKind.Assignable ? 0 : DestructuringKind.CannotDestruct;
+
+ if (parser.token !== Token.Comma && parser.token !== Token.RightBrace) {
+ if (parser.token !== Token.Assign) destructible |= DestructuringKind.CannotDestruct;
+ value = parseAssignmentExpression(
+ parser,
+ context,
+ inGroup,
+ isPattern,
+ tokenPos,
+ linePos,
+ colPos,
+ value
+ );
+ }
+ }
+ }
+ } else if (parser.token === Token.LeftParen) {
+ state |= PropertyKind.Method;
+
+ value = parseMethodDefinition(parser, context, state, inGroup, parser.tokenPos, linePos, colPos);
+
+ destructible = DestructuringKind.CannotDestruct;
+ } else {
+ report(parser, Errors.InvalidComputedPropName);
+ }
+ } else if (token === Token.Multiply) {
+ consume(parser, context | Context.AllowRegExp, Token.Multiply);
+
+ state |= PropertyKind.Generator;
+
+ if (parser.token & Token.IsIdentifier) {
+ const { token, line, index } = parser;
+
+ key = parseIdentifier(parser, context, 0);
+
+ state |= PropertyKind.Method;
+
+ if (parser.token === Token.LeftParen) {
+ destructible |= DestructuringKind.CannotDestruct;
+ value = parseMethodDefinition(
+ parser,
+ context,
+ state,
+ inGroup,
+ parser.tokenPos,
+ parser.linePos,
+ parser.colPos
+ );
+ } else {
+ reportMessageAt(
+ index,
+ line,
+ index,
+ token === Token.AsyncKeyword
+ ? Errors.InvalidAsyncGetter
+ : token === Token.GetKeyword || parser.token === Token.SetKeyword
+ ? Errors.InvalidGetSetGenerator
+ : Errors.InvalidGenMethodShorthand,
+ KeywordDescTable[token & Token.Type]
+ );
+ }
+ } else if ((parser.token & Token.IsStringOrNumber) === Token.IsStringOrNumber) {
+ destructible |= DestructuringKind.CannotDestruct;
+ key = parseLiteral(parser, context);
+ state |= PropertyKind.Method;
+ value = parseMethodDefinition(parser, context, state, inGroup, tokenPos, linePos, colPos);
+ } else if (parser.token === Token.LeftBracket) {
+ destructible |= DestructuringKind.CannotDestruct;
+ state |= PropertyKind.Computed | PropertyKind.Method;
+ key = parseComputedPropertyName(parser, context, inGroup);
+ value = parseMethodDefinition(
+ parser,
+ context,
+ state,
+ inGroup,
+ parser.tokenPos,
+ parser.linePos,
+ parser.colPos
+ );
+ } else {
+ report(parser, Errors.InvalidObjLitKeyStar);
+ }
+ } else {
+ report(parser, Errors.UnexpectedToken, KeywordDescTable[token & Token.Type]);
+ }
+
+ destructible |= parser.destructible & DestructuringKind.Await ? DestructuringKind.Await : 0;
+
+ parser.destructible = destructible;
+
+ properties.push(
+ finishNode(parser, context, tokenPos, linePos, colPos, {
+ type: 'Property',
+ key: key as ESTree.Expression,
+ value,
+ kind: !(state & PropertyKind.GetSet) ? 'init' : state & PropertyKind.Setter ? 'set' : 'get',
+ computed: (state & PropertyKind.Computed) > 0,
+ method: (state & PropertyKind.Method) > 0,
+ shorthand: (state & PropertyKind.Shorthand) > 0
+ })
+ );
+ }
+
+ destructible |= parser.destructible;
+ if (parser.token !== Token.Comma) break;
+ nextToken(parser, context);
+ }
+
+ consume(parser, context, Token.RightBrace);
+
+ if (prototypeCount > 1) destructible |= DestructuringKind.SeenProto;
+
+ const node = finishNode(parser, context, start, line, column, {
+ type: isPattern ? 'ObjectPattern' : 'ObjectExpression',
+ properties
+ });
+
+ if (!skipInitializer && parser.token & Token.IsAssignOp) {
+ return parseArrayOrObjectAssignmentPattern(
+ parser,
+ context,
+ destructible,
+ inGroup,
+ isPattern,
+ start,
+ line,
+ column,
+ node
+ );
+ }
+
+ parser.destructible = destructible;
+
+ return node;
+}
+
+/**
+ * Parses method formals
+ *
+ * @param parser parser object
+ * @param context context masks
+ * @param kind
+ * @param type Binding kind
+ * @param inGroup
+ */
+export function parseMethodFormals(
+ parser: ParserState,
+ context: Context,
+ scope: ScopeState | undefined,
+ kind: PropertyKind,
+ type: BindingKind,
+ inGroup: 0 | 1
+): ESTree.Parameter[] {
+ // FormalParameter[Yield,GeneratorParameter] :
+ // BindingElement[?Yield, ?GeneratorParameter]
+
+ consume(parser, context, Token.LeftParen);
+
+ const params: (ESTree.AssignmentPattern | ESTree.Parameter)[] = [];
+
+ parser.flags = (parser.flags | Flags.SimpleParameterList) ^ Flags.SimpleParameterList;
+
+ if (parser.token === Token.RightParen) {
+ if (kind & PropertyKind.Setter) {
+ report(parser, Errors.AccessorWrongArgs, 'Setter', 'one', '');
+ }
+ nextToken(parser, context);
+ return params;
+ }
+
+ if (kind & PropertyKind.Getter) {
+ report(parser, Errors.AccessorWrongArgs, 'Getter', 'no', 's');
+ }
+ if (kind & PropertyKind.Setter && parser.token === Token.Ellipsis) {
+ report(parser, Errors.BadSetterRestParameter);
+ }
+
+ context = (context | Context.DisallowIn) ^ Context.DisallowIn;
+
+ let setterArgs = 0;
+ let isSimpleParameterList: 0 | 1 = 0;
+
+ while (parser.token !== Token.Comma) {
+ let left = null;
+ const { tokenPos, linePos, colPos } = parser;
+
+ if (parser.token & Token.IsIdentifier) {
+ if ((context & Context.Strict) < 1) {
+ if ((parser.token & Token.FutureReserved) === Token.FutureReserved) {
+ parser.flags |= Flags.HasStrictReserved;
+ }
+
+ if ((parser.token & Token.IsEvalOrArguments) === Token.IsEvalOrArguments) {
+ parser.flags |= Flags.StrictEvalArguments;
+ }
+ }
+
+ left = parseAndClassifyIdentifier(
+ parser,
+ context,
+ scope,
+ kind | BindingKind.ArgumentList,
+ Origin.None,
+ tokenPos,
+ linePos,
+ colPos
+ );
+ } else {
+ if (parser.token === Token.LeftBrace) {
+ left = parseObjectLiteralOrPattern(
+ parser,
+ context,
+ scope,
+ 1,
+ inGroup,
+ 1,
+ type,
+ Origin.None,
+ tokenPos,
+ linePos,
+ colPos
+ );
+ } else if (parser.token === Token.LeftBracket) {
+ left = parseArrayExpressionOrPattern(
+ parser,
+ context,
+ scope,
+ 1,
+ inGroup,
+ 1,
+ type,
+ Origin.None,
+ tokenPos,
+ linePos,
+ colPos
+ );
+ } else if (parser.token === Token.Ellipsis) {
+ left = parseSpreadOrRestElement(
+ parser,
+ context,
+ scope,
+ Token.RightParen,
+ type,
+ Origin.None,
+ 0,
+ inGroup,
+ 1,
+ tokenPos,
+ linePos,
+ colPos
+ );
+ }
+
+ isSimpleParameterList = 1;
+
+ if (parser.destructible & (DestructuringKind.Assignable | DestructuringKind.CannotDestruct))
+ report(parser, Errors.InvalidBindingDestruct);
+ }
+
+ if (parser.token === Token.Assign) {
+ nextToken(parser, context | Context.AllowRegExp);
+
+ isSimpleParameterList = 1;
+
+ const right = parseExpression(parser, context, 1, 1, 0, parser.tokenPos, parser.linePos, parser.colPos);
+
+ left = finishNode(parser, context, tokenPos, linePos, colPos, {
+ type: 'AssignmentPattern',
+ left: left as ESTree.BindingPattern | ESTree.Identifier,
+ right
+ });
+ }
+
+ setterArgs++;
+
+ params.push(left as any);
+
+ if (!consumeOpt(parser, context, Token.Comma)) break;
+ if (parser.token === Token.RightParen) {
+ // allow the trailing comma
+ break;
+ }
+ }
+
+ if (kind & PropertyKind.Setter && setterArgs !== 1) {
+ report(parser, Errors.AccessorWrongArgs, 'Setter', 'one', '');
+ }
+
+ if (scope && scope.scopeError !== void 0) reportScopeError(scope.scopeError);
+
+ if (isSimpleParameterList) parser.flags |= Flags.SimpleParameterList;
+
+ consume(parser, context, Token.RightParen);
+
+ return params;
+}
+
+/**
+ * Parse computed property name
+ *
+ * @param parser Parser object
+ * @param context Context masks
+ */
+export function parseComputedPropertyName(parser: ParserState, context: Context, inGroup: 0 | 1): ESTree.Expression {
+ // ComputedPropertyName :
+ // [ AssignmentExpression ]
+ nextToken(parser, context | Context.AllowRegExp);
+ const key = parseExpression(
+ parser,
+ (context | Context.DisallowIn) ^ Context.DisallowIn,
+ 1,
+ 0,
+ inGroup,
+ parser.tokenPos,
+ parser.linePos,
+ parser.colPos
+ );
+ consume(parser, context, Token.RightBracket);
+ return key;
+}
+
+/**
+ * Parses an expression which has been parenthesised, or arrow head
+ *
+ * @param parser Parser object
+ * @param context Context masks
+ * @param assignable
+ * @param start Start index
+ * @param line Start line
+ * @param column Start of column
+ */
+export function parseParenthesizedExpression(
+ parser: ParserState,
+ context: Context,
+ canAssign: 0 | 1,
+ kind: BindingKind,
+ origin: Origin,
+ start: number,
+ line: number,
+ column: number
+): any {
+ parser.flags = (parser.flags | Flags.SimpleParameterList) ^ Flags.SimpleParameterList;
+
+ const { tokenPos: piStart, linePos: plStart, colPos: pcStart } = parser;
+
+ nextToken(parser, context | Context.AllowRegExp | Context.AllowEscapedKeyword);
+
+ const scope = context & Context.OptionsLexical ? addChildScope(createScope(), ScopeKind.ArrowParams) : void 0;
+
+ context = (context | Context.DisallowIn) ^ Context.DisallowIn;
+
+ if (consumeOpt(parser, context, Token.RightParen)) {
+ // Not valid expression syntax, but this is valid in an arrow function
+ // with no params: `() => body`.
+ return parseParenthesizedArrow(parser, context, scope, [], canAssign, 0, start, line, column);
+ }
+
+ let destructible: AssignmentKind | DestructuringKind = 0;
+
+ parser.destructible &= ~(DestructuringKind.Yield | DestructuringKind.Await);
+
+ let expr;
+ let expressions: ESTree.Expression[] = [];
+ let isSequence: 0 | 1 = 0;
+ let isSimpleParameterList: 0 | 1 = 0;
+
+ const { tokenPos: iStart, linePos: lStart, colPos: cStart } = parser;
+
+ parser.assignable = AssignmentKind.Assignable;
+
+ while (parser.token !== Token.RightParen) {
+ const { token, tokenPos, linePos, colPos } = parser;
+
+ if (token & (Token.IsIdentifier | Token.Keyword)) {
+ if (scope) addBlockName(parser, context, scope, parser.tokenValue, BindingKind.ArgumentList, Origin.None);
+
+ expr = parsePrimaryExpression(parser, context, kind, 0, 1, 0, 1, 1, tokenPos, linePos, colPos);
+
+ if (parser.token === Token.RightParen || parser.token === Token.Comma) {
+ if (parser.assignable & AssignmentKind.CannotAssign) {
+ destructible |= DestructuringKind.CannotDestruct;
+ isSimpleParameterList = 1;
+ } else if (
+ (token & Token.IsEvalOrArguments) === Token.IsEvalOrArguments ||
+ (token & Token.FutureReserved) === Token.FutureReserved
+ ) {
+ isSimpleParameterList = 1;
+ }
+ } else {
+ if (parser.token === Token.Assign) {
+ isSimpleParameterList = 1;
+ } else {
+ destructible |= DestructuringKind.CannotDestruct;
+ }
+
+ expr = parseMemberOrUpdateExpression(parser, context, expr, /* inGroup */ 1, 0, tokenPos, linePos, colPos);
+
+ if (parser.token !== Token.RightParen && parser.token !== Token.Comma) {
+ expr = parseAssignmentExpression(parser, context, 1, 0, tokenPos, linePos, colPos, expr);
+ }
+ }
+ } else if ((token & Token.IsPatternStart) === Token.IsPatternStart) {
+ expr =
+ token === Token.LeftBrace
+ ? parseObjectLiteralOrPattern(
+ parser,
+ context | Context.AllowEscapedKeyword,
+ scope,
+ 0,
+ 1,
+ 0,
+ kind,
+ origin,
+ tokenPos,
+ linePos,
+ colPos
+ )
+ : parseArrayExpressionOrPattern(
+ parser,
+ context | Context.AllowEscapedKeyword,
+ scope,
+ 0,
+ 1,
+ 0,
+ kind,
+ origin,
+ tokenPos,
+ linePos,
+ colPos
+ );
+
+ destructible |= parser.destructible;
+
+ isSimpleParameterList = 1;
+
+ parser.assignable = AssignmentKind.CannotAssign;
+
+ if (parser.token !== Token.RightParen && parser.token !== Token.Comma) {
+ if (destructible & DestructuringKind.HasToDestruct) report(parser, Errors.InvalidPatternTail);
+
+ expr = parseMemberOrUpdateExpression(parser, context, expr, 0, 0, tokenPos, linePos, colPos);
+
+ destructible |= DestructuringKind.CannotDestruct;
+
+ if (parser.token !== Token.RightParen && parser.token !== Token.Comma) {
+ expr = parseAssignmentExpression(parser, context, 0, 0, tokenPos, linePos, colPos, expr);
+ }
+ }
+ } else if (token === Token.Ellipsis) {
+ expr = parseSpreadOrRestElement(
+ parser,
+ context,
+ scope,
+ Token.RightParen,
+ kind,
+ origin,
+ 0,
+ 1,
+ 0,
+ tokenPos,
+ linePos,
+ colPos
+ );
+
+ if (parser.destructible & DestructuringKind.CannotDestruct) report(parser, Errors.InvalidRestArg);
+
+ isSimpleParameterList = 1;
+
+ if (isSequence && (parser.token === Token.RightParen || parser.token === Token.Comma)) {
+ expressions.push(expr);
+ }
+ destructible |= DestructuringKind.HasToDestruct;
+ break;
+ } else {
+ destructible |= DestructuringKind.CannotDestruct;
+
+ expr = parseExpression(parser, context, 1, 0, 1, tokenPos, linePos, colPos);
+
+ if (isSequence && (parser.token === Token.RightParen || parser.token === Token.Comma)) {
+ expressions.push(expr);
+ }
+
+ if (parser.token === Token.Comma) {
+ if (!isSequence) {
+ isSequence = 1;
+ expressions = [expr];
+ }
+ }
+
+ if (isSequence) {
+ while (consumeOpt(parser, context | Context.AllowRegExp, Token.Comma)) {
+ expressions.push(parseExpression(parser, context, 1, 0, 1, parser.tokenPos, parser.linePos, parser.colPos));
+ }
+
+ parser.assignable = AssignmentKind.CannotAssign;
+
+ expr = finishNode(parser, context, iStart, lStart, cStart, {
+ type: 'SequenceExpression',
+ expressions
+ });
+ }
+
+ consume(parser, context, Token.RightParen);
+
+ parser.destructible = destructible;
+
+ return expr;
+ }
+
+ if (isSequence && (parser.token === Token.RightParen || parser.token === Token.Comma)) {
+ expressions.push(expr);
+ }
+
+ if (!consumeOpt(parser, context | Context.AllowRegExp, Token.Comma)) break;
+
+ if (!isSequence) {
+ isSequence = 1;
+ expressions = [expr];
+ }
+
+ if (parser.token === Token.RightParen) {
+ destructible |= DestructuringKind.HasToDestruct;
+ break;
+ }
+ }
+
+ if (isSequence) {
+ parser.assignable = AssignmentKind.CannotAssign;
+
+ expr = finishNode(parser, context, iStart, lStart, cStart, {
+ type: 'SequenceExpression',
+ expressions
+ });
+ }
+
+ consume(parser, context, Token.RightParen);
+
+ if (destructible & DestructuringKind.CannotDestruct && destructible & DestructuringKind.HasToDestruct)
+ report(parser, Errors.CantAssignToValidRHS);
+
+ destructible |=
+ parser.destructible & DestructuringKind.Yield
+ ? DestructuringKind.Yield
+ : 0 | (parser.destructible & DestructuringKind.Await)
+ ? DestructuringKind.Await
+ : 0;
+
+ if (parser.token === Token.Arrow) {
+ if (destructible & (DestructuringKind.Assignable | DestructuringKind.CannotDestruct))
+ report(parser, Errors.InvalidArrowDestructLHS);
+ if (context & (Context.InAwaitContext | Context.Module) && destructible & DestructuringKind.Await)
+ report(parser, Errors.AwaitInParameter);
+ if (context & (Context.Strict | Context.InYieldContext) && destructible & DestructuringKind.Yield) {
+ report(parser, Errors.YieldInParameter);
+ }
+ if (isSimpleParameterList) parser.flags |= Flags.SimpleParameterList;
+ return parseParenthesizedArrow(
+ parser,
+ context,
+ scope,
+ isSequence ? expressions : [expr],
+ canAssign,
+ 0,
+ start,
+ line,
+ column
+ );
+ } else if (destructible & DestructuringKind.HasToDestruct) {
+ report(parser, Errors.UncompleteArrow);
+ }
+
+ parser.destructible = ((parser.destructible | DestructuringKind.Yield) ^ DestructuringKind.Yield) | destructible;
+
+ return context & Context.OptionsPreserveParens
+ ? finishNode(parser, context, piStart, plStart, pcStart, {
+ type: 'ParenthesizedExpression',
+ expression: expr
+ })
+ : expr;
+}
+
+/**
+ * Parses either an identifier or an arrow function
+ *
+ * @param parser Parser object
+ * @param context Context masks
+ * @param start Start index
+ * @param line Start line
+ * @param column Start of column
+
+ */
+export function parseIdentifierOrArrow(
+ parser: ParserState,
+ context: Context,
+ start: number,
+ line: number,
+ column: number
+): ESTree.Identifier | ESTree.ArrowFunctionExpression {
+ const { tokenValue } = parser;
+
+ const expr = parseIdentifier(parser, context, 0);
+ parser.assignable = AssignmentKind.Assignable;
+ if (parser.token === Token.Arrow) {
+ let scope: ScopeState | undefined = void 0;
+
+ if (context & Context.OptionsLexical) scope = createArrowHeadParsingScope(parser, context, tokenValue);
+
+ parser.flags = (parser.flags | Flags.SimpleParameterList) ^ Flags.SimpleParameterList;
+
+ return parseArrowFunctionExpression(parser, context, scope, [expr], /* isAsync */ 0, start, line, column);
+ }
+ return expr;
+}
+
+/**
+ * Parse arrow function expression
+ *
+ * @param parser Parser object
+ * @param context Context masks
+ * @param params
+ * @param isAsync
+ * @param start Start index
+ * @param line Start line
+ * @param column Start of column
+ */
+function parseArrowFromIdentifier(
+ parser: ParserState,
+ context: Context,
+ value: any,
+ expr: ESTree.Expression,
+ inNew: 0 | 1,
+ canAssign: 0 | 1,
+ isAsync: 0 | 1,
+ start: number,
+ line: number,
+ column: number
+): ESTree.ArrowFunctionExpression {
+ if (!canAssign) report(parser, Errors.InvalidAssignmentTarget);
+ if (inNew) report(parser, Errors.InvalidAsyncArrow);
+ parser.flags &= ~Flags.SimpleParameterList;
+ const scope = context & Context.OptionsLexical ? createArrowHeadParsingScope(parser, context, value) : void 0;
+
+ return parseArrowFunctionExpression(parser, context, scope, [expr], isAsync, start, line, column);
+}
+
+/**
+ * Parse arrow function expression
+ *
+ * @param parser Parser object
+ * @param context Context masks
+ * @param params
+ * @param isAsync
+ * @param start Start index
+ * @param line Start line
+ * @param column Start of column
+ */
+function parseParenthesizedArrow(
+ parser: ParserState,
+ context: Context,
+ scope: ScopeState | undefined,
+ params: any,
+ canAssign: 0 | 1,
+ isAsync: 0 | 1,
+ start: number,
+ line: number,
+ column: number
+): ESTree.ArrowFunctionExpression {
+ if (!canAssign) report(parser, Errors.InvalidAssignmentTarget);
+
+ for (let i = 0; i < params.length; ++i) reinterpretToPattern(parser, params[i]);
+
+ return parseArrowFunctionExpression(parser, context, scope, params, isAsync, start, line, column);
+}
+
+/**
+ * Parse arrow function expression
+ *
+ * @param parser Parser object
+ * @param context Context masks
+ * @param params
+ * @param isAsync
+ * @param start Start index
+ * @param line Start line
+ * @param column Start of column
+ */
+export function parseArrowFunctionExpression(
+ parser: ParserState,
+ context: Context,
+ scope: ScopeState | undefined,
+ params: any,
+ isAsync: 0 | 1,
+ start: number,
+ line: number,
+ column: number
+): ESTree.ArrowFunctionExpression {
+ /**
+ * ArrowFunction :
+ * ArrowParameters => ConciseBody
+ *
+ * ArrowParameters :
+ * BindingIdentifer
+ * CoverParenthesizedExpressionAndArrowParameterList
+ *
+ * CoverParenthesizedExpressionAndArrowParameterList :
+ * ( Expression )
+ * ( )
+ * ( ... BindingIdentifier )
+ * ( Expression , ... BindingIdentifier )
+ *
+ * ConciseBody :
+ * [lookahead not {] AssignmentExpression
+ * { FunctionBody }
+ *
+ */
+
+ if (parser.flags & Flags.NewLine) report(parser, Errors.InvalidLineBreak);
+
+ consume(parser, context | Context.AllowRegExp, Token.Arrow);
+
+ context = ((context | 0b0000000111100000000_0000_00000000) ^ 0b0000000111100000000_0000_00000000) | (isAsync << 22);
+
+ const expression = parser.token !== Token.LeftBrace;
+
+ let body: ESTree.BlockStatement | ESTree.Expression;
+
+ if (scope && scope.scopeError !== void 0) {
+ reportScopeError(scope.scopeError);
+ }
+
+ if (expression) {
+ // Single-expression body
+ body = parseExpression(parser, context, 1, 0, 0, parser.tokenPos, parser.linePos, parser.colPos);
+ } else {
+ if (scope) scope = addChildScope(scope, ScopeKind.FunctionBody);
+
+ body = parseFunctionBody(
+ parser,
+ (context | 0b0001000000000000001_0000_00000000 | Context.InGlobal | Context.InClass) ^
+ (0b0001000000000000001_0000_00000000 | Context.InGlobal | Context.InClass),
+ scope,
+ Origin.Arrow,
+ void 0,
+ void 0
+ );
+
+ switch (parser.token) {
+ case Token.LeftBracket:
+ if ((parser.flags & Flags.NewLine) < 1) {
+ report(parser, Errors.InvalidInvokedBlockBodyArrow);
+ }
+ break;
+ case Token.Period:
+ case Token.TemplateSpan:
+ case Token.QuestionMark:
+ report(parser, Errors.InvalidAccessedBlockBodyArrow);
+ case Token.LeftParen:
+ if ((parser.flags & Flags.NewLine) < 1) {
+ report(parser, Errors.InvalidInvokedBlockBodyArrow);
+ }
+ parser.flags |= Flags.DisallowCall;
+ break;
+ default: // ignore
+ }
+ if ((parser.token & Token.IsBinaryOp) === Token.IsBinaryOp && (parser.flags & Flags.NewLine) < 1)
+ report(parser, Errors.UnexpectedToken, KeywordDescTable[parser.token & Token.Type]);
+ if ((parser.token & Token.IsUpdateOp) === Token.IsUpdateOp) report(parser, Errors.InvalidArrowPostfix);
+ }
+
+ parser.assignable = AssignmentKind.CannotAssign;
+
+ return finishNode(parser, context, start, line, column, {
+ type: 'ArrowFunctionExpression',
+ params,
+ body,
+ async: isAsync === 1,
+ expression
+ });
+}
+
+/**
+ * Parses formal parameters
+ *
+ * @param parser Parser object
+ * @param context Context masks
+ */
+export function parseFormalParametersOrFormalList(
+ parser: ParserState,
+ context: Context,
+ scope: ScopeState | undefined,
+ inGroup: 0 | 1,
+ kind: BindingKind
+): ESTree.Parameter[] {
+ /**
+ * FormalParameter :
+ * BindingElement
+ *
+ * FormalParameterList :
+ * [empty]
+ * FunctionRestParameter
+ * FormalsList
+ * FormalsList , FunctionRestParameter
+ *
+ * FunctionRestParameter :
+ * ... BindingIdentifier
+ *
+ * FormalsList :
+ * FormalParameter
+ * FormalsList , FormalParameter
+ *
+ * FormalParameter :
+ * BindingElement
+ *
+ * BindingElement :
+ * SingleNameBinding
+ * BindingPattern Initializeropt
+ *
+ */
+ consume(parser, context, Token.LeftParen);
+
+ parser.flags = (parser.flags | Flags.SimpleParameterList) ^ Flags.SimpleParameterList;
+
+ const params: ESTree.Parameter[] = [];
+
+ if (consumeOpt(parser, context, Token.RightParen)) return params;
+
+ context = (context | Context.DisallowIn) ^ Context.DisallowIn;
+
+ let isSimpleParameterList: 0 | 1 = 0;
+
+ while (parser.token !== Token.Comma) {
+ let left: any;
+
+ const { tokenPos, linePos, colPos } = parser;
+
+ if (parser.token & Token.IsIdentifier) {
+ if ((context & Context.Strict) < 1) {
+ if ((parser.token & Token.FutureReserved) === Token.FutureReserved) {
+ parser.flags |= Flags.HasStrictReserved;
+ }
+ if ((parser.token & Token.IsEvalOrArguments) === Token.IsEvalOrArguments) {
+ parser.flags |= Flags.StrictEvalArguments;
+ }
+ }
+
+ left = parseAndClassifyIdentifier(
+ parser,
+ context,
+ scope,
+ kind | BindingKind.ArgumentList,
+ Origin.None,
+ tokenPos,
+ linePos,
+ colPos
+ );
+ } else {
+ if (parser.token === Token.LeftBrace) {
+ left = parseObjectLiteralOrPattern(
+ parser,
+ context,
+ scope,
+ 1,
+ inGroup,
+ 1,
+ kind,
+ Origin.None,
+ tokenPos,
+ linePos,
+ colPos
+ );
+ } else if (parser.token === Token.LeftBracket) {
+ left = parseArrayExpressionOrPattern(
+ parser,
+ context,
+ scope,
+ 1,
+ inGroup,
+ 1,
+ kind,
+ Origin.None,
+ tokenPos,
+ linePos,
+ colPos
+ );
+ } else if (parser.token === Token.Ellipsis) {
+ left = parseSpreadOrRestElement(
+ parser,
+ context,
+ scope,
+ Token.RightParen,
+ kind,
+ Origin.None,
+ 0,
+ inGroup,
+ 1,
+ tokenPos,
+ linePos,
+ colPos
+ );
+ } else {
+ report(parser, Errors.UnexpectedToken, KeywordDescTable[parser.token & Token.Type]);
+ }
+
+ isSimpleParameterList = 1;
+
+ if (parser.destructible & (DestructuringKind.Assignable | DestructuringKind.CannotDestruct)) {
+ report(parser, Errors.InvalidBindingDestruct);
+ }
+ }
+
+ if (parser.token === Token.Assign) {
+ nextToken(parser, context | Context.AllowRegExp);
+
+ isSimpleParameterList = 1;
+
+ const right = parseExpression(parser, context, 1, 1, inGroup, parser.tokenPos, parser.linePos, parser.colPos);
+
+ left = finishNode(parser, context, tokenPos, linePos, colPos, {
+ type: 'AssignmentPattern',
+ left,
+ right
+ });
+ }
+
+ params.push(left);
+
+ if (!consumeOpt(parser, context, Token.Comma)) break;
+ if (parser.token === Token.RightParen) {
+ // allow the trailing comma
+ break;
+ }
+ }
+
+ if (isSimpleParameterList) parser.flags |= Flags.SimpleParameterList;
+
+ if (scope && (isSimpleParameterList || context & Context.Strict) && scope.scopeError !== void 0) {
+ reportScopeError(scope.scopeError);
+ }
+
+ consume(parser, context, Token.RightParen);
+
+ return params;
+}
+
+/**
+ * Parses member or update expression without call expression
+ *
+ * @param parser Parser object
+ * @param context Context masks
+ * @param expr ESTree AST node
+ * @param inGroup
+ * @param start
+ * @param line
+ * @param column
+ */
+export function parseMembeExpressionNoCall(
+ parser: ParserState,
+ context: Context,
+ expr: ESTree.Expression,
+ inGroup: 0 | 1,
+ start: number,
+ line: number,
+ column: number
+): any {
+ const { token } = parser;
+
+ if (token & Token.IsMemberOrCallExpression) {
+ /* Property */
+ if (token === Token.Period) {
+ nextToken(parser, context | Context.AllowEscapedKeyword);
+
+ parser.assignable = AssignmentKind.Assignable;
+
+ const property = parsePropertyOrPrivatePropertyName(parser, context);
+
+ return parseMembeExpressionNoCall(
+ parser,
+ context,
+ finishNode(parser, context, start, line, column, {
+ type: 'MemberExpression',
+ object: expr,
+ computed: false,
+ property
+ }),
+ 0,
+ start,
+ line,
+ column
+ );
+ /* Property */
+ } else if (token === Token.LeftBracket) {
+ nextToken(parser, context | Context.AllowRegExp);
+
+ const { tokenPos, linePos, colPos } = parser;
+
+ const property = parseExpressions(parser, context, inGroup, 1, tokenPos, linePos, colPos);
+
+ consume(parser, context, Token.RightBracket);
+
+ parser.assignable = AssignmentKind.Assignable;
+
+ return parseMembeExpressionNoCall(
+ parser,
+ context,
+ finishNode(parser, context, start, line, column, {
+ type: 'MemberExpression',
+ object: expr,
+ computed: true,
+ property
+ }),
+ 0,
+ start,
+ line,
+ column
+ );
+ /* Template */
+ } else if (token === Token.TemplateContinuation || token === Token.TemplateSpan) {
+ parser.assignable = AssignmentKind.CannotAssign;
+
+ return parseMembeExpressionNoCall(
+ parser,
+ context,
+ finishNode(parser, context, start, line, column, {
+ type: 'TaggedTemplateExpression',
+ tag: expr,
+ quasi:
+ parser.token === Token.TemplateContinuation
+ ? parseTemplate(parser, context | Context.TaggedTemplate)
+ : parseTemplateLiteral(parser, context, parser.tokenPos, parser.linePos, parser.colPos)
+ }),
+ 0,
+ start,
+ line,
+ column
+ );
+ }
+ }
+ return expr;
+}
+
+/**
+ * Parses new or new target expression
+ *
+ * @param parser Parser object
+ * @param context Context masks
+ * @returns {(ESTree.Expression | ESTree.MetaProperty)}
+ */
+export function parseNewExpression(
+ parser: ParserState,
+ context: Context,
+ inGroup: 0 | 1,
+ start: number,
+ line: number,
+ column: number
+): ESTree.NewExpression | ESTree.Expression | ESTree.MetaProperty {
+ // NewExpression ::
+ // ('new')+ MemberExpression
+ //
+ // NewTarget ::
+ // 'new' '.' 'target'
+ //
+ // Examples of new expression:
+ // - new foo.bar().baz
+ // - new foo()()
+ // - new new foo()()
+ // - new new foo
+ // - new new foo()
+ // - new new foo().bar().baz
+ // - `new.target[await x]`
+ // - `new (foo);`
+ // - `new (foo)();`
+ // - `new foo()();`
+ // - `new (await foo);`
+ // - `new x(await foo);`
+ const id = parseIdentifier(parser, context | Context.AllowRegExp, 0);
+ const { tokenPos, linePos, colPos } = parser;
+
+ if (consumeOpt(parser, context, Token.Period)) {
+ if (context & Context.AllowNewTarget && parser.token === Token.Target) {
+ parser.assignable = AssignmentKind.CannotAssign;
+ return parseMetaProperty(parser, context, id, start, line, column);
+ }
+
+ report(parser, Errors.InvalidNewTarget);
+ }
+
+ parser.assignable = AssignmentKind.CannotAssign;
+
+ if ((parser.token & Token.IsUnaryOp) === Token.IsUnaryOp) {
+ report(parser, Errors.InvalidNewUnary, KeywordDescTable[parser.token & Token.Type]);
+ }
+
+ const expr = parsePrimaryExpression(
+ parser,
+ context,
+ BindingKind.Empty,
+ 1,
+ 0,
+ 0,
+ inGroup,
+ 1,
+ tokenPos,
+ linePos,
+ colPos
+ );
+
+ context = (context | Context.DisallowIn) ^ Context.DisallowIn;
+
+ if (parser.token === Token.QuestionMarkPeriod) report(parser, Errors.OptionalChainingNoNew);
+
+ // NewExpression without arguments.
+ const callee = parseMembeExpressionNoCall(parser, context, expr, inGroup, tokenPos, linePos, colPos);
+
+ parser.assignable = AssignmentKind.CannotAssign;
+
+ return finishNode(parser, context, start, line, column, {
+ type: 'NewExpression',
+ callee,
+ arguments: parser.token === Token.LeftParen ? parseArguments(parser, context, inGroup) : []
+ });
+}
+
+/**
+ * Parse meta property
+ *
+ * @see [Link](https://tc39.github.io/ecma262/#prod-StatementList)
+ *
+ * @param parser Parser object
+ * @param context Context masks
+ * @param meta ESTree AST node
+ */
+export function parseMetaProperty(
+ parser: ParserState,
+ context: Context,
+ meta: ESTree.Identifier,
+ start: number,
+ line: number,
+ column: number
+): ESTree.MetaProperty {
+ const property = parseIdentifier(parser, context, 0);
+ return finishNode(parser, context, start, line, column, {
+ type: 'MetaProperty',
+ meta,
+ property
+ });
+}
+
+/**
+ * Parses async expression
+ *
+ * @param parser Parser object
+ * @param context Context masks
+ * @param inNew
+ * @param assignable
+ */
+
+/**
+ * Parses async arrow after identifier
+ *
+ * @param parser Parser object
+ * @param context Context masks
+ * @param canAssign Either true or false
+ * @param start Start pos of node
+ * @param line Line pos of node
+ * @param column Column pos of node
+ */
+function parseAsyncArrowAfterIdent(
+ parser: ParserState,
+ context: Context,
+ canAssign: 0 | 1,
+ start: number,
+ line: number,
+ column: number
+) {
+ if (parser.token === Token.AwaitKeyword) report(parser, Errors.AwaitInParameter);
+
+ if (context & (Context.Strict | Context.InYieldContext) && parser.token === Token.YieldKeyword) {
+ report(parser, Errors.YieldInParameter);
+ }
+
+ if ((parser.token & Token.IsEvalOrArguments) === Token.IsEvalOrArguments) {
+ parser.flags |= Flags.StrictEvalArguments;
+ }
+
+ return parseArrowFromIdentifier(
+ parser,
+ context,
+ parser.tokenValue,
+ parseIdentifier(parser, context, 0),
+ 0,
+ canAssign,
+ 1,
+ start,
+ line,
+ column
+ );
+}
+
+/**
+ * Parses async arrow or call expressions
+ *
+ * @param parser Parser object
+ * @param context Context masks
+ * @param callee ESTree AST node
+ * @param assignable
+ * @param kind Binding kind
+ * @param origin Binding origin
+ * @param flags Mutual parser flags
+ * @param start Start pos of node
+ * @param line Line pos of node
+ * @param column Column pos of node
+ */
+
+export function parseAsyncArrowOrCallExpression(
+ parser: ParserState,
+ context: Context,
+ callee: ESTree.Identifier | void,
+ canAssign: 0 | 1,
+ kind: BindingKind,
+ origin: Origin,
+ flags: Flags,
+ start: number,
+ line: number,
+ column: number
+): ESTree.CallExpression | ESTree.ArrowFunctionExpression {
+ nextToken(parser, context | Context.AllowRegExp);
+
+ const scope = context & Context.OptionsLexical ? addChildScope(createScope(), ScopeKind.ArrowParams) : void 0;
+
+ context = (context | Context.DisallowIn) ^ Context.DisallowIn;
+
+ if (consumeOpt(parser, context, Token.RightParen)) {
+ if (parser.token === Token.Arrow) {
+ if (flags & Flags.NewLine) report(parser, Errors.InvalidLineBreak);
+ return parseParenthesizedArrow(parser, context, scope, [], canAssign, 1, start, line, column);
+ }
+
+ return finishNode(parser, context, start, line, column, {
+ type: 'CallExpression',
+ callee,
+ arguments: []
+ });
+ }
+
+ let destructible: AssignmentKind | DestructuringKind = 0;
+ let expr: ESTree.Expression | null = null;
+ let isSimpleParameterList: 0 | 1 = 0;
+
+ parser.destructible =
+ (parser.destructible | DestructuringKind.Yield | DestructuringKind.Await) ^
+ (DestructuringKind.Yield | DestructuringKind.Await);
+
+ const params: ESTree.Expression[] = [];
+
+ while (parser.token !== Token.RightParen) {
+ const { token, tokenPos, linePos, colPos } = parser;
+
+ if (token & (Token.IsIdentifier | Token.Keyword)) {
+ if (scope) addBlockName(parser, context, scope, parser.tokenValue, kind, Origin.None);
+
+ expr = parsePrimaryExpression(parser, context, kind, 0, 1, 0, 1, 1, tokenPos, linePos, colPos);
+
+ if (parser.token === Token.RightParen || parser.token === Token.Comma) {
+ if (parser.assignable & AssignmentKind.CannotAssign) {
+ destructible |= DestructuringKind.CannotDestruct;
+ isSimpleParameterList = 1;
+ } else if ((token & Token.IsEvalOrArguments) === Token.IsEvalOrArguments) {
+ parser.flags |= Flags.StrictEvalArguments;
+ } else if ((token & Token.FutureReserved) === Token.FutureReserved) {
+ parser.flags |= Flags.HasStrictReserved;
+ }
+ } else {
+ if (parser.token === Token.Assign) {
+ isSimpleParameterList = 1;
+ } else {
+ destructible |= DestructuringKind.CannotDestruct;
+ }
+
+ expr = parseMemberOrUpdateExpression(
+ parser,
+ context,
+ expr as ESTree.Expression,
+ 1,
+ 0,
+ tokenPos,
+ linePos,
+ colPos
+ );
+
+ if (parser.token !== Token.RightParen && parser.token !== Token.Comma) {
+ expr = parseAssignmentExpression(parser, context, 1, 0, tokenPos, linePos, colPos, expr as ESTree.Expression);
+ }
+ }
+ } else if (token & Token.IsPatternStart) {
+ expr =
+ token === Token.LeftBrace
+ ? parseObjectLiteralOrPattern(parser, context, scope, 0, 1, 0, kind, origin, tokenPos, linePos, colPos)
+ : parseArrayExpressionOrPattern(parser, context, scope, 0, 1, 0, kind, origin, tokenPos, linePos, colPos);
+
+ destructible |= parser.destructible;
+
+ isSimpleParameterList = 1;
+
+ if (parser.token !== Token.RightParen && parser.token !== Token.Comma) {
+ if (destructible & DestructuringKind.HasToDestruct) report(parser, Errors.InvalidPatternTail);
+
+ expr = parseMemberOrUpdateExpression(parser, context, expr, 0, 0, tokenPos, linePos, colPos);
+
+ destructible |= DestructuringKind.CannotDestruct;
+
+ if ((parser.token & Token.IsBinaryOp) === Token.IsBinaryOp) {
+ expr = parseBinaryExpression(parser, context, 1, start, line, column, 4, token, expr as ESTree.Expression);
+ }
+ if (consumeOpt(parser, context | Context.AllowRegExp, Token.QuestionMark)) {
+ expr = parseConditionalExpression(parser, context, expr as ESTree.Expression, start, line, column);
+ }
+ }
+ } else if (token === Token.Ellipsis) {
+ expr = parseSpreadOrRestElement(
+ parser,
+ context,
+ scope,
+ Token.RightParen,
+ kind,
+ origin,
+ 1,
+ 1,
+ 0,
+ tokenPos,
+ linePos,
+ colPos
+ );
+
+ destructible |= (parser.token === Token.RightParen ? 0 : DestructuringKind.CannotDestruct) | parser.destructible;
+
+ isSimpleParameterList = 1;
+ } else {
+ expr = parseExpression(parser, context, 1, 0, 0, tokenPos, linePos, colPos);
+
+ destructible = parser.assignable;
+
+ params.push(expr);
+
+ while (consumeOpt(parser, context | Context.AllowRegExp, Token.Comma)) {
+ params.push(parseExpression(parser, context, 1, 0, 0, tokenPos, linePos, colPos));
+ }
+
+ destructible |= parser.assignable;
+
+ consume(parser, context, Token.RightParen);
+
+ parser.destructible = destructible | DestructuringKind.CannotDestruct;
+
+ parser.assignable = AssignmentKind.CannotAssign;
+
+ return finishNode(parser, context, start, line, column, {
+ type: 'CallExpression',
+ callee,
+ arguments: params
+ });
+ }
+
+ params.push(expr as ESTree.Expression);
+
+ if (!consumeOpt(parser, context | Context.AllowRegExp, Token.Comma)) break;
+ }
+
+ consume(parser, context, Token.RightParen);
+
+ destructible |=
+ parser.destructible & DestructuringKind.Yield
+ ? DestructuringKind.Yield
+ : 0 | (parser.destructible & DestructuringKind.Await)
+ ? DestructuringKind.Await
+ : 0;
+
+ if (parser.token === Token.Arrow) {
+ if (destructible & (DestructuringKind.Assignable | DestructuringKind.CannotDestruct))
+ report(parser, Errors.InvalidLHSAsyncArrow);
+ if (parser.flags & Flags.NewLine || flags & Flags.NewLine) report(parser, Errors.InvalidLineBreak);
+ if (destructible & DestructuringKind.Await) report(parser, Errors.AwaitInParameter);
+ if (context & (Context.Strict | Context.InYieldContext) && destructible & DestructuringKind.Yield)
+ report(parser, Errors.YieldInParameter);
+ if (isSimpleParameterList) parser.flags |= Flags.SimpleParameterList;
+
+ return parseParenthesizedArrow(parser, context, scope, params, canAssign, 1, start, line, column);
+ } else if (destructible & DestructuringKind.HasToDestruct) {
+ report(parser, Errors.InvalidShorthandPropInit);
+ }
+
+ parser.assignable = AssignmentKind.CannotAssign;
+
+ return finishNode(parser, context, start, line, column, {
+ type: 'CallExpression',
+ callee,
+ arguments: params
+ });
+}
+
+/**
+ * Parse regular expression literal
+ *
+ * @see [Link](https://tc39.github.io/ecma262/#sec-literals-regular-expression-literals)
+ *
+ * @param parser Parser object
+ * @param context Context masks
+ */
+
+/**
+ * Parses reguar expression literal AST node
+ *
+ * @param parser Parser object
+ * @param context Context masks
+ */
+export function parseRegExpLiteral(
+ parser: ParserState,
+ context: Context,
+ start: number,
+ line: number,
+ column: number
+): ESTree.RegExpLiteral {
+ const { tokenRaw, tokenRegExp, tokenValue } = parser;
+ nextToken(parser, context);
+ parser.assignable = AssignmentKind.CannotAssign;
+ return context & Context.OptionsRaw
+ ? finishNode(parser, context, start, line, column, {
+ type: 'Literal',
+ value: tokenValue,
+ regex: tokenRegExp as { pattern: string; flags: string },
+ raw: tokenRaw
+ })
+ : finishNode(parser, context, start, line, column, {
+ type: 'Literal',
+ value: tokenValue,
+ regex: tokenRegExp as { pattern: string; flags: string }
+ });
+}
+
+/**
+ * Parse class expression
+ *
+ * @param parser Parser object
+ * @param context Context masks
+ * @param ExportDefault
+ */
+export function parseClassDeclaration(
+ parser: ParserState,
+ context: Context,
+ scope: ScopeState | undefined,
+ flags: HoistedClassFlags,
+ start: number,
+ line: number,
+ column: number
+): ESTree.ClassDeclaration {
+ // ClassDeclaration ::
+ // 'class' Identifier ('extends' LeftHandSideExpression)? '{' ClassBody '}'
+ // 'class' ('extends' LeftHandSideExpression)? '{' ClassBody '}'
+ // DecoratorList[?Yield, ?Await]optclassBindingIdentifier[?Yield, ?Await]ClassTail[?Yield, ?Await]
+ // DecoratorList[?Yield, ?Await]optclassClassTail[?Yield, ?Await]
+ //
+ context = (context | Context.InConstructor | Context.Strict) ^ Context.InConstructor;
+
+ let decorators = parseDecorators(parser, context);
+ if (decorators.length) {
+ start = parser.tokenPos;
+ line = parser.linePos;
+ column = parser.colPos;
+ }
+
+ if (parser.leadingDecorators.length) {
+ parser.leadingDecorators.push(...decorators);
+ decorators = parser.leadingDecorators;
+ parser.leadingDecorators = [];
+ }
+
+ nextToken(parser, context);
+ let id: ESTree.Expression | null = null;
+ let superClass: ESTree.Expression | null = null;
+
+ const { tokenValue } = parser;
+
+ if (parser.token & Token.Keyword && parser.token !== Token.ExtendsKeyword) {
+ if (isStrictReservedWord(parser, context, parser.token)) {
+ report(parser, Errors.UnexpectedStrictReserved);
+ }
+
+ if ((parser.token & Token.IsEvalOrArguments) === Token.IsEvalOrArguments) {
+ report(parser, Errors.StrictEvalArguments);
+ }
+
+ if (scope) {
+ // A named class creates a new lexical scope with a const binding of the
+ // class name for the "inner name".
+ addBlockName(parser, context, scope, tokenValue, BindingKind.Class, Origin.None);
+
+ if (flags) {
+ if (flags & HoistedClassFlags.Export) {
+ declareUnboundVariable(parser, tokenValue);
+ }
+ }
+ }
+
+ id = parseIdentifier(parser, context, 0);
+ } else {
+ // Only under the "export default" context, class declaration does not require the class name.
+ //
+ // ExportDeclaration:
+ // ...
+ // export default ClassDeclaration[~Yield, +Default]
+ // ...
+ //
+ // ClassDeclaration[Yield, Default]:
+ // ...
+ // [+Default] class ClassTail[?Yield]
+ //
+ if ((flags & HoistedClassFlags.Hoisted) < 1) report(parser, Errors.DeclNoName, 'Class');
+ }
+ let inheritedContext = context;
+
+ if (consumeOpt(parser, context | Context.AllowRegExp, Token.ExtendsKeyword)) {
+ superClass = parseLeftHandSideExpression(parser, context, 0, 0, 0, parser.tokenPos, parser.linePos, parser.colPos);
+ inheritedContext |= Context.SuperCall;
+ } else {
+ inheritedContext = (inheritedContext | Context.SuperCall) ^ Context.SuperCall;
+ }
+
+ const body = parseClassBody(parser, inheritedContext, context, scope, BindingKind.Empty, Origin.Declaration, 0);
+
+ return finishNode(
+ parser,
+ context,
+ start,
+ line,
+ column,
+ context & Context.OptionsNext
+ ? {
+ type: 'ClassDeclaration',
+ id,
+ superClass,
+ decorators,
+ body
+ }
+ : {
+ type: 'ClassDeclaration',
+ id,
+ superClass,
+ body
+ }
+ );
+}
+
+/**
+ * Parse class expression
+ *
+ * @param parser Parser object
+ * @param context Context masks
+ */
+export function parseClassExpression(
+ parser: ParserState,
+ context: Context,
+ inGroup: 0 | 1,
+ start: number,
+ line: number,
+ column: number
+): ESTree.ClassExpression {
+ // ClassExpression ::
+ // 'class' Identifier ('extends' LeftHandSideExpression)? '{' ClassBody '}'
+ // 'class' ('extends' LeftHandSideExpression)? '{' ClassBody '}'
+ // DecoratorList[?Yield, ?Await]optclassBindingIdentifier[?Yield, ?Await]ClassTail[?Yield, ?Await]
+ //
+
+ let id: ESTree.Expression | null = null;
+ let superClass: ESTree.Expression | null = null;
+
+ // All class code is always strict mode implicitly
+ context = (context | Context.Strict | Context.InConstructor) ^ Context.InConstructor;
+
+ const decorators = parseDecorators(parser, context);
+ if (decorators.length) {
+ start = parser.tokenPos;
+ line = parser.linePos;
+ column = parser.colPos;
+ }
+
+ nextToken(parser, context);
+
+ if (parser.token & Token.Keyword && parser.token !== Token.ExtendsKeyword) {
+ if (isStrictReservedWord(parser, context, parser.token)) report(parser, Errors.UnexpectedStrictReserved);
+ if ((parser.token & Token.IsEvalOrArguments) === Token.IsEvalOrArguments) {
+ report(parser, Errors.StrictEvalArguments);
+ }
+
+ id = parseIdentifier(parser, context, 0);
+ }
+
+ // Second set of context masks to fix 'super' edge cases
+ let inheritedContext = context;
+
+ if (consumeOpt(parser, context | Context.AllowRegExp, Token.ExtendsKeyword)) {
+ superClass = parseLeftHandSideExpression(
+ parser,
+ context,
+ 0,
+ inGroup,
+ 0,
+ parser.tokenPos,
+ parser.linePos,
+ parser.colPos
+ );
+ inheritedContext |= Context.SuperCall;
+ } else {
+ inheritedContext = (inheritedContext | Context.SuperCall) ^ Context.SuperCall;
+ }
+
+ const body = parseClassBody(parser, inheritedContext, context, void 0, BindingKind.Empty, Origin.None, inGroup);
+
+ parser.assignable = AssignmentKind.CannotAssign;
+
+ return finishNode(
+ parser,
+ context,
+ start,
+ line,
+ column,
+ context & Context.OptionsNext
+ ? {
+ type: 'ClassExpression',
+ id,
+ superClass,
+ decorators,
+ body
+ }
+ : {
+ type: 'ClassExpression',
+ id,
+ superClass,
+ body
+ }
+ );
+}
+
+/**
+ * Parses a list of decorators
+ *
+ * @param parser Parser object
+ * @param context Context masks
+ */
+export function parseDecorators(parser: ParserState, context: Context): ESTree.Decorator[] {
+ const list: ESTree.Decorator[] = [];
+
+ if (context & Context.OptionsNext) {
+ while (parser.token === Token.Decorator) {
+ list.push(parseDecoratorList(parser, context, parser.tokenPos, parser.linePos, parser.colPos));
+ }
+ }
+
+ return list;
+}
+
+/**
+ * Parses a list of decorators
+ *
+ * @param parser Parser object
+ * @param context Context masks
+ * @param start
+ */
+
+export function parseDecoratorList(
+ parser: ParserState,
+ context: Context,
+ start: number,
+ line: number,
+ column: number
+): ESTree.Decorator {
+ nextToken(parser, context | Context.AllowRegExp);
+
+ let expression = parsePrimaryExpression(parser, context, BindingKind.Empty, 0, 1, 0, 0, 1, start, line, column);
+
+ expression = parseMemberOrUpdateExpression(parser, context, expression, 0, 0, start, line, column);
+
+ return finishNode(parser, context, start, line, column, {
+ type: 'Decorator',
+ expression
+ });
+}
+/**
+ * Parses class body
+ *
+ * @param parser Parser object
+ * @param context Context masks
+ * @param inheritedContext Second set of context masks
+ * @param type Binding kind
+ * @param origin Binding origin
+ * @param decorators
+ */
+
+export function parseClassBody(
+ parser: ParserState,
+ context: Context,
+ inheritedContext: Context,
+ scope: ScopeState | undefined,
+ kind: BindingKind,
+ origin: Origin,
+ inGroup: 0 | 1
+): ESTree.ClassBody {
+ /**
+ * ClassElement :
+ * static MethodDefinition
+ * MethodDefinition
+ * DecoratorList
+ * DecoratorList static MethodDefinition
+ * DecoratorList PropertyDefinition
+ * DecoratorList static PropertyDefinition
+ *
+ * MethodDefinition :
+ * ClassElementName ( FormalParameterList ) { FunctionBody }
+ * get ClassElementName ( ) { FunctionBody }
+ * set ClassElementName ( PropertySetParameterList ) { FunctionBody }
+ *
+ * ClassElementName :
+ * PropertyName
+ * PrivateIdentifier
+ *
+ * PrivateIdentifier ::
+ * # IdentifierName
+ *
+ * IdentifierName ::
+ * IdentifierStart
+ * IdentifierName IdentifierPart
+ *
+ * IdentifierStart ::
+ * UnicodeIDStart
+ * $
+ * _
+ * \ UnicodeEscapeSequence
+ * IdentifierPart::
+ * UnicodeIDContinue
+ * $
+ * \ UnicodeEscapeSequence
+ * <ZWNJ> <ZWJ>
+ *
+ * UnicodeIDStart::
+ * any Unicode code point with the Unicode property "ID_Start"
+ *
+ * UnicodeIDContinue::
+ * any Unicode code point with the Unicode property "ID_Continue"
+ *
+ * GeneratorMethod :
+ * * ClassElementName ( UniqueFormalParameters ){GeneratorBody}
+ *
+ * AsyncMethod :
+ * async [no LineTerminator here] ClassElementName ( UniqueFormalParameters ) { AsyncFunctionBody }
+ *
+ * AsyncGeneratorMethod :
+ * async [no LineTerminator here]* ClassElementName ( UniqueFormalParameters ) { AsyncGeneratorBody }
+ */
+
+ const { tokenPos, linePos, colPos } = parser;
+
+ consume(parser, context | Context.AllowRegExp, Token.LeftBrace);
+ context = (context | Context.DisallowIn) ^ Context.DisallowIn;
+ parser.flags = (parser.flags | Flags.HasConstructor) ^ Flags.HasConstructor;
+
+ const body: (ESTree.MethodDefinition | ESTree.PropertyDefinition)[] = [];
+ let decorators: ESTree.Decorator[];
+
+ while (parser.token !== Token.RightBrace) {
+ let length = 0;
+
+ // See: https://github.com/tc39/proposal-decorators
+
+ decorators = parseDecorators(parser, context);
+
+ length = decorators.length;
+
+ if (length > 0 && parser.tokenValue === 'constructor') {
+ report(parser, Errors.GeneratorConstructor);
+ }
+
+ if (parser.token === Token.RightBrace) report(parser, Errors.TrailingDecorators);
+
+ if (consumeOpt(parser, context, Token.Semicolon)) {
+ if (length > 0) report(parser, Errors.InvalidDecoratorSemicolon);
+ continue;
+ }
+ body.push(
+ parseClassElementList(
+ parser,
+ context,
+ scope,
+ inheritedContext,
+ kind,
+ decorators,
+ 0,
+ inGroup,
+ parser.tokenPos,
+ parser.linePos,
+ parser.colPos
+ )
+ );
+ }
+ consume(parser, origin & Origin.Declaration ? context | Context.AllowRegExp : context, Token.RightBrace);
+
+ return finishNode(parser, context, tokenPos, linePos, colPos, {
+ type: 'ClassBody',
+ body
+ });
+}
+
+/**
+ * Parses class element list
+ *
+ * @param parser Parser object
+ * @param context Context masks
+ * @param inheritedContext Second set of context masks
+ * @param type Binding type
+ * @param decorators
+ * @param isStatic
+ */
+function parseClassElementList(
+ parser: ParserState,
+ context: Context,
+ scope: ScopeState | undefined,
+ inheritedContext: Context,
+ type: BindingKind,
+ decorators: ESTree.Decorator[],
+ isStatic: 0 | 1,
+ inGroup: 0 | 1,
+ start: number,
+ line: number,
+ column: number
+): ESTree.MethodDefinition | ESTree.PropertyDefinition {
+ let kind: PropertyKind = isStatic ? PropertyKind.Static : PropertyKind.None;
+ let key: ESTree.Expression | ESTree.PrivateIdentifier | null = null;
+
+ const { token, tokenPos, linePos, colPos } = parser;
+
+ if (token & (Token.IsIdentifier | Token.FutureReserved)) {
+ key = parseIdentifier(parser, context, 0);
+
+ switch (token) {
+ case Token.StaticKeyword:
+ if (!isStatic && parser.token !== Token.LeftParen) {
+ return parseClassElementList(
+ parser,
+ context,
+ scope,
+ inheritedContext,
+ type,
+ decorators,
+ 1,
+ inGroup,
+ start,
+ line,
+ column
+ );
+ }
+ break;
+
+ case Token.AsyncKeyword:
+ if (parser.token !== Token.LeftParen && (parser.flags & Flags.NewLine) < 1) {
+ if (context & Context.OptionsNext && (parser.token & Token.IsClassField) === Token.IsClassField) {
+ return parsePropertyDefinition(parser, context, key, kind, decorators, tokenPos, linePos, colPos);
+ }
+
+ kind |= PropertyKind.Async | (optionalBit(parser, context, Token.Multiply) ? PropertyKind.Generator : 0);
+ }
+ break;
+
+ case Token.GetKeyword:
+ if (parser.token !== Token.LeftParen) {
+ if (context & Context.OptionsNext && (parser.token & Token.IsClassField) === Token.IsClassField) {
+ return parsePropertyDefinition(parser, context, key, kind, decorators, tokenPos, linePos, colPos);
+ }
+ kind |= PropertyKind.Getter;
+ }
+ break;
+
+ case Token.SetKeyword:
+ if (parser.token !== Token.LeftParen) {
+ if (context & Context.OptionsNext && (parser.token & Token.IsClassField) === Token.IsClassField) {
+ return parsePropertyDefinition(parser, context, key, kind, decorators, tokenPos, linePos, colPos);
+ }
+ kind |= PropertyKind.Setter;
+ }
+ break;
+
+ default: // ignore
+ }
+ } else if (token === Token.LeftBracket) {
+ kind |= PropertyKind.Computed;
+ key = parseComputedPropertyName(parser, inheritedContext, inGroup);
+ } else if ((token & Token.IsStringOrNumber) === Token.IsStringOrNumber) {
+ key = parseLiteral(parser, context);
+ } else if (token === Token.Multiply) {
+ kind |= PropertyKind.Generator;
+ nextToken(parser, context); // skip: '*'
+ } else if (context & Context.OptionsNext && parser.token === Token.PrivateField) {
+ kind |= PropertyKind.PrivateField;
+ key = parsePrivateIdentifier(parser, context, tokenPos, linePos, colPos);
+ context = context | Context.InClass;
+ } else if (context & Context.OptionsNext && (parser.token & Token.IsClassField) === Token.IsClassField) {
+ kind |= PropertyKind.ClassField;
+ context = context | Context.InClass;
+ } else if (token === Token.EscapedFutureReserved) {
+ key = parseIdentifier(parser, context, 0);
+ if (parser.token !== Token.LeftParen)
+ report(parser, Errors.UnexpectedToken, KeywordDescTable[parser.token & Token.Type]);
+ } else {
+ report(parser, Errors.UnexpectedToken, KeywordDescTable[parser.token & Token.Type]);
+ }
+
+ if (kind & (PropertyKind.Generator | PropertyKind.Async | PropertyKind.GetSet)) {
+ if (parser.token & Token.IsIdentifier) {
+ key = parseIdentifier(parser, context, 0);
+ } else if ((parser.token & Token.IsStringOrNumber) === Token.IsStringOrNumber) {
+ key = parseLiteral(parser, context);
+ } else if (parser.token === Token.LeftBracket) {
+ kind |= PropertyKind.Computed;
+ key = parseComputedPropertyName(parser, context, /* inGroup */ 0);
+ } else if (parser.token === Token.EscapedFutureReserved) {
+ key = parseIdentifier(parser, context, 0);
+ } else if (context & Context.OptionsNext && parser.token === Token.PrivateField) {
+ kind |= PropertyKind.PrivateField;
+ key = parsePrivateIdentifier(parser, context, tokenPos, linePos, colPos);
+ } else report(parser, Errors.InvalidKeyToken);
+ }
+
+ if ((kind & PropertyKind.Computed) < 1) {
+ if (parser.tokenValue === 'constructor') {
+ if ((parser.token & Token.IsClassField) === Token.IsClassField) {
+ report(parser, Errors.InvalidClassFieldConstructor);
+ } else if ((kind & PropertyKind.Static) < 1 && parser.token === Token.LeftParen) {
+ if (kind & (PropertyKind.GetSet | PropertyKind.Async | PropertyKind.ClassField | PropertyKind.Generator)) {
+ report(parser, Errors.InvalidConstructor, 'accessor');
+ } else if ((context & Context.SuperCall) < 1) {
+ if (parser.flags & Flags.HasConstructor) report(parser, Errors.DuplicateConstructor);
+ else parser.flags |= Flags.HasConstructor;
+ }
+ }
+ kind |= PropertyKind.Constructor;
+ } else if (
+ // Static Async Generator Private Methods can be named "#prototype" (class declaration)
+ (kind & PropertyKind.PrivateField) < 1 &&
+ kind & (PropertyKind.Static | PropertyKind.GetSet | PropertyKind.Generator | PropertyKind.Async) &&
+ parser.tokenValue === 'prototype'
+ ) {
+ report(parser, Errors.StaticPrototype);
+ }
+ }
+
+ if (context & Context.OptionsNext && parser.token !== Token.LeftParen) {
+ return parsePropertyDefinition(parser, context, key, kind, decorators, tokenPos, linePos, colPos);
+ }
+
+ const value = parseMethodDefinition(parser, context, kind, inGroup, parser.tokenPos, parser.linePos, parser.colPos);
+
+ return finishNode(
+ parser,
+ context,
+ start,
+ line,
+ column,
+ context & Context.OptionsNext
+ ? {
+ type: 'MethodDefinition',
+ kind:
+ (kind & PropertyKind.Static) < 1 && kind & PropertyKind.Constructor
+ ? 'constructor'
+ : kind & PropertyKind.Getter
+ ? 'get'
+ : kind & PropertyKind.Setter
+ ? 'set'
+ : 'method',
+ static: (kind & PropertyKind.Static) > 0,
+ computed: (kind & PropertyKind.Computed) > 0,
+ key,
+ decorators,
+ value
+ }
+ : {
+ type: 'MethodDefinition',
+ kind:
+ (kind & PropertyKind.Static) < 1 && kind & PropertyKind.Constructor
+ ? 'constructor'
+ : kind & PropertyKind.Getter
+ ? 'get'
+ : kind & PropertyKind.Setter
+ ? 'set'
+ : 'method',
+ static: (kind & PropertyKind.Static) > 0,
+ computed: (kind & PropertyKind.Computed) > 0,
+ key,
+ value
+ }
+ );
+}
+
+/**
+ * Parses private name
+ *
+ * @param parser Parser object
+ * @param context Context masks
+ */
+function parsePrivateIdentifier(
+ parser: ParserState,
+ context: Context,
+ start: number,
+ line: number,
+ column: number
+): ESTree.PrivateIdentifier {
+ // PrivateIdentifier::
+ // #IdentifierName
+ nextToken(parser, context); // skip: '#'
+ const { tokenValue } = parser;
+ if (tokenValue === 'constructor') report(parser, Errors.InvalidStaticClassFieldConstructor);
+ nextToken(parser, context);
+
+ return finishNode(parser, context, start, line, column, {
+ type: 'PrivateIdentifier',
+ name: tokenValue
+ });
+}
+
+/**
+ * Parses field definition
+ *
+ * @param parser Parser object
+ * @param context Context masks
+ * @param key ESTree AST node
+ * @param state
+ * @param decorators
+ */
+
+export function parsePropertyDefinition(
+ parser: ParserState,
+ context: Context,
+ key: ESTree.PrivateIdentifier | ESTree.Expression | null,
+ state: PropertyKind,
+ decorators: ESTree.Decorator[] | null,
+ start: number,
+ line: number,
+ column: number
+): ESTree.PropertyDefinition {
+ // ClassElement :
+ // MethodDefinition
+ // static MethodDefinition
+ // PropertyDefinition ;
+ // ;
+ let value: ESTree.Expression | null = null;
+
+ if (state & PropertyKind.Generator) report(parser, Errors.Unexpected);
+
+ if (parser.token === Token.Assign) {
+ nextToken(parser, context | Context.AllowRegExp);
+
+ const { tokenPos, linePos, colPos } = parser;
+
+ if (parser.token === Token.Arguments) report(parser, Errors.StrictEvalArguments);
+
+ value = parsePrimaryExpression(
+ parser,
+ context | Context.InClass,
+ BindingKind.Empty,
+ 0,
+ 1,
+ 0,
+ 0,
+ 1,
+ tokenPos,
+ linePos,
+ colPos
+ );
+
+ if ((parser.token & Token.IsClassField) !== Token.IsClassField) {
+ value = parseMemberOrUpdateExpression(
+ parser,
+ context | Context.InClass,
+ value as ESTree.Expression,
+ 0,
+ 0,
+ tokenPos,
+ linePos,
+ colPos
+ );
+
+ value = parseAssignmentExpression(parser, context | Context.InClass, 0, 0, tokenPos, linePos, colPos, value);
+ if (parser.token === Token.Comma) {
+ value = parseSequenceExpression(parser, context, 0, start, line, column, value as any);
+ }
+ }
+ }
+
+ return finishNode(parser, context, start, line, column, {
+ type: 'PropertyDefinition',
+ key,
+ value,
+ static: (state & PropertyKind.Static) > 0,
+ computed: (state & PropertyKind.Computed) > 0,
+ decorators
+ } as any);
+}
+
+/**
+ * Parses binding pattern
+ *
+ * @param parser Parser object
+ * @param context Context masks
+ * @param type Binding kind
+ */
+export function parseBindingPattern(
+ parser: ParserState,
+ context: Context,
+ scope: ScopeState | undefined,
+ type: BindingKind,
+ origin: Origin,
+ start: number,
+ line: number,
+ column: number
+): ESTree.BindingPattern {
+ // Pattern ::
+ // Identifier
+ // ArrayLiteral
+ // ObjectLiteral
+
+ if (parser.token & Token.IsIdentifier)
+ return parseAndClassifyIdentifier(parser, context, scope, type, origin, start, line, column);
+
+ if ((parser.token & Token.IsPatternStart) !== Token.IsPatternStart)
+ report(parser, Errors.UnexpectedToken, KeywordDescTable[parser.token & Token.Type]);
+
+ const left: any =
+ parser.token === Token.LeftBracket
+ ? parseArrayExpressionOrPattern(parser, context, scope, 1, 0, 1, type, origin, start, line, column)
+ : parseObjectLiteralOrPattern(parser, context, scope, 1, 0, 1, type, origin, start, line, column);
+
+ if (parser.destructible & DestructuringKind.CannotDestruct) report(parser, Errors.InvalidBindingDestruct);
+
+ if (parser.destructible & DestructuringKind.Assignable) report(parser, Errors.InvalidBindingDestruct);
+
+ return left;
+}
+
+/**
+ * Classify and parse identifier if of valid type
+ *
+ * @param parser Parser object
+ * @param context Context masks
+ * @param type Binding kind
+ */
+function parseAndClassifyIdentifier(
+ parser: ParserState,
+ context: Context,
+ scope: ScopeState | undefined,
+ kind: BindingKind,
+ origin: Origin,
+ start: number,
+ line: number,
+ column: number
+): ESTree.Identifier {
+ const { tokenValue, token } = parser;
+
+ if (context & Context.Strict) {
+ if ((token & Token.IsEvalOrArguments) === Token.IsEvalOrArguments) {
+ report(parser, Errors.StrictEvalArguments);
+ } else if ((token & Token.FutureReserved) === Token.FutureReserved) {
+ report(parser, Errors.UnexpectedStrictReserved);
+ }
+ }
+
+ if ((token & Token.Reserved) === Token.Reserved) {
+ report(parser, Errors.KeywordNotId);
+ }
+
+ if (context & (Context.Module | Context.InYieldContext) && token === Token.YieldKeyword) {
+ report(parser, Errors.YieldInParameter);
+ }
+ if (token === Token.LetKeyword) {
+ if (kind & (BindingKind.Let | BindingKind.Const)) report(parser, Errors.InvalidLetConstBinding);
+ }
+ if (context & (Context.InAwaitContext | Context.Module) && token === Token.AwaitKeyword) {
+ report(parser, Errors.AwaitOutsideAsync);
+ }
+
+ nextToken(parser, context);
+
+ if (scope) addVarOrBlock(parser, context, scope, tokenValue, kind, origin);
+
+ return finishNode(parser, context, start, line, column, {
+ type: 'Identifier',
+ name: tokenValue
+ });
+}
+
+/**
+ * Parses either a JSX element or JSX Fragment
+ *
+ * @param parser Parser object
+ * @param context Context masks
+ * @param inJSXChild
+ * @param start
+ * @param line
+ * @param column
+ */
+
+function parseJSXRootElementOrFragment(
+ parser: ParserState,
+ context: Context,
+ inJSXChild: 0 | 1,
+ start: number,
+ line: number,
+ column: number
+): ESTree.JSXElement | ESTree.JSXFragment {
+ nextToken(parser, context);
+
+ // JSX fragments
+ if (parser.token === Token.GreaterThan) {
+ return finishNode(parser, context, start, line, column, {
+ type: 'JSXFragment',
+ openingFragment: parseOpeningFragment(parser, context, start, line, column),
+ children: parseJSXChildren(parser, context),
+ closingFragment: parseJSXClosingFragment(
+ parser,
+ context,
+ inJSXChild,
+ parser.tokenPos,
+ parser.linePos,
+ parser.colPos
+ )
+ });
+ }
+
+ let closingElement: ESTree.JSXClosingElement | null = null;
+ let children: ESTree.JSXChild[] = [];
+
+ const openingElement: ESTree.JSXOpeningElement = parseJSXOpeningFragmentOrSelfCloseElement(
+ parser,
+ context,
+ inJSXChild,
+ start,
+ line,
+ column
+ );
+
+ if (!openingElement.selfClosing) {
+ children = parseJSXChildren(parser, context);
+ closingElement = parseJSXClosingElement(
+ parser,
+ context,
+ inJSXChild,
+ parser.tokenPos,
+ parser.linePos,
+ parser.colPos
+ );
+ const close = isEqualTagName(closingElement.name);
+ if (isEqualTagName(openingElement.name) !== close) report(parser, Errors.ExpectedJSXClosingTag, close);
+ }
+
+ return finishNode(parser, context, start, line, column, {
+ type: 'JSXElement',
+ children,
+ openingElement,
+ closingElement
+ });
+}
+
+/**
+ * Parses JSX opening fragment
+ *
+ * @param parser Parser object
+ * @param context Context masks
+ * @param start
+ * @param line
+ * @param column
+ */
+export function parseOpeningFragment(
+ parser: ParserState,
+ context: Context,
+ start: number,
+ line: number,
+ column: number
+): ESTree.JSXOpeningFragment {
+ scanJSXToken(parser, context);
+ return finishNode(parser, context, start, line, column, {
+ type: 'JSXOpeningFragment'
+ });
+}
+
+/**
+ * Parses JSX Closing element
+ *
+ * @param parser Parser object
+ * @param context Context masks
+ * @param inJSXChild
+ * @param start
+ * @param line
+ * @param column
+ */
+function parseJSXClosingElement(
+ parser: ParserState,
+ context: Context,
+ inJSXChild: 0 | 1,
+ start: number,
+ line: number,
+ column: number
+): ESTree.JSXClosingElement {
+ consume(parser, context, Token.JSXClose);
+ const name = parseJSXElementName(parser, context, parser.tokenPos, parser.linePos, parser.colPos);
+ if (inJSXChild) {
+ consume(parser, context, Token.GreaterThan);
+ } else {
+ parser.token = scanJSXToken(parser, context);
+ }
+
+ return finishNode(parser, context, start, line, column, {
+ type: 'JSXClosingElement',
+ name
+ });
+}
+
+/**
+ * Parses JSX closing fragment
+ *
+ * @param parser Parser object
+ * @param context Context masks
+ * @param inJSXChild
+ * @param start
+ * @param line
+ * @param column
+ */
+export function parseJSXClosingFragment(
+ parser: ParserState,
+ context: Context,
+ inJSXChild: 0 | 1,
+ start: number,
+ line: number,
+ column: number
+): ESTree.JSXClosingFragment {
+ consume(parser, context, Token.JSXClose);
+
+ if (inJSXChild) {
+ consume(parser, context, Token.GreaterThan);
+ } else {
+ consume(parser, context, Token.GreaterThan);
+ }
+
+ return finishNode(parser, context, start, line, column, {
+ type: 'JSXClosingFragment'
+ });
+}
+
+/**
+ * Parses JSX children
+ *
+ * @param parser Parser object
+ * @param context Context masks
+ */
+export function parseJSXChildren(parser: ParserState, context: Context): ESTree.JSXChild[] {
+ const children: ESTree.JSXChild[] = [];
+ while (parser.token !== Token.JSXClose) {
+ parser.index = parser.tokenPos = parser.startPos;
+ parser.column = parser.colPos = parser.startColumn;
+ parser.line = parser.linePos = parser.startLine;
+ scanJSXToken(parser, context);
+ children.push(parseJSXChild(parser, context, parser.tokenPos, parser.linePos, parser.colPos));
+ }
+ return children;
+}
+
+/**
+ * Parses a JSX child node
+ *
+ * @param parser Parser object
+ * @param context Context masks
+ * @param start
+ * @param line
+ * @param column
+ */
+function parseJSXChild(parser: ParserState, context: Context, start: number, line: number, column: number): any {
+ if (parser.token === Token.JSXText) return parseJSXText(parser, context, start, line, column);
+ if (parser.token === Token.LeftBrace)
+ return parseJSXExpressionContainer(parser, context, /*inJSXChild*/ 0, /* isAttr */ 0, start, line, column);
+ if (parser.token === Token.LessThan)
+ return parseJSXRootElementOrFragment(parser, context, /*inJSXChild*/ 0, start, line, column);
+ report(parser, Errors.Unexpected);
+}
+
+/**
+ * Parses JSX Text
+ *
+ * @param parser Parser object
+ * @param context Context masks
+ * @param start
+ * @param line
+ * @param column
+ */
+export function parseJSXText(
+ parser: ParserState,
+ context: Context,
+ start: number,
+ line: number,
+ column: number
+): ESTree.JSXText {
+ scanJSXToken(parser, context);
+
+ const node = {
+ type: 'JSXText',
+ value: parser.tokenValue as string
+ } as ESTree.JSXText;
+
+ if (context & Context.OptionsRaw) {
+ node.raw = parser.tokenRaw;
+ }
+
+ return finishNode(parser, context, start, line, column, node);
+}
+
+/**
+ * Parses either a JSX element, JSX Fragment or JSX self close element
+ *
+ * @param parser Parser object
+ * @param context Context masks
+ * @param inJSXChild
+ * @param start
+ * @param line
+ * @param column
+ */
+function parseJSXOpeningFragmentOrSelfCloseElement(
+ parser: ParserState,
+ context: Context,
+ inJSXChild: 0 | 1,
+ start: number,
+ line: number,
+ column: number
+): ESTree.JSXOpeningElement {
+ if ((parser.token & Token.IsIdentifier) !== Token.IsIdentifier && (parser.token & Token.Keyword) !== Token.Keyword)
+ report(parser, Errors.Unexpected);
+
+ const tagName = parseJSXElementName(parser, context, parser.tokenPos, parser.linePos, parser.colPos);
+ const attributes = parseJSXAttributes(parser, context);
+ const selfClosing = parser.token === Token.Divide;
+
+ if (parser.token === Token.GreaterThan) {
+ scanJSXToken(parser, context);
+ } else {
+ consume(parser, context, Token.Divide);
+ if (inJSXChild) {
+ consume(parser, context, Token.GreaterThan);
+ } else {
+ scanJSXToken(parser, context);
+ }
+ }
+
+ return finishNode(parser, context, start, line, column, {
+ type: 'JSXOpeningElement',
+ name: tagName,
+ attributes,
+ selfClosing
+ });
+}
+
+/**
+ * Parses JSX element name
+ *
+ * @param parser Parser object
+ * @param context Context masks
+ * @param start
+ * @param line
+ * @param column
+ */
+function parseJSXElementName(
+ parser: ParserState,
+ context: Context,
+ start: number,
+ line: number,
+ column: number
+): ESTree.JSXIdentifier | ESTree.JSXMemberExpression | ESTree.JSXNamespacedName {
+ scanJSXIdentifier(parser);
+
+ let key: ESTree.JSXIdentifier | ESTree.JSXMemberExpression = parseJSXIdentifier(parser, context, start, line, column);
+
+ // Namespace
+ if (parser.token === Token.Colon) return parseJSXNamespacedName(parser, context, key, start, line, column);
+
+ // Member expression
+ while (consumeOpt(parser, context, Token.Period)) {
+ scanJSXIdentifier(parser);
+ key = parseJSXMemberExpression(parser, context, key, start, line, column);
+ }
+ return key;
+}
+
+/**
+ * Parses JSX member expression
+ *
+ * @param parser Parser object
+ * @param context Context masks
+ * @param start
+ * @param line
+ * @param column
+ */
+export function parseJSXMemberExpression(
+ parser: ParserState,
+ context: Context,
+ object: ESTree.JSXIdentifier | ESTree.JSXMemberExpression,
+ start: number,
+ line: number,
+ column: number
+): ESTree.JSXMemberExpression {
+ const property = parseJSXIdentifier(parser, context, parser.tokenPos, parser.linePos, parser.colPos);
+ return finishNode(parser, context, start, line, column, {
+ type: 'JSXMemberExpression',
+ object,
+ property
+ });
+}
+
+/**
+ * Parses JSX attributes
+ *
+ * @param parser Parser object
+ * @param context Context masks
+ * @param start
+ * @param line
+ * @param column
+ */
+export function parseJSXAttributes(
+ parser: ParserState,
+ context: Context
+): (ESTree.JSXAttribute | ESTree.JSXSpreadAttribute)[] {
+ const attributes: (ESTree.JSXAttribute | ESTree.JSXSpreadAttribute)[] = [];
+ while (parser.token !== Token.Divide && parser.token !== Token.GreaterThan && parser.token !== Token.EOF) {
+ attributes.push(parseJsxAttribute(parser, context, parser.tokenPos, parser.linePos, parser.colPos));
+ }
+ return attributes;
+}
+
+/**
+ * Parses JSX Spread attribute
+ *
+ * @param parser Parser object
+ * @param context Context masks
+ * @param start
+ * @param line
+ * @param column
+ */
+export function parseJSXSpreadAttribute(
+ parser: ParserState,
+ context: Context,
+ start: number,
+ line: number,
+ column: number
+): ESTree.JSXSpreadAttribute {
+ nextToken(parser, context); // skips: '{'
+ consume(parser, context, Token.Ellipsis);
+ const expression = parseExpression(parser, context, 1, 0, 0, parser.tokenPos, parser.linePos, parser.colPos);
+ consume(parser, context, Token.RightBrace);
+ return finishNode(parser, context, start, line, column, {
+ type: 'JSXSpreadAttribute',
+ argument: expression
+ });
+}
+
+/**
+ * Parses JSX attribute
+ *
+ * @param parser Parser object
+ * @param context Context masks
+ * @param start
+ * @param line
+ * @param column
+ */
+function parseJsxAttribute(
+ parser: ParserState,
+ context: Context,
+ start: number,
+ line: number,
+ column: number
+): ESTree.JSXAttribute | ESTree.JSXSpreadAttribute {
+ if (parser.token === Token.LeftBrace) return parseJSXSpreadAttribute(parser, context, start, line, column);
+ scanJSXIdentifier(parser);
+ let value: ESTree.JSXAttributeValue | null = null;
+ let name: ESTree.JSXNamespacedName | ESTree.JSXIdentifier = parseJSXIdentifier(parser, context, start, line, column);
+
+ if (parser.token === Token.Colon) {
+ name = parseJSXNamespacedName(parser, context, name, start, line, column);
+ }
+
+ // HTML empty attribute
+ if (parser.token === Token.Assign) {
+ const token = scanJSXAttributeValue(parser, context);
+ const { tokenPos, linePos, colPos } = parser;
+ switch (token) {
+ case Token.StringLiteral:
+ value = parseLiteral(parser, context);
+ break;
+ case Token.LessThan:
+ value = parseJSXRootElementOrFragment(parser, context, /*inJSXChild*/ 1, tokenPos, linePos, colPos);
+ break;
+ case Token.LeftBrace:
+ value = parseJSXExpressionContainer(parser, context, 1, 1, tokenPos, linePos, colPos);
+ break;
+ default:
+ report(parser, Errors.InvalidJSXAttributeValue);
+ }
+ }
+
+ return finishNode(parser, context, start, line, column, {
+ type: 'JSXAttribute',
+ value,
+ name
+ });
+}
+
+/**
+ * Parses JSX namespace name
+ *
+ * @param parser Parser object
+ * @param context Context masks
+ * @param namespace
+ * @param start
+ * @param line
+ * @param column
+ */
+
+function parseJSXNamespacedName(
+ parser: ParserState,
+ context: Context,
+ namespace: ESTree.JSXIdentifier | ESTree.JSXMemberExpression,
+ start: number,
+ line: number,
+ column: number
+): ESTree.JSXNamespacedName {
+ consume(parser, context, Token.Colon);
+ const name = parseJSXIdentifier(parser, context, parser.tokenPos, parser.linePos, parser.colPos);
+ return finishNode(parser, context, start, line, column, {
+ type: 'JSXNamespacedName',
+ namespace,
+ name
+ });
+}
+
+/**
+ * Parses JSX Expression container
+ *
+ * @param parser Parser object
+ * @param context Context masks
+ * @param inJSXChild
+ * @param start
+ * @param line
+ * @param column
+ */
+function parseJSXExpressionContainer(
+ parser: ParserState,
+ context: Context,
+ inJSXChild: 0 | 1,
+ isAttr: 0 | 1,
+ start: number,
+ line: number,
+ column: number
+): ESTree.JSXExpressionContainer | ESTree.JSXSpreadChild {
+ nextToken(parser, context);
+ const { tokenPos, linePos, colPos } = parser;
+ if (parser.token === Token.Ellipsis) return parseJSXSpreadChild(parser, context, tokenPos, linePos, colPos);
+
+ let expression: ESTree.Expression | ESTree.JSXEmptyExpression | null = null;
+
+ if (parser.token === Token.RightBrace) {
+ // JSX attributes must only be assigned a non-empty 'expression'
+ if (isAttr) report(parser, Errors.InvalidNonEmptyJSXExpr);
+ expression = parseJSXEmptyExpression(parser, context, parser.startPos, parser.startLine, parser.startColumn);
+ } else {
+ expression = parseExpression(parser, context, 1, 0, 0, tokenPos, linePos, colPos);
+ }
+ if (inJSXChild) {
+ consume(parser, context, Token.RightBrace);
+ } else {
+ scanJSXToken(parser, context);
+ }
+
+ return finishNode(parser, context, start, line, column, {
+ type: 'JSXExpressionContainer',
+ expression
+ });
+}
+
+/**
+ * Parses JSX spread child
+ *
+ * @param parser Parser object
+ * @param context Context masks
+ * @param start
+ * @param line
+ * @param column
+ */
+function parseJSXSpreadChild(
+ parser: ParserState,
+ context: Context,
+ start: number,
+ line: number,
+ column: number
+): ESTree.JSXSpreadChild {
+ consume(parser, context, Token.Ellipsis);
+ const expression = parseExpression(parser, context, 1, 0, 0, parser.tokenPos, parser.linePos, parser.colPos);
+ consume(parser, context, Token.RightBrace);
+ return finishNode(parser, context, start, line, column, {
+ type: 'JSXSpreadChild',
+ expression
+ });
+}
+
+/**
+ * Parses JSX empty expression
+ *
+ * @param parser Parser object
+ * @param context Context masks
+ * @param start
+ * @param line
+ * @param column
+ */
+function parseJSXEmptyExpression(
+ parser: ParserState,
+ context: Context,
+ start: number,
+ line: number,
+ column: number
+): ESTree.JSXEmptyExpression {
+ // Since " }" is treated as single token, we have to artificially break
+ // it into " " and "}".
+ // Move token start from beginning of whitespace(s) to beginning of "}",
+ // so JSXEmptyExpression can have correct end loc.
+ parser.startPos = parser.tokenPos;
+ parser.startLine = parser.linePos;
+ parser.startColumn = parser.colPos;
+ return finishNode(parser, context, start, line, column, {
+ type: 'JSXEmptyExpression'
+ });
+}
+
+/**
+ * Parses JSX Identifier
+ *
+ * @param parser Parser object
+ * @param context Context masks
+ * @param start
+ * @param line
+ * @param column
+ */
+export function parseJSXIdentifier(
+ parser: ParserState,
+ context: Context,
+ start: number,
+ line: number,
+ column: number
+): ESTree.JSXIdentifier {
+ const { tokenValue } = parser;
+ nextToken(parser, context);
+
+ return finishNode(parser, context, start, line, column, {
+ type: 'JSXIdentifier',
+ name: tokenValue
+ });
+}