UNPKG

aurelia-router-metadata

Version:

Adds decorator configuration with conventions and eager loading capabilities to aurelia-router

8,518 lines 343 kB
'use strict';

Object.defineProperty(exports, '__esModule', { value: true });

var aureliaPal = require('aurelia-pal');
var aureliaDependencyInjection = require('aurelia-dependency-injection');
var aureliaRouter = require('aurelia-router');
var aureliaLogging = require('aurelia-logging');
var aureliaLoader = require('aurelia-loader');

// tslint:disable:max-classes-per-file
class $Application {
    constructor() {
        this._modules = [];
        this._exports = [];
    }
    get $modules() {
        return this._modules;
    }
    get $exports() {
        return this._exports;
    }
    addModule($module) {
        this.$modules.push($module);
        this.$exports.push(...$module.$exports);
    }
}
class $Module {
    constructor(application, moduleId, raw) {
        this._exports = [];
        this._defaultExport = null;
        this._application = application;
        this._moduleId = moduleId;
        this._raw = raw;
    }
    get $application() {
        return this._application;
    }
    get moduleId() {
        return this._moduleId;
    }
    get raw() {
        return this._raw;
    }
    get $exports() {
        return this._exports;
    }
    get $defaultExport() {
        return this._defaultExport;
    }
    set $defaultExport(value) {
        if (this._defaultExport !== null) {
            throw new Error("defaultExport can only be set once");
        }
        this._defaultExport = value;
    }
    addExport($export) {
        this.$exports.push($export);
    }
}
class $Export {
    constructor($module, name) {
        this._constructor = null;
        this._prototype = null;
        this._module = $module;
        this._name = name;
    }
    get $application() {
        return this.$module.$application;
    }
    get moduleId() {
        return this.$module.moduleId;
    }
    get exportPath() {
        return `${this.$module.moduleId}::${this.name}`;
    }
    get $module() {
        return this._module;
    }
    get name() {
        return this._name;
    }
    get $constructor() {
        return this._constructor;
    }
    set $constructor(value) {
        if (this._constructor !== null) {
            throw new Error("constructor can only be set once");
        }
        this._constructor = value;
    }
    get $prototype() {
        return this._prototype;
    }
    set $prototype(value) {
        if (this._prototype !== null) {
            throw new Error("prototype can only be set once");
        }
        this._prototype = value;
    }
    get hasBase() {
        return this.$constructor.hasBase;
    }
    get $base() {
        return (this.$constructor.$base && this.$constructor.$base.$export) || null;
    }
}
class $Constructor {
    constructor($export, name, raw) {
        this._properties = [];
        this._base = null;
        this._export = $export;
        this._name = name;
        this._raw = raw;
        this._hasBase = Object.getPrototypeOf(raw) !== Function.prototype;
    }
    get $application() {
        return this.$export.$application;
    }
    get moduleId() {
        return this.$export.moduleId;
    }
    get exportPath() {
        return this.$export.exportPath;
    }
    get $module() {
        return this.$export.$module;
    }
    get $export() {
        return this._export;
    }
    get name() {
        return this._name;
    }
    get $properties() {
        return this._properties;
    }
    get raw() {
        return this._raw;
    }
    get hasBase() {
        return this._hasBase;
    }
    get $base() {
        return this._base;
    }
    set $base(value) {
        if (this._base !== null) {
            throw new Error("base can only be set once");
        }
        this._base = value;
    }
    addProperty($property) {
        this.$properties.push($property);
    }
}
class $Prototype {
    constructor($export, name, raw) {
        this._properties = [];
        this._base = null;
        this._export = $export;
        this._name = name;
        this._raw = raw;
        this._hasBase = Object.getPrototypeOf(raw) !== Object.prototype;
    }
    get $application() {
        return this.$export.$application;
    }
    get moduleId() {
        return this.$export.moduleId;
    }
    get exportPath() {
        return this.$export.exportPath;
    }
    get $module() {
        return this.$export.$module;
    }
    get $export() {
        return this._export;
    }
    get name() {
        return this._name;
    }
    get $properties() {
        return this._properties;
    }
    get raw() {
        return this._raw;
    }
    get hasBase() {
        return this._hasBase;
    }
    get $base() {
        return this._base;
    }
    set $base(value) {
        if (this._base !== null) {
            throw new Error("base can only be set once");
        }
        this._base = value;
    }
    addProperty($property) {
        this.$properties.push($property);
    }
}
class $Property {
    get $application() {
        return this.$object.$application;
    }
    get moduleId() {
        return this.$object.moduleId;
    }
    get $module() {
        return this.$object.$module;
    }
    get $export() {
        return this.$object.$export;
    }
    get $object() {
        return this._object;
    }
    get descriptor() {
        return this._descriptor;
    }
    get key() {
        return this._key;
    }
    get isStatic() {
        return this._isStatic;
    }
    constructor($object, key, descriptor) {
        this._object = $object;
        this._key = key;
        this._isStatic = $object instanceof $Constructor;
        this._descriptor = descriptor;
    }
}

function allObjectKeys(obj) {
    const names = Object.getOwnPropertyNames(obj);
    const symbols = Object.getOwnPropertySymbols(obj);
    return names.concat(symbols);
}
function ensureArray(value) {
    if (value === null || value === undefined) {
        return [];
    }
    return Array.isArray(value) ? value : [value];
}
function splitRouteConfig(configs) {
    if (configs.length === 0) {
        return configs;
    }
    const result = [];
    for (const config of configs) {
        if (Object.prototype.hasOwnProperty.call(config, "route")) {
            if (/String/.test(Object.prototype.toString.call(config.route))) {
                result.push([config]);
            }
            else if (Array.isArray(config.route)) {
                if (config.route.length === 0) {
                    delete config.route;
                    result.push([config]);
                }
                else {
                    result.push(config.route.map(r => (Object.assign({}, config, { route: r }))));
                }
            }
            else {
                delete config.route;
                result.push([config]);
            }
        }
        else {
            result.push([config]);
        }
    }
    return result.reduce((prev, cur) => prev.concat(cur));
}

class Registry {
    constructor() {
        this.cache = Object.create(null);
        this.moduleIds = new Set();
        this.$application = new $Application();
    }
    getModule(normalizedId) {
        let $module = this.cache[normalizedId];
        if ($module === undefined) {
            let moduleExport;
            aureliaPal.PLATFORM.eachModule((moduleId, value) => {
                if (moduleId === normalizedId) {
                    moduleExport = value;
                    return true;
                }
                else {
                    return false;
                }
            });
            if (moduleExport !== undefined) {
                $module = this.registerModule(moduleExport, normalizedId);
            }
        }
        return $module;
    }
    registerModuleViaConstructor($constructor) {
        let moduleInstance;
        let moduleId;
        aureliaPal.PLATFORM.eachModule((key, value) => {
            if (typeof value === "object") {
                for (const name of Object.keys(value)) {
                    if (value[name] === $constructor) {
                        moduleInstance = value;
                        moduleId = key;
                        return true;
                    }
                }
            }
            if (value === $constructor) {
                moduleInstance = value;
                moduleId = key;
                return true;
            }
            else {
                return false;
            }
        });
        if (!moduleInstance || !moduleId) {
            throw new Error(`No module could be found for constructor ${$constructor}`);
        }
        return this.registerModule(moduleInstance, moduleId);
    }
    registerModule(moduleInstance, moduleId) {
        this.moduleIds.add(moduleId);
        const $module = (this.cache[moduleId] = new $Module(this.$application, moduleId, moduleInstance));
        this.$application.addModule($module);
        if (moduleInstance instanceof Function) {
            this.registerModuleExport($module, "default", moduleInstance);
        }
        else {
            for (const exportName of Object.keys(moduleInstance)) {
                const exportValue = moduleInstance[exportName];
                if (exportValue instanceof Function) {
                    this.registerModuleExport($module, exportName, exportValue);
                }
            }
        }
        return $module;
    }
    registerModuleExport($module, exportName, exportValue) {
        if (!Object.prototype.hasOwnProperty.call(exportValue, "prototype")) {
            return;
        }
        const $export = new $Export($module, exportName);
        $export.$constructor = new $Constructor($export, exportName, exportValue);
        $export.$prototype = new $Prototype($export, exportName, exportValue.prototype);
        $module.addExport($export);
        if ($module.$defaultExport === null) {
            $module.$defaultExport = $export;
        }
        this.registerProperties($export.$constructor);
        this.registerProperties($export.$prototype);
        const ownNeedsBase = $export.hasBase && $export.$base === null;
        const ownRaw = $export.$constructor.raw;
        const ownBase = Object.getPrototypeOf(ownRaw);
        for (const $other of this.$application.$exports) {
            const otherNeedsBase = $other.hasBase && $other.$base === null;
            const otherRaw = $other.$constructor.raw;
            if (ownNeedsBase && ownBase === otherRaw) {
                $export.$constructor.$base = $other.$constructor;
                $export.$prototype.$base = $other.$prototype;
            }
            else if (otherNeedsBase) {
                const otherBase = Object.getPrototypeOf(otherRaw);
                if (otherBase === ownRaw) {
                    $other.$constructor.$base = $export.$constructor;
                    $other.$prototype.$base = $export.$prototype;
                }
            }
        }
    }
    registerProperties($object) {
        const obj = $object.raw;
        for (const key of allObjectKeys(obj)) {
            const descriptor = Object.getOwnPropertyDescriptor(obj, key);
            const propertySymbol = new $Property($object, key, descriptor);
            $object.addProperty(propertySymbol);
        }
    }
}

/*! *****************************************************************************
Copyright (c) Microsoft Corporation. All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License"); you may not use
this file except in compliance with the License. You may obtain a copy of the
License at http://www.apache.org/licenses/LICENSE-2.0

THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED
WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE,
MERCHANTABLITY OR NON-INFRINGEMENT.

See the Apache Version 2.0 License for specific language governing permissions
and limitations under the License.
***************************************************************************** */

function __awaiter(thisArg, _arguments, P, generator) {
    return new (P || (P = Promise))(function (resolve, reject) {
        function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
        function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
        function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
        step((generator = generator.apply(thisArg, _arguments || [])).next());
    });
}

// Note: this *must* be kept in sync with the enum's order.
//
// It exploits the enum value ordering, and it's necessarily a complete and
// utter hack.
//
// All to lower it to a single monomorphic array access.
const keywordDescTable = [
    'end of source',
    /* Constants/Bindings */
    'identifier', 'number', 'string', 'regular expression',
    'false', 'true', 'null',
    /* Template nodes */
    'template continuation', 'template end',
    /* Punctuators */
    '=>', '(', '{', '.', '...', '}', ')', ';', ',', '[', ']', ':', '?', '\'', '"', '</', '/>',
    /* Update operators */
    '++', '--',
    /* Assign operators */
    '=', '<<=', '>>=', '>>>=', '**=', '+=', '-=', '*=', '/=', '%=', '^=', '|=',
    '&=',
    /* Unary/binary operators */
    'typeof', 'delete', 'void', '!', '~', '+', '-', 'in', 'instanceof', '*', '%', '/', '**', '&&',
    '||', '===', '!==', '==', '!=', '<=', '>=', '<', '>', '<<', '>>', '>>>', '&', '|', '^',
    /* Variable declaration kinds */
    'var', 'let', 'const',
    /* Other reserved words */
    'break', 'case', 'catch', 'class', 'continue', 'debugger', 'default', 'do', 'else', 'export',
    'extends', 'finally', 'for', 'function', 'if', 'import', 'new', 'return', 'super', 'switch',
    'this', 'throw', 'try', 'while', 'with',
    /* Strict mode reserved words */
    'implements', 'interface', 'package', 'private', 'protected', 'public', 'static', 'yield',
    /* Contextual keywords */
    'as', 'async', 'await', 'constructor', 'get', 'set', 'from', 'of',
    '#',
    'eval', 'arguments', 'enum', 'BigInt', '@', 'JSXText',
    /** TS */
    'KeyOf', 'ReadOnly', 'is', 'unique', 'declare', 'type', 'namespace', 'abstract', 'module'
];
/**
 * The conversion function between token and its string description/representation.
 */
function tokenDesc(token) {
    return keywordDescTable[token & 255 /* Type */];
}
// Used `Object.create(null)` to avoid potential `Object.prototype`
// interference.
const descKeywordTable = Object.create(null, {
    this: { value: 33566815 /* ThisKeyword */ },
    function: { value: 33566808 /* FunctionKeyword */ },
    if: { value: 12377 /* IfKeyword */ },
    return: { value: 12380 /* ReturnKeyword */ },
    var: { value: 33566791 /* VarKeyword */ },
    else: { value: 12370 /* ElseKeyword */ },
    for: { value: 12374 /* ForKeyword */ },
    new: { value: 33566811 /* NewKeyword */ },
    in: { value: 168834865 /* InKeyword */ },
    typeof: { value: 302002218 /* TypeofKeyword */ },
    while: { value: 12402 /* WhileKeyword */ },
    case: { value: 12363 /* CaseKeyword */ },
    break: { value: 12362 /* BreakKeyword */ },
    try: { value: 12385 /* TryKeyword */ },
    catch: { value: 12364 /* CatchKeyword */ },
    delete: { value: 302002219 /* DeleteKeyword */ },
    throw: { value: 302002272 /* ThrowKeyword */ },
    switch: { value: 33566814 /* SwitchKeyword */ },
    continue: { value: 12366 /* ContinueKeyword */ },
    default: { value: 12368 /* DefaultKeyword */ },
    instanceof: { value: 167786290 /* InstanceofKeyword */ },
    do: { value: 12369 /* DoKeyword */ },
    void: { value: 302002220 /* VoidKeyword */ },
    finally: { value: 12373 /* FinallyKeyword */ },
    arguments: { value: 37814389 /* Arguments */ },
    keyof: { value: 65658 /* KeyOfKeyword */ },
    readonly: { value: 65659 /* ReadOnlyKeyword */ },
    unique: { value: 65661 /* UniqueKeyword */ },
    declare: { value: 65662 /* DeclareKeyword */ },
    async: { value: 299116 /* AsyncKeyword */ },
    await: { value: 33788013 /* AwaitKeyword */ },
    class: { value: 33566797 /* ClassKeyword */ },
    const: { value: 33566793 /* ConstKeyword */ },
    constructor: { value: 36974 /* ConstructorKeyword */ },
    debugger: { value: 12367 /* DebuggerKeyword */ },
    enum: { value: 12406 /* EnumKeyword */ },
    eval: { value: 37814388 /* Eval */ },
    export: { value: 12371 /* ExportKeyword */ },
    extends: { value: 12372 /* ExtendsKeyword */ },
    false: { value: 33566725 /* FalseKeyword */ },
    from: { value: 36977 /* FromKeyword */ },
    get: { value: 36975 /* GetKeyword */ },
    implements: { value: 20579 /* ImplementsKeyword */ },
    import: { value: 33566810 /* ImportKeyword */ },
    interface: { value: 20580 /* InterfaceKeyword */ },
    let: { value: 33574984 /* LetKeyword */ },
    null: { value: 33566727 /* NullKeyword */ },
    of: { value: 1085554 /* OfKeyword */ },
    package: { value: 20581 /* PackageKeyword */ },
    private: { value: 20582 /* PrivateKeyword */ },
    protected: { value: 20583 /* ProtectedKeyword */ },
    public: { value: 20584 /* PublicKeyword */ },
    set: { value: 36976 /* SetKeyword */ },
    static: { value: 20585 /* StaticKeyword */ },
    super: { value: 33566813 /* SuperKeyword */ },
    true: { value: 33566726 /* TrueKeyword */ },
    with: { value: 12387 /* WithKeyword */ },
    yield: { value: 1107316842 /* YieldKeyword */ },
    is: { value: 65660 /* IsKeyword */ },
    type: { value: 65663 /* TypeKeyword */ },
    namespace: { value: 65664 /* NameSpaceKeyword */ },
    abstract: { value: 65665 /* AbstractKeyword */ },
    as: { value: 36971 /* AsKeyword */ },
    module: { value: 65666 /* ModuleKeyword */ },
});
function descKeyword(value) {
    return (descKeywordTable[value] | 0);
}

/*@internal*/
const errorMessages = {
    [0 /* Unexpected */]: 'Unexpected token',
    [1 /* UnexpectedToken */]: 'Unexpected token \'%0\'',
    [2 /* InvalidEscapedReservedWord */]: 'Keyword must not contain escaped characters',
    [3 /* UnexpectedKeyword */]: 'Keyword \'%0\' is reserved',
    [4 /* InvalidLHSInAssignment */]: 'Invalid left-hand side in assignment',
    [5 /* UnterminatedString */]: 'Unterminated string literal',
    [6 /* UnterminatedRegExp */]: 'Unterminated regular expression literal',
    [7 /* UnterminatedComment */]: 'Unterminated MultiLineComment',
    [8 /* UnterminatedTemplate */]: 'Unterminated template literal',
    [9 /* UnexpectedChar */]: 'Invalid character \'%0\'',
    [10 /* StrictOctalEscape */]: 'Octal escapes are not allowed in strict mode',
    [11 /* InvalidEightAndNine */]: 'Escapes \\8 or \\9 are not syntactically valid escapes',
    [12 /* UnicodeOutOfRange */]: 'Unicode escape code point out of range',
    [13 /* DuplicateRegExpFlag */]: 'Duplicate regular expression flag \'%0\'',
    [14 /* UnexpectedTokenRegExpFlag */]: 'Unexpected regular expression flag \'%0\'',
    [15 /* StrictLHSAssignment */]: 'Eval or arguments can\'t be assigned to in strict mode code',
    [16 /* IllegalReturn */]: 'Illegal return statement',
    [17 /* StrictFunction */]: 'In strict mode code, functions can only be declared at top level or inside a block',
    [18 /* SloppyFunction */]: 'In non-strict mode code, functions can only be declared at top level, inside a block, or as the body of an if statement',
    [19 /* ForbiddenAsStatement */]: '%0 can\'t appear in single-statement context',
    [20 /* GeneratorInSingleStatementContext */]: 'Generators can only be declared at the top level or inside a block',
    [21 /* ForAwaitNotOf */]: '\'for await\' loop should be used with \'of\'',
    [22 /* DeclarationMissingInitializer */]: 'Missing initializer in %0 declaration',
    [23 /* ForInOfLoopInitializer */]: '\'for-%0\' loop variable declaration may not have an initializer',
    [24 /* ForInOfLoopMultiBindings */]: 'Invalid left-hand side in for-%0 loop: Must have a single binding.',
    [25 /* LetInLexicalBinding */]: 'let is disallowed as a lexically bound name',
    [26 /* UnexpectedLexicalDeclaration */]: 'Lexical declaration cannot appear in a single-statement context',
    [27 /* LabelRedeclaration */]: 'Label \'%0\' has already been declared',
    [28 /* InvalidNestedStatement */]: '%0  statement must be nested within an iteration statement',
    [29 /* IllegalContinue */]: 'Illegal continue statement: \'%0\' does not denote an iteration statement',
    [30 /* UnknownLabel */]: 'Undefined label \'%0\'',
    [31 /* MultipleDefaultsInSwitch */]: 'More than one default clause in switch statement',
    [32 /* ImportExportDeclAtTopLevel */]: '%0 declarations may only appear at top level of a module',
    [33 /* AsyncFunctionInSingleStatementContext */]: 'Async functions can only be declared at the top level or inside a block',
    [34 /* InvalidLineBreak */]: 'No line break is allowed after \'%0\'',
    [35 /* StrictModeWith */]: 'Strict mode code may not include a with statement',
    [36 /* AwaitOutsideAsync */]: 'Await is only valid in async functions',
    [37 /* UnNamedFunctionDecl */]: 'Function declaration must have a name in this context',
    [38 /* DisallowedInContext */]: '\'%0\' may not be used as an identifier in this context',
    [41 /* StrictDelete */]: 'Delete of an unqualified identifier in strict mode',
    [42 /* DeletePrivateField */]: 'Private fields can not be deleted',
    [39 /* PrivateFieldConstructor */]: 'Classes may not have a private field named \'#constructor\'',
    [40 /* PublicFieldConstructor */]: 'Classes may not have a field named \'constructor\'',
    [43 /* InvalidConstructor */]: 'Class constructor may not be a \'%0\'',
    [44 /* UnexpectedReserved */]: 'Unexpected reserved word',
    [45 /* StrictEvalArguments */]: 'Unexpected eval or arguments in strict mode',
    [46 /* AwaitBindingIdentifier */]: '\'await\' is not a valid identifier inside an async function',
    [47 /* YieldBindingIdentifier */]: '\'yield\' is not a valid identifier inside an generator function',
    [48 /* UnexpectedStrictReserved */]: 'Unexpected strict mode reserved word',
    [50 /* AwaitInParameter */]: 'Await expression not allowed in formal parameter',
    [49 /* YieldInParameter */]: 'Yield expression not allowed in formal parameter',
    [51 /* MetaNotInFunctionBody */]: 'new.target only allowed within functions',
    [52 /* BadSuperCall */]: 'super() is not allowed in this context',
    [53 /* UnexpectedSuper */]: 'Member access from super not allowed in this context',
    [54 /* LoneSuper */]: 'Only "(" or "." or "[" are allowed after \'super\'',
    [55 /* YieldReservedKeyword */]: '\'yield\' is a reserved keyword within generator function bodies',
    [56 /* ContinuousNumericSeparator */]: 'Only one underscore is allowed as numeric separator',
    [57 /* TrailingNumericSeparator */]: 'Numeric separators are not allowed at the end of numeric literals',
    [58 /* ZeroDigitNumericSeparator */]: 'Numeric separator can not be used after leading 0.',
    [59 /* StrictOctalLiteral */]: 'Legacy octal literals are not allowed in strict mode',
    [60 /* InvalidLhsInAssignment */]: 'Invalid left-hand side in assignment',
    [61 /* DuplicateProto */]: 'Property name __proto__ appears more than once in object literal',
    [62 /* IllegalUseStrict */]: 'Illegal \'use strict\' directive in function with non-simple parameter list',
    [63 /* StaticPrototype */]: 'Classes may not have a static property named \'prototype\'',
    [64 /* AccessorWrongArgs */]: '%0 functions must have %1 argument%2',
    [65 /* BadSetterRestParameter */]: 'Setter function argument must not be a rest parameter',
    [66 /* StrictLHSPrefixPostFix */]: '%0 increment/decrement may not have eval or arguments operand in strict mode',
    [67 /* InvalidElisonInObjPropList */]: 'Elision not allowed in object property list',
    [68 /* ElementAfterRest */]: 'Rest element must be last element',
    [70 /* ElementAfterSpread */]: 'Spread element must be last element',
    [69 /* RestDefaultInitializer */]: 'Rest parameter may not have a default initializer',
    [71 /* InvalidDestructuringTarget */]: 'Invalid destructuring assignment target',
    [72 /* UnexpectedSurrogate */]: 'Unexpected surrogate pair',
    [73 /* MalformedEscape */]: 'Malformed %0 character escape sequence',
    [74 /* TemplateOctalLiteral */]: 'Template literals may not contain octal escape sequences',
    [75 /* NotBindable */]: 'Invalid binding pattern',
    [76 /* ParamAfterRest */]: 'Rest parameter must be last formal parameter',
    [77 /* NoCatchOrFinally */]: 'Missing catch or finally after try',
    [78 /* NewlineAfterThrow */]: 'Illegal newline after throw',
    [79 /* ParamDupe */]: 'Duplicate parameter name not allowed in this context',
    [80 /* AsAfterImportStart */]: 'Missing keyword \'as\' after import *',
    [81 /* LabelNoColon */]: 'Labels must be followed by a \':\'',
    [82 /* NonEmptyJSXExpression */]: 'JSX attributes must only be assigned a non-empty  \'expression\'',
    [83 /* ExpectedJSXClosingTag */]: 'Expected corresponding JSX closing tag for %0',
    [84 /* AdjacentJSXElements */]: 'Adjacent JSX elements must be wrapped in an enclosing tag',
    [85 /* InvalidJSXAttributeValue */]: 'Invalid JSX attribute value',
    [86 /* RestWithComma */]: 'Rest element may not have a trailing comma',
    [87 /* UndefinedUnicodeCodePoint */]: 'Undefined Unicode code-point',
    [88 /* HtmlCommentInModule */]: 'HTML comments are not allowed in modules',
    [89 /* InvalidCoverInitializedName */]: 'Invalid shorthand property initializer',
    [90 /* TrailingDecorators */]: 'Trailing decorator may be followed by method',
    [91 /* GeneratorConstructor */]: 'Decorators can\'t be used with a constructor',
    [92 /* InvalidRestBindingPattern */]: '`...` must be followed by an identifier in declaration contexts',
};
/**
 * Collect line, index, and colum from either the recorded error
 * or directly from the parser and returns it
 *
 * @param parser Parser instance
 * @param context Context masks
 * @param index  The 0-based end index of the error.
 * @param line The 0-based line position of the error.
 * @param column The 0-based column position of the error.
 * @param parser The 0-based end index of the current node.
 * @param description Error description
 */
function constructError(parser, context, index, line, column, description) {
    const error = new SyntaxError(`Line ${line}, column ${column}: ${description}`);
    error.index = index;
    error.line = line;
    error.column = column;
    error.description = description;
    if (context & 512 /* OptionsTolerant */) {
        parser.errors.push(error);
    }
    else
        throw error;
}
/**
 * Collect line, index, and colum from either the recorded error
 * or directly from the parser and returns it
 *
 * @param parser Parser instance
 */
function getErrorLocation(parser) {
    let { index, startLine: line, startColumn: column } = parser;
    const errorLoc = parser.errorLocation;
    if (!!errorLoc) {
        index = errorLoc.index;
        line = errorLoc.line;
        column = errorLoc.column;
    }
    return { index, line, column };
}
/**
 * Throws an error
 *
 * @param parser Parser instance
 * @param context Context masks
 * @param type Error type
 * @param params Error params
 */
function report(parser, type, ...params) {
    const { index, line, column } = getErrorLocation(parser);
    const errorMessage = errorMessages[type].replace(/%(\d+)/g, (_, i) => params[i]);
    constructError(parser, 0 /* Empty */, index, line, column, errorMessage);
}
/**
 * If in tolerant mode, all errors are pushed to a top-level error array containing
 * otherwise throws
 *
 * @param parser Parser instance
 * @param context Context masks
 * @param type Error type
 * @param params Error params
 */
function tolerant(parser, context, type, ...params) {
    const { index, line, column } = getErrorLocation(parser);
    const errorMessage = errorMessages[type].replace(/%(\d+)/g, (_, i) => params[i]);
    constructError(parser, context, index, line, column, errorMessage);
}

/*@internal*/
const characterType = [
    0 /* Unknown */,
    0 /* Unknown */,
    0 /* Unknown */,
    0 /* Unknown */,
    0 /* Unknown */,
    0 /* Unknown */,
    0 /* Unknown */,
    0 /* Unknown */,
    0 /* Unknown */,
    16 /* Space */,
    48 /* Whitespace */,
    16 /* Space */,
    16 /* Space */,
    48 /* Whitespace */,
    0 /* Unknown */,
    0 /* Unknown */,
    0 /* Unknown */,
    0 /* Unknown */,
    0 /* Unknown */,
    0 /* Unknown */,
    0 /* Unknown */,
    0 /* Unknown */,
    0 /* Unknown */,
    0 /* Unknown */,
    0 /* Unknown */,
    0 /* Unknown */,
    0 /* Unknown */,
    0 /* Unknown */,
    0 /* Unknown */,
    0 /* Unknown */,
    0 /* Unknown */,
    0 /* Unknown */,
    16 /* Space */,
    0 /* Unknown */,
    0 /* Unknown */,
    0 /* Unknown */,
    3 /* Letters */,
    0 /* Unknown */,
    0 /* Unknown */,
    0 /* Unknown */,
    0 /* Unknown */,
    0 /* Unknown */,
    0 /* Unknown */,
    0 /* Unknown */,
    0 /* Unknown */,
    0 /* Unknown */,
    0 /* Unknown */,
    0 /* Unknown */,
    9 /* Decimals */,
    9 /* Decimals */,
    9 /* Decimals */,
    9 /* Decimals */,
    9 /* Decimals */,
    9 /* Decimals */,
    9 /* Decimals */,
    9 /* Decimals */,
    9 /* Decimals */,
    9 /* Decimals */,
    0 /* Unknown */,
    0 /* Unknown */,
    0 /* Unknown */,
    0 /* Unknown */,
    0 /* Unknown */,
    0 /* Unknown */,
    0 /* Unknown */,
    7 /* Hexadecimal */,
    7 /* Hexadecimal */,
    7 /* Hexadecimal */,
    7 /* Hexadecimal */,
    7 /* Hexadecimal */,
    7 /* Hexadecimal */,
    3 /* Letters */,
    3 /* Letters */,
    3 /* Letters */,
    3 /* Letters */,
    3 /* Letters */,
    3 /* Letters */,
    3 /* Letters */,
    3 /* Letters */,
    3 /* Letters */,
    3 /* Letters */,
    3 /* Letters */,
    3 /* Letters */,
    3 /* Letters */,
    3 /* Letters */,
    3 /* Letters */,
    3 /* Letters */,
    3 /* Letters */,
    3 /* Letters */,
    3 /* Letters */,
    3 /* Letters */,
    0 /* Unknown */,
    0 /* Unknown */,
    0 /* Unknown */,
    0 /* Unknown */,
    3 /* Letters */,
    0 /* Unknown */,
    7 /* Hexadecimal */,
    7 /* Hexadecimal */,
    7 /* Hexadecimal */,
    7 /* Hexadecimal */,
    7 /* Hexadecimal */,
    7 /* Hexadecimal */,
    3 /* Letters */,
    3 /* Letters */,
    3 /* Letters */,
    3 /* Letters */,
    3 /* Letters */,
    3 /* Letters */,
    3 /* Letters */,
    3 /* Letters */,
    3 /* Letters */,
    3 /* Letters */,
    3 /* Letters */,
    3 /* Letters */,
    3 /* Letters */,
    3 /* Letters */,
    3 /* Letters */,
    3 /* Letters */,
    3 /* Letters */,
    3 /* Letters */,
    3 /* Letters */,
    3 /* Letters */,
    0 /* Unknown */,
    0 /* Unknown */,
    0 /* Unknown */,
    0 /* Unknown */,
    0 /* Unknown */,
];

// Unicode v. 10 support
// tslint:disable
function isValidIdentifierPart(code) {
    return (convert[(code >>> 5) + 0] >>> code & 31 & 1) !== 0;
}
function isValidIdentifierStart(code) {
    return (convert[(code >>> 5) + 34816] >>> code & 31 & 1) !== 0;
}
function mustEscape(code) {
    return (convert[(code >>> 5) + 69632] >>> code & 31 & 1) !== 0;
}
const convert = ((compressed, lookup) => {
    const result = new Uint32Array(104448);
    let index = 0;
    let subIndex = 0;
    while (index < 3293) {
        const inst = compressed[index++];
        if (inst < 0) {
            subIndex -= inst;
        }
        else {
            let code = compressed[index++];
            if (inst & 2)
                code = lookup[code];
            if (inst & 1) {
                result.fill(code, subIndex, subIndex += compressed[index++]);
            }
            else {
                result[subIndex++] = code;
            }
        }
    }
    return result;
})([-1, 2, 28, 2, 29, 2, 5, -1, 0, 77595648, 3, 41, 2, 3, 0, 14, 2, 52, 2, 53, 3, 0, 3, 0, 3168796671, 0, 4294956992, 2, 1, 2, 0, 2, 54, 3, 0, 4, 0, 4294966523, 3, 0, 4, 2, 55, 2, 56, 2, 4, 0, 4294836479, 0, 3221225471, 0, 4294901942, 2, 57, 0, 134152192, 3, 0, 2, 0, 4294951935, 3, 0, 2, 0, 2683305983, 0, 2684354047, 2, 17, 2, 0, 0, 4294961151, 3, 0, 2, 2, 20, 2, 0, 2, 59, 2, 0, 2, 125, 2, 6, 2, 19, -1, 2, 60, 2, 148, 2, 1, 3, 0, 3, 0, 4294901711, 2, 37, 0, 4089839103, 0, 2961209759, 0, 268697551, 0, 4294543342, 0, 3547201023, 0, 1577204103, 0, 4194240, 0, 4294688750, 2, 2, 0, 80831, 0, 4261478351, 0, 4294549486, 2, 2, 0, 2965387679, 0, 196559, 0, 3594373100, 0, 3288319768, 0, 8469959, 2, 167, 2, 3, 0, 3825204735, 0, 123747807, 0, 65487, 2, 3, 0, 4092591615, 0, 1080049119, 0, 458703, 2, 3, 2, 0, 0, 2163244511, 0, 4227923919, 0, 4236247020, 2, 64, 0, 4284449919, 0, 851904, 2, 4, 2, 16, 0, 67076095, -1, 2, 65, 0, 1006628014, 0, 4093591391, -1, 0, 50331649, 0, 3265266687, 2, 34, 0, 4294844415, 0, 4278190047, 2, 22, 2, 124, -1, 3, 0, 2, 2, 33, 2, 0, 2, 10, 2, 0, 2, 14, 2, 15, 3, 0, 10, 2, 66, 2, 0, 2, 67, 2, 68, 2, 69, 2, 0, 2, 70, 2, 0, 0, 3892314111, 0, 261632, 2, 27, 3, 0, 2, 2, 11, 2, 4, 3, 0, 18, 2, 71, 2, 5, 3, 0, 2, 2, 72, 0, 2088959, 2, 31, 2, 8, 0, 909311, 3, 0, 2, 0, 814743551, 2, 39, 0, 67057664, 3, 0, 2, 2, 9, 2, 0, 2, 32, 2, 0, 2, 18, 2, 7, 0, 268374015, 2, 30, 2, 46, 2, 0, 2, 73, 0, 134153215, -1, 2, 6, 2, 0, 2, 7, 0, 2684354559, 0, 67044351, 0, 1073676416, -2, 3, 0, 2, 2, 40, 0, 1046528, 3, 0, 3, 2, 8, 2, 0, 2, 9, 0, 4294960127, 2, 10, 2, 13, -1, 0, 4294377472, 2, 25, 3, 0, 7, 0, 4227858431, 3, 0, 8, 2, 11, 2, 0, 2, 75, 2, 10, 2, 0, 2, 76, 2, 77, 2, 78, -1, 2, 121, 0, 1048577, 2, 79, 2, 12, -1, 2, 12, 0, 131042, 2, 80, 2, 81, 2, 82, 2, 0, 2, 13, -83, 2, 0, 2, 49, 2, 7, 3, 0, 4, 0, 1046559, 2, 0, 2, 14, 2, 0, 0, 2147516671, 2, 23, 3, 83, 2, 2, 0, -16, 2, 84, 0, 524222462, 2, 4, 2, 0, 0, 4269801471, 2, 4, 2, 0, 2, 15, 2, 74, 2, 86, 3, 0, 2, 2, 43, 2, 16, -1, 2, 17, -16, 3, 0, 205, 2, 18, -2, 3, 0, 655, 2, 19, 3, 0, 36, 2, 47, -1, 2, 17, 2, 10, 3, 0, 8, 2, 87, 2, 117, 2, 0, 0, 3220242431, 3, 0, 3, 2, 20, 2, 21, 2, 88, 3, 0, 2, 2, 89, 2, 90, -1, 2, 21, 2, 0, 2, 26, 2, 0, 2, 8, 3, 0, 2, 0, 67043391, 0, 687865855, 2, 0, 2, 24, 2, 8, 2, 22, 3, 0, 2, 0, 67076097, 2, 7, 2, 0, 2, 23, 0, 67059711, 0, 4236247039, 3, 0, 2, 0, 939524103, 0, 8191999, 2, 94, 2, 95, 2, 15, 2, 92, 3, 0, 3, 0, 67057663, 3, 0, 349, 2, 96, 2, 97, 2, 6, -264, 3, 0, 11, 2, 24, 3, 0, 2, 2, 25, -1, 0, 3774349439, 2, 98, 2, 99, 3, 0, 2, 2, 20, 2, 100, 3, 0, 10, 2, 10, 2, 17, 2, 0, 2, 42, 2, 0, 2, 26, 2, 101, 2, 27, 0, 1638399, 2, 165, 2, 102, 3, 0, 3, 2, 22, 2, 28, 2, 29, 2, 5, 2, 30, 2, 0, 2, 7, 2, 103, -1, 2, 104, 2, 105, 2, 106, -1, 3, 0, 3, 2, 16, -2, 2, 0, 2, 31, -3, 2, 144, -4, 2, 22, 2, 0, 2, 107, 0, 1, 2, 0, 2, 58, 2, 32, 2, 16, 2, 10, 2, 0, 2, 108, -1, 3, 0, 4, 2, 10, 2, 33, 2, 109, 2, 6, 2, 0, 2, 110, 2, 0, 2, 44, -4, 3, 0, 9, 2, 23, 2, 18, 2, 26, -4, 2, 111, 2, 112, 2, 18, 2, 23, 2, 7, -2, 2, 113, 2, 18, 2, 25, -2, 2, 0, 2, 114, -2, 0, 4277137519, 0, 2265972735, -1, 3, 22, 2, -1, 2, 34, 2, 36, 2, 0, 3, 18, 2, 2, 35, 2, 20, -3, 3, 0, 2, 2, 13, -1, 2, 0, 2, 35, 2, 0, 2, 35, -24, 3, 0, 2, 2, 36, 0, 2147549120, 2, 0, 2, 16, 2, 17, 2, 128, 2, 0, 2, 48, 2, 17, 0, 5242879, 3, 0, 2, 0, 402594847, -1, 2, 116, 0, 1090519039, -2, 2, 118, 2, 119, 2, 0, 2, 38, 2, 37, 2, 2, 0, 3766565279, 0, 2039759, -4, 3, 0, 2, 2, 38, -1, 3, 0, 2, 0, 67043519, -5, 2, 0, 0, 4282384383, 0, 1056964609, -1, 3, 0, 2, 0, 67043345, -1, 2, 0, 2, 9, 2, 39, -1, 0, 3825205247, 2, 40, -11, 3, 0, 2, 0, 2147484671, -8, 2, 0, 2, 7, 0, 4294901888, 2, 0, 0, 67108815, -1, 2, 0, 2, 45, -8, 2, 50, 2, 41, 0, 67043329, 2, 122, 2, 42, 0, 8388351, -2, 2, 123, 0, 3028287487, 0, 67043583, -21, 3, 0, 28, 2, 25, -3, 3, 0, 3, 2, 43, 3, 0, 6, 2, 44, -85, 3, 0, 33, 2, 43, -126, 3, 0, 18, 2, 36, -269, 3, 0, 17, 2, 45, 2, 7, 2, 39, -2, 2, 17, 2, 46, 2, 0, 2, 23, 0, 67043343, 2, 126, 2, 27, -27, 3, 0, 2, 0, 4294901791, 2, 7, 2, 187, -2, 0, 3, 3, 0, 191, 2, 47, 3, 0, 23, 2, 35, -296, 3, 0, 8, 2, 7, -2, 2, 17, 3, 0, 11, 2, 6, -72, 3, 0, 3, 2, 127, 0, 1677656575, -166, 0, 4161266656, 0, 4071, 0, 15360, -4, 0, 28, -13, 3, 0, 2, 2, 48, 2, 0, 2, 129, 2, 130, 2, 51, 2, 0, 2, 131, 2, 132, 2, 133, 3, 0, 10, 2, 134, 2, 135, 2, 15, 3, 48, 2, 3, 49, 2, 3, 50, 2, 0, 4294954999, 2, 0, -16, 2, 0, 2, 85, 2, 0, 0, 2105343, 0, 4160749584, 2, 194, -42, 0, 4194303871, 0, 2011, -62, 3, 0, 6, 0, 8323103, -1, 3, 0, 2, 2, 38, -37, 2, 51, 2, 138, 2, 139, 2, 140, 2, 141, 2, 142, -138, 3, 0, 1334, 2, 23, -1, 3, 0, 129, 2, 31, 3, 0, 6, 2, 10, 3, 0, 180, 2, 143, 3, 0, 233, 0, 1, -96, 3, 0, 16, 2, 10, -22583, 3, 0, 7, 2, 27, -6130, 3, 5, 2, -1, 0, 69207040, 3, 41, 2, 3, 0, 14, 2, 52, 2, 53, -3, 0, 3168731136, 0, 4294956864, 2, 1, 2, 0, 2, 54, 3, 0, 4, 0, 4294966275, 3, 0, 4, 2, 55, 2, 56, 2, 4, 2, 26, -1, 2, 17, 2, 57, -1, 2, 0, 2, 19, 0, 4294885376, 3, 0, 2, 0, 3145727, 0, 2617294944, 0, 4294770688, 2, 27, 2, 58, 3, 0, 2, 0, 131135, 2, 91, 0, 70256639, 2, 59, 0, 272, 2, 45, 2, 19, -1, 2, 60, -2, 2, 93, 0, 603979775, 0, 4278255616, 0, 4294836227, 0, 4294549473, 0, 600178175, 0, 2952806400, 0, 268632067, 0, 4294543328, 0, 57540095, 0, 1577058304, 0, 1835008, 0, 4294688736, 2, 61, 2, 62, 0, 33554435, 2, 120, 2, 61, 2, 145, 0, 131075, 0, 3594373096, 0, 67094296, 2, 62, -1, 2, 63, 0, 603979263, 2, 153, 0, 3, 0, 4294828001, 0, 602930687, 2, 175, 0, 393219, 2, 63, 0, 671088639, 0, 2154840064, 0, 4227858435, 0, 4236247008, 2, 64, 2, 36, -1, 2, 4, 0, 917503, 2, 36, -1, 2, 65, 0, 537783470, 0, 4026531935, -1, 0, 1, -1, 2, 34, 2, 47, 0, 7936, -3, 2, 0, 0, 2147485695, 0, 1010761728, 0, 4292984930, 0, 16387, 2, 0, 2, 14, 2, 15, 3, 0, 10, 2, 66, 2, 0, 2, 67, 2, 68, 2, 69, 2, 0, 2, 70, 2, 0, 2, 16, -1, 2, 27, 3, 0, 2, 2, 11, 2, 4, 3, 0, 18, 2, 71, 2, 5, 3, 0, 2, 2, 72, 0, 253951, 3, 20, 2, 0, 122879, 2, 0, 2, 8, 0, 276824064, -2, 3, 0, 2, 2, 9, 2, 0, 0, 4294903295, 2, 0, 2, 18, 2, 7, -1, 2, 17, 2, 46, 2, 0, 2, 73, 2, 39, -1, 2, 23, 2, 0, 2, 31, -2, 0, 128, -2, 2, 74, 2, 8, 0, 4064, -1, 2, 115, 0, 4227907585, 2, 0, 2, 191, 2, 0, 2, 44, 0, 4227915776, 2, 10, 2, 13, -2, 0, 6544896, 3, 0, 6, -2, 3, 0, 8, 2, 11, 2, 0, 2, 75, 2, 10, 2, 0, 2, 76, 2, 77, 2, 78, -3, 2, 79, 2, 12, -3, 2, 80, 2, 81, 2, 82, 2, 0, 2, 13, -83, 2, 0, 2, 49, 2, 7, 3, 0, 4, 0, 817183, 2, 0, 2, 14, 2, 0, 0, 33023, 2, 23, 3, 83, 2, -17, 2, 84, 0, 524157950, 2, 4, 2, 0, 2, 85, 2, 4, 2, 0, 2, 15, 2, 74, 2, 86, 3, 0, 2, 2, 43, 2, 16, -1, 2, 17, -16, 3, 0, 205, 2, 18, -2, 3, 0, 655, 2, 19, 3, 0, 36, 2, 47, -1, 2, 17, 2, 10, 3, 0, 8, 2, 87, 0, 3072, 2, 0, 0, 2147516415, 2, 10, 3, 0, 2, 2, 27, 2, 21, 2, 88, 3, 0, 2, 2, 89, 2, 90, -1, 2, 21, 0, 4294965179, 0, 7, 2, 0, 2, 8, 2, 88, 2, 8, -1, 0, 687603712, 2, 91, 2, 92, 2, 36, 2, 22, 2, 93, 2, 35, 2, 159, 0, 2080440287, 2, 0, 2, 13, 2, 136, 0, 3296722943, 2, 0, 0, 1046675455, 0, 939524101, 0, 1837055, 2, 94, 2, 95, 2, 15, 2, 92, 3, 0, 3, 0, 7, 3, 0, 349, 2, 96, 2, 97, 2, 6, -264, 3, 0, 11, 2, 24, 3, 0, 2, 2, 25, -1, 0, 2700607615, 2, 98, 2, 99, 3, 0, 2, 2, 20, 2, 100, 3, 0, 10, 2, 10, 2, 17, 2, 0, 2, 42, 2, 0, 2, 26, 2, 101, -3, 2, 102, 3, 0, 3, 2, 22, -1, 3, 5, 2, 2, 30, 2, 0, 2, 7, 2, 103, -1, 2, 104, 2, 105, 2, 106, -1, 3, 0, 3, 2, 16, -2, 2, 0, 2, 31, -8, 2, 22, 2, 0, 2, 107, -1, 2, 0, 2, 58, 2, 32, 2, 18, 2, 10, 2, 0, 2, 108, -1, 3, 0, 4, 2, 10, 2, 17, 2, 109, 2, 6, 2, 0, 2, 110, 2, 0, 2, 44, -4, 3, 0, 9, 2, 23, 2, 18, 2, 26, -4, 2, 111, 2, 112, 2, 18, 2, 23, 2, 7, -2, 2, 113, 2, 18, 2, 25, -2, 2, 0, 2, 114, -2, 0, 4277075969, 2, 8, -1, 3, 22, 2, -1, 2, 34, 2, 137, 2, 0, 3, 18, 2, 2, 35, 2, 20, -3, 3, 0, 2, 2, 13, -1, 2, 0, 2, 35, 2, 0, 2, 35, -24, 2, 115, 2, 9, -2, 2, 115, 2, 27, 2, 17, 2, 13, 2, 115, 2, 36, 2, 17, 0, 4718591, 2, 115, 2, 35, 0, 335544350, -1, 2, 116, 2, 117, -2, 2, 118, 2, 119, 2, 7, -1, 2, 120, 2, 61, 0, 3758161920, 0, 3, -4, 2, 0, 2, 31, 2, 170, -1, 2, 0, 2, 27, 0, 176, -5, 2, 0, 2, 43, 2, 177, -1, 2, 0, 2, 27, 2, 189, -1, 2, 0, 2, 19, -2, 2, 25, -12, 3, 0, 2, 2, 121, -8, 0, 4294965249, 0, 67633151, 0, 4026597376, 2, 0, 0, 975, -1, 2, 0, 2, 45, -8, 2, 50, 2, 43, 0, 1, 2, 122, 2, 27, -3, 2, 123, 2, 107, 2, 124, -21, 3, 0, 28, 2, 25, -3, 3, 0, 3, 2, 43, 3, 0, 6, 2, 44, -85, 3, 0, 33, 2, 43, -126, 3, 0, 18, 2, 36, -269, 3, 0, 17, 2, 45, 2, 7, -3, 2, 17, 2, 125, 2, 0, 2, 27, 2, 44, 2, 126, 2, 27, -27, 3, 0, 2, 0, 65567, -1, 2, 100, -2, 0, 3, 3, 0, 191, 2, 47, 3, 0, 23, 2, 35, -296, 3, 0, 8, 2, 7, -2, 2, 17, 3, 0, 11, 2, 6, -72, 3, 0, 3, 2, 127, 2, 128, -187, 3, 0, 2, 2, 48, 2, 0, 2, 129, 2, 130, 2, 51, 2, 0, 2, 131, 2, 132, 2, 133, 3, 0, 10, 2, 134, 2, 135, 2, 15, 3, 48, 2, 3, 49, 2, 3, 50, 2, 2, 136, -129, 3, 0, 6, 2, 137, -1, 3, 0, 2, 2, 44, -37, 2, 51, 2, 138, 2, 139, 2, 140, 2, 141, 2, 142, -138, 3, 0, 1334, 2, 23, -1, 3, 0, 129, 2, 31, 3, 0, 6, 2, 10, 3, 0, 180, 2, 143, 3, 0, 233, 0, 1, -96, 3, 0, 16, 2, 10, -28719, 2, 0, 0, 1, -1, 2, 121, 2, 0, 0, 8193, -21, 0, 50331648, 0, 10255, 0, 4, -11, 2, 62, 2, 163, 0, 1, 0, 71936, -1, 2, 154, 0, 4292933632, 0, 805306431, -5, 2, 144, -1, 2, 172, -1, 0, 6144, -2, 2, 122, -1, 2, 164, -1, 2, 150, 2, 145, 2, 158, 2, 0, 0, 3223322624, 2, 8, 0, 4, -4, 2, 183, 0, 205128192, 0, 1333757536, 0, 3221225520, 0, 423953, 0, 747766272, 0, 2717763192, 0, 4290773055, 0, 278545, 2, 146, 0, 4294886464, 0, 33292336, 0, 417809, 2, 146, 0, 1329579616, 0, 4278190128, 0, 700594195, 0, 1006647527, 0, 4286497336, 0, 4160749631, 2, 147, 0, 469762560, 0, 4171219488, 0, 16711728, 2, 147, 0, 202375680, 0, 3214918176, 0, 4294508592, 2, 147, -1, 0, 983584, 0, 48, 0, 58720275, 0, 3489923072, 0, 10517376, 0, 4293066815, 0, 1, 0, 2013265920, 2, 171, 2, 0, 0, 17816169, 0, 3288339281, 0, 201375904, 2, 0, -2, 0, 256, 0, 122880, 0, 16777216, 2, 144, 0, 4160757760, 2, 0, -6, 2, 160, -11, 0, 3263218176, -1, 0, 49664, 0, 2160197632, 0, 8388802, -1, 0, 12713984, -1, 0, 402653184, 2, 152, 2, 155, -2, 2, 156, -20, 0, 3758096385, -2, 2, 185, 0, 4292878336, 2, 21, 2, 148, 0, 4294057984, -2, 2, 157, 2, 149, 2, 168, -2, 2, 166, -1, 2, 174, -1, 2, 162, 2, 121, 0, 4026593280, 0, 14, 0, 4292919296, -1, 2, 151, 0, 939588608, -1, 0, 805306368, -1, 2, 121, 0, 1610612736, 2, 149, 2, 150, 3, 0, 2, -2, 2, 151, 2, 152, -3, 0, 267386880, -1, 2, 153, 0, 7168, -1, 2, 180, 2, 0, 2, 154, 2, 155, -7, 2, 161, -8, 2, 156, -1, 0, 1426112704, 2, 157, -1, 2, 181, 0, 271581216, 0, 2149777408, 2, 27, 2, 154, 2, 121, 0, 851967, 0, 3758129152, -1, 2, 27, 2, 173, -4, 2, 151, -20, 2, 188, 2, 158, -56, 0, 3145728, 2, 179, 2, 184, 0, 4294443520, 2, 73, -1, 2, 159, 2, 121, -4, 0, 32505856, -1, 2, 160, -1, 0, 2147385088, 2, 21, 1, 2155905152, 2, -3, 2, 91, 2, 0, 2, 161, -2, 2, 148, -6, 2, 162, 0, 4026597375, 0, 1, -1, 0, 1, -1, 2, 163, -3, 2, 137, 2, 190, -2, 2, 159, 2, 164, -1, 2, 169, 2, 121, -6, 2, 121, -213, 2, 162, -657, 2, 158, -36, 2, 165, -1, 0, 65408, -10, 2, 193, -5, 2, 166, -5, 0, 4278222848, 2, 0, 2, 23, -1, 0, 4227919872, -1, 2, 166, -2, 0, 4227874752, 2, 157, -2, 0, 2146435072, 2, 152, -2, 0, 1006649344, 2, 121, -1, 2, 21, 0, 201375744, -3, 0, 134217720, 2, 21, 0, 4286677377, 0, 32896, -1, 2, 167, -3, 2, 168, -349, 2, 169, 2, 170, 2, 171, 3, 0, 264, -11, 2, 172, -2, 2, 155, 2, 0, 0, 520617856, 0, 2692743168, 0, 36, -3, 0, 524284, -11, 2, 27, -1, 2, 178, -1, 2, 176, 0, 3221291007, 2, 155, -1, 0, 524288, 0, 2158720, -3, 2, 152, 0, 1, -4, 2, 121, 0, 3808625411, 0, 3489628288, 0, 4096, 0, 1207959680, 0, 3221274624, 2, 0, -3, 2, 164, 0, 120, 0, 7340032, -2, 0, 4026564608, 2, 4, 2, 27, 2, 157, 3, 0, 4, 2, 152, -1, 2, 173, 2, 171, -1, 0, 8176, 2, 174, 2, 164, 2, 175, -1, 0, 4290773232, 2, 0, -4, 2, 157, 2, 182, 0, 15728640, 2, 171, -1, 2, 154, -1, 0, 4294934512, 3, 0, 4, -9, 2, 21, 2, 162, 2, 176, 3, 0, 4, 0, 704, 0, 1849688064, 0, 4194304, -1, 2, 121, 0, 4294901887, 2, 0, 0, 130547712, 0, 1879048192, 0, 2080374784, 3, 0, 2, -1, 2, 177, 2, 178, -1, 0, 17829776, 0, 2028994560, 0, 4261478144, -2, 2, 0, -1, 0, 4286580608, -1, 0, 29360128, 2, 179, 0, 16252928, 0, 3791388672, 2, 119, 3, 0, 2, -2, 2, 180, 2, 0, -1, 2, 100, -1, 0, 66584576, 3, 0, 11, 2, 121, 3, 0, 12, -2, 0, 245760, 0, 2147418112, -1, 2, 144, 2, 195, 0, 4227923456, -1, 2, 181, 2, 169, 2, 21, -2, 2, 172, 0, 4292870145, 0, 262144, 2, 121, 3, 0, 2, 0, 1073758848, 2, 182, -1, 0, 4227921920, 2, 183, 2, 146, 0, 528402016, 0, 4292927536, 3, 0, 4, -2, 0, 3556769792, 2, 0, -2, 2, 186, 3, 0, 5, -1, 2, 179, 2, 157, 2, 0, -2, 0, 4227923936, 2, 58, -1, 2, 166, 2, 91, 2, 0, 2, 184, 2, 151, 3, 0, 11, -2, 0, 2146959360, 3, 0, 8, -2, 2, 154, -1, 0, 536870960, 2, 115, -1, 2, 185, 3, 0, 8, 0, 512, 0, 8388608, 2, 167, 2, 165, 2, 178, 0, 4286578944, 3, 0, 2, 0, 1152, 0, 1266679808, 2, 186, 3, 0, 21, -28, 2, 155, 3, 0, 3, -3, 0, 4292902912, -6, 2, 93, 3, 0, 85, -33, 2, 187, 3, 0, 126, -18, 2, 188, 3, 0, 269, -17, 2, 185, 2, 121, 0, 4294917120, 3, 0, 2, 2, 27, 0, 4290822144, -2, 0, 67174336, 0, 520093700, 2, 17, 3, 0, 27, -2, 0, 65504, 2, 121, 2, 43, 3, 0, 2, 2, 88, -191, 2, 58, -23, 2, 100, 3, 0, 296, -8, 2, 121, 3, 0, 2, 2, 27, -11, 2, 171, 3, 0, 72, -3, 0, 3758159872, 0, 201391616, 3, 0, 155, -7, 2, 162, -1, 0, 384, -1, 0, 133693440, -3, 2, 180, -2, 2, 30, 3, 0, 5, -2, 2, 21, 2, 122, 3, 0, 4, -2, 2, 181, -1, 2, 144, 0, 335552923, 2, 189, -1, 0, 538974272, 0, 2214592512, 0, 132000, -10, 0, 192, -8, 0, 12288, -21, 0, 134213632, 0, 4294901761, 3, 0, 42, 0, 100663424, 0, 4294965284, 3, 0, 62, -6, 0, 4286578784, 2, 0, -2, 0, 1006696448, 3, 0, 37, 2, 189, 0, 4110942569, 0, 1432950139, 0, 2701658217, 0, 4026532864, 0, 4026532881, 2, 0, 2, 42, 3, 0, 8, -1, 2, 151, -2, 2, 148, 2, 190, 0, 65537, 2, 162, 2, 165, 2, 159, -1, 2, 151, -1, 2, 58, 2, 0, 2, 191, 0, 65528, 2, 171, 0, 4294770176, 2, 30, 3, 0, 4, -30, 2, 192, 0, 4261470208, -3, 2, 148, -2, 2, 192, 2, 0, 2, 151, -1, 2, 186, -1, 2, 154, 0, 4294950912, 3, 0, 2, 2, 151, 2, 121, 2, 165, 2, 193, 2, 166, 2, 0, 2, 194, 2, 188, 3, 0, 48, -1334, 2, 21, 2, 0, -129, 2, 192, -6, 2, 157, -180, 2, 195, -233, 2, 4, 3, 0, 96, -16, 2, 157, 3, 0, 22583, -7, 2, 17, 3, 0, 6128], [4294967295, 4294967291, 4092460543, 4294828015, 4294967294, 134217726, 268435455, 2147483647, 1048575, 16777215, 1073741823, 1061158911, 536805376, 511, 4294910143, 4160749567, 134217727, 4294901760, 4194303, 2047, 262143, 4286578688, 536870911, 8388607, 4294918143, 67108863, 255, 65535, 67043328, 2281701374, 4294967232, 2097151, 4294903807, 4294902783, 4294967039, 524287, 127, 4294549487, 67045375, 1023, 67047423, 4286578687, 4294770687, 32767, 15, 33554431, 2047999, 8191, 4292870143, 4294934527, 4294966783, 4294967279, 262083, 20511, 4290772991, 4294901759, 41943039, 460799, 4294959104, 71303167, 1071644671, 602799615, 65536, 4294828000, 805044223, 4277151126, 1031749119, 4294917631, 2134769663, 4286578493, 4282253311, 4294942719, 33540095, 4294905855, 4294967264, 2868854591, 1608515583, 265232348, 534519807, 2147614720, 1060109444, 4093640016, 17376, 2139062143, 224, 4169138175, 4294868991, 4294909951, 4294967292, 4294965759, 16744447, 4294966272, 4294901823, 4294967280, 8289918, 4294934399, 4294901775, 4294965375, 1602223615, 4294967259, 4294443008, 268369920, 4292804608, 486341884, 4294963199, 3087007615, 1073692671, 131071, 4128527, 4279238655, 4294902015, 4294966591, 2445279231, 3670015, 3238002687, 4294967288, 4294705151, 4095, 3221208447, 4294902271, 4294549472, 2147483648, 4294705152, 4294966143, 64, 16383, 3774873592, 536807423, 67043839, 3758096383, 3959414372, 3755993023, 2080374783, 4294835295, 4294967103, 4160749565, 4087, 31, 184024726, 2862017156, 1593309078, 268434431, 268434414, 4294901763, 536870912, 2952790016, 202506752, 139280, 4293918720, 4227922944, 2147532800, 61440, 3758096384, 117440512, 65280, 4227858432, 3233808384, 3221225472, 4294965248, 32768, 57152, 67108864, 4290772992, 25165824, 4160749568, 57344, 4278190080, 65472, 4227907584, 65520, 1920, 4026531840, 49152, 4294836224, 63488, 1073741824, 4294967040, 251658240, 196608, 12582912, 4294966784, 2097152, 64512, 417808, 469762048, 4261412864, 4227923712, 4294934528, 4294967168, 16, 98304, 63, 4292870144, 4294963200, 65534, 65532]);

/**
 * Return the next unicodechar in the stream
 *
 * @param parser Parser object
 */
function nextUnicodeChar(parser) {
    const { index } = parser;
    const hi = parser.source.charCodeAt(index);
    if (hi < 55296 /* LeadSurrogateMin */ || hi > 56319 /* LeadSurrogateMax */)
        return hi;
    const lo = parser.source.charCodeAt(index + 1);
    if (lo < 56320 /* TrailSurrogateMin */ || lo > 57343 /* TrailSurrogateMax */)
        return hi;
    return 65536 /* NonBMPMin */ + ((hi & 0x3FF) << 10) | lo & 0x3FF;
}
/**
 * Returns true if this is a valid identifier part
 *
 * @param code Codepoint
 */
const isIdentifierPart = (code) => (characterType[code] & 1 /* IdentifierStart */) !== 0 || isValidIdentifierPart(code);
function escapeForPrinting(code) {
    switch (code) {
        case 0 /* Null */:
            return '\\0';
        case 8 /* Backspace */:
            return '\\b';
        case 9 /* Tab */:
            return '\\t';
        case 10 /* LineFeed */:
            return '\\n';
        case 11 /* VerticalTab */:
            return '\\v';
        case 12 /* FormFeed */:
            return '\\f';
        case 13 /* CarriageReturn */:
            return '\\r';
        default:
            if (!mustEscape(code))
                return fromCodePoint(code);
            if (code < 0x10)
                return `\\x0${code.toString(16)}`;
            if (code < 0x100)
                return `\\x${code.toString(16)}`;
            if (code < 0x1000)
                return `\\u0${code.toString(16)}`;
            if (code < 0x10000)
                return `\\u${code.toString(16)}`;
            return `\\u{${code.toString(16)}}`;
    }
}
/**
 * Consume an token in the scanner on match. This is an equalent to
 * 'consume' used in the parser code itself.
 *
 * @param parser Parser object
 * @param context  Context masks
 */
function consumeOpt(parser, code) {
    if (parser.source.charCodeAt(parser.index) !== code)
        return false;
    parser.index++;
    parser.column++;
    return true;
}
/**
 * Consumes line feed
 *
 * @param parser Parser object
 * @param state  Scanner state
 */
function consumeLineFeed(parser, state) {
    parser.flags |= 1 /* NewLine */;
    parser.index++;
    if ((state & 2 /* LastIsCR */) === 0) {
        parser.column = 0;
        parser.line++;
    }
}
/**
 * Scans private name. Stage 3 proposal related
 *
 * @param parser Parser object
 * @param context Context masks
 */
function scanPrivateName(parser, context) {
    if (!(context & 32768 /* InClass */) || !isValidIdentifierStart(parser.source.charCodeAt(parser.index))) {
        report(parser, 1 /* UnexpectedToken */, tokenDesc(parser.token));
    }
    return 115 /* Hash */;
}
/**
 * Advance to new line
 *
 * @param parser Parser object
 */
function advanceNewline(parser) {
    parser.flags |= 1 /* NewLine */;
    parser.index++;
    parser.column = 0;
    parser.line++;
}
const fromCodePoint = (code) => {
    return code <= 0xFFFF ?
        String.fromCharCode(code) :
        String.fromCharCode(((code - 65536 /* NonBMPMin */) >> 10) + 55296 /* LeadSurrogateMin */, ((code - 65536 /* NonBMPMin */) & (1024 - 1)) + 56320 /* TrailSurrogateMin */);
};
function readNext(parser) {
    parser.index++;
    parser.column++;
    if (parser.index >= parser.source.length)
        report(parser, 12 /* UnicodeOutOfRange */);
    return nextUnicodeChar(parser);
}
function toHex(code) {
    if (code < 48 /* Zero */)
        return -1;
    if (code <= 57 /* Nine */)
        return code - 48 /* Zero */;
    if (code < 65 /* UpperA */)
        return -1;
    if (code <= 70 /* UpperF */)
        return code - 65 /* UpperA */ + 10;
    if (code < 97 /* LowerA */)
        return -1;
    if (code <= 102 /* LowerF */)
        return code - 97 /* LowerA */ + 10;
    return -1;
}
function advanceOnMaybeAstral(parser, ch) {
    parser.index++;
    parser.column++;
    if (ch > 0xFFFF)
        parser.index++;
}

/**
 * Scans regular expression
 *
 * @param parser Parser object
 * @param context Context masks
 */
function scanRegularExpression(parser, context) {
    const bodyStart = parser.index;
    let preparseState = 0 /* Empty */;
    loop: while (true) {
        const ch = parser.source.charCodeAt(parser.index);
        parser.index++;
        parser.column++;
        if (preparseState & 1 /* Escape */) {
            preparseState &= ~1 /* Escape */;
        }
        else {
            switch (ch) {
                case 47 /* Slash */:
                    if (!preparseState)
                        break loop;
                    else
                        break;
                case 92 /* Backslash */:
                    preparseState |= 1 /* Escape */;
                    break;
                case 91 /* LeftBracket */:
                    preparseState |= 2 /* Class */;
                    break;
                case 93 /* RightBracket */:
                    preparseState &= 1 /* Escape */;
                    break;
                case 13 /* CarriageReturn */:
                case 10 /* LineFeed */:
                case 8232 /* LineSeparator */:
                case 8233 /* ParagraphSeparator */:
                    report(parser, 6 /* UnterminatedRegExp */);
                default: // ignore
            }
        }
        if (parser.index >= parser.source.length) {
            report(parser, 6 /* UnterminatedRegExp */);
        }
    }
    const bodyEnd = parser.index - 1;
    let mask = 0 /* Empty */;
    const { index: flagStart } = parser;
    loop: while (parser.index < parser.source.length) {
        const code = parser.source.charCodeAt(parser.index);
        switch (code) {
            case 103 /* LowerG */:
                if (mask & 2 /* Global */)
                    tolerant(parser, context, 13 /* DuplicateRegExpFlag */, 'g');
                mask |= 2 /* Global */;
                break;
            case 105 /* LowerI */:
                if (mask & 1 /* IgnoreCase */)
                    tolerant(parser, context, 13 /* DuplicateRegExpFlag */, 'i');
                mask |= 1 /* IgnoreCase */;
                break;
            case 109 /* LowerM */:
                if (mask & 4 /* Multiline */)
                    tolerant(parser, context, 13 /* DuplicateRegExpFlag */, 'm');
                mask |= 4 /* Multiline */;
                break;
            case 117 /* LowerU */:
                if (mask & 8 /* Unicode */)
                    tolerant(parser, context, 13 /* DuplicateRegExpFlag */, 'u');
                mask |= 8 /* Unicode */;
                break;
            case 121 /* LowerY */:
                if (mask & 16 /* Sticky */)
                    tolerant(parser, context, 13 /* DuplicateRegExpFlag */, 'y');
                mask |= 16 /* Sticky */;
                break;
            case 115 /* LowerS */:
                if (mask & 32 /* DotAll */)
                    tolerant(parser, context, 13 /* DuplicateRegExpFlag */, 's');
                mask |= 32 /* DotAll */;
                break;
            default:
                if (!isIdentifierPart(code))
                    break loop;
                report(parser, 14 /* UnexpectedTokenRegExpFlag */, fromCodePoint(code));
        }
        parser.index++;
        parser.column++;
    }
    const flags = parser.source.slice(flagStart, parser.index);
    const pattern = parser.source.slice(bodyStart, bodyEnd);
    parser.tokenRegExp = { pattern, flags };
    if (context & 8 /* OptionsRaw */)
        parser.tokenRaw = parser.source.slice(parser.startIndex, parser.index);
    parser.tokenValue = validate(parser, context, pattern, flags);
    return 33554436 /* RegularExpression */;
}
/**
 * Validates regular expressions
 *
 *
 * @param parser Parser instance
 * @param context Context masks
 * @param pattern Regexp body
 * @param flags Regexp flags
 */
function validate(parser, context, pattern, flags) {
    if (!(context & 1024 /* OptionsNode */)) {
        try {
        }
        catch (e) {
            report(parser, 6 /* UnterminatedRegExp */);
        }
    }
    try {
        return new RegExp(pattern, flags);
    }
    catch (e) {
        return null;
    }
}

/**
 * Scan escape sequence
 *
 * @param parser Parser object
 * @param context Context masks
 */
function scanEscapeSequence(parser, context, first) {
    switch (first) {
        case 98 /* LowerB */:
            return 8 /* Backspace */;
        case 102 /* LowerF */:
            return 12 /* FormFeed */;
        case 114 /* LowerR */:
            return 13 /* CarriageReturn */;
        case 110 /* LowerN */:
            return 10 /* LineFeed */;
        case 116 /* LowerT */:
            return 9 /* Tab */;
        case 118 /* LowerV */:
            return 11 /* VerticalTab */;
        case 13 /* CarriageReturn */:
        case 10 /* LineFeed */:
        case 8232 /* LineSeparator */:
        case 8233 /* ParagraphSeparator */:
            parser.column = -1;
            parser.line++;
            return -1 /* Empty */;
        case 48 /* Zero */:
        case 49 /* One */:
        case 50 /* Two */:
        case 51 /* Three */:
            {
                // 1 to 3 octal digits
                let code = first - 48 /* Zero */;
                let index = parser.index + 1;
                let column = parser.column + 1;
                let next = parser.source.charCodeAt(index);
                if (next < 48 /* Zero */ || next > 55 /* Seven */) {
                    // Strict mode code allows only \0, then a non-digit.
                    if (code !== 0 || next === 56 /* Eight */ || next === 57 /* Nine */) {
                        if (context & 4096 /* Strict */)
                            return -2 /* StrictOctal */;
                        parser.flags |= 128 /* HasOctal */;
                    }
                }
                else if (context & 4096 /* Strict */) {
                    return -2 /* StrictOctal */;
                }
                else {
                    parser.flags |= 128 /* HasOctal */;
                    parser.lastValue = next;
                    code = code * 8 + (next - 48 /* Zero */);
                    index++;
                    column++;
                    next = parser.source.charCodeAt(index);
                    if (next >= 48 /* Zero */ && next <= 55 /* Seven */) {
                        parser.lastValue = next;
                        code = code * 8 + (next - 48 /* Zero */);
                        index++;
                        column++;
                    }
                    parser.index = index - 1;
                    parser.column = column - 1;
                }
                return code;
            }
        case 52 /* Four */:
        case 53 /* Five */:
        case 54 /* Six */:
        case 55 /* Seven */:
            {
                // 1 to 2 octal digits
                if (context & 4096 /* Strict */)
                    return -2 /* StrictOctal */;
                let code = first - 48 /* Zero */;
                const index = parser.index + 1;
                const column = parser.column + 1;
                const next = parser.source.charCodeAt(index);
                if (next >= 48 /* Zero */ && next <= 55 /* Seven */) {
                    code = code * 8 + (next - 48 /* Zero */);
                    parser.lastValue = next;
                    parser.index = index;
                    parser.column = column;
                }
                return code;
            }
        // `8`, `9` (invalid escapes)
        case 56 /* Eight */:
        case 57 /* Nine */:
            return -3 /* EightOrNine */;
        // ASCII escapes
        case 120 /* LowerX */:
            {
                const ch1 = parser.lastValue = readNext(parser);
                const hi = toHex(ch1);
                if (hi < 0)
                    return -4 /* InvalidHex */;
                const ch2 = parser.lastValue = readNext(parser);
                const lo = toHex(ch2);
                if (lo < 0)
                    return -4 /* InvalidHex */;
                return hi << 4 | lo;
            }
        // UCS-2/Unicode escapes
        case 117 /* LowerU */:
            {
                let ch = parser.lastValue = readNext(parser);
                if (ch === 123 /* LeftBrace */) {
                    ch = parser.lastValue = readNext(parser);
                    let code = toHex(ch);
                    if (code < 0)
                        return -4 /* InvalidHex */;
                    ch = parser.lastValue = readNext(parser);
                    while (ch !== 125 /* RightBrace */) {
                        const digit = toHex(ch);
                        if (digit < 0)
                            return -4 /* InvalidHex */;
                        code = code * 16 + digit;
                        // Code point out of bounds
                        if (code > 1114111 /* NonBMPMax */)
                            return -5 /* OutOfRange */;
                        ch = parser.lastValue = readNext(parser);
                    }
                    return code;
                }
                else {
                    // \uNNNN
                    let codePoint = toHex(ch);
                    if (codePoint < 0)
                        return -4 /* InvalidHex */;
                    for (let i = 0; i < 3; i++) {
                        ch = parser.lastValue = readNext(parser);
                        const digit = toHex(ch);
                        if (digit < 0)
                            return -4 /* InvalidHex */;
                        codePoint = codePoint * 16 + digit;
                    }
                    return codePoint;
                }
            }
        default:
            return parser.source.charCodeAt(parser.index);
    }
}
/**
 * Throws a string error for either string or template literal
 *
 * @param parser Parser object
 * @param context Context masks
 */
function throwStringError(parser, context, code) {
    switch (code) {
        case -1 /* Empty */:
            return;
        case -2 /* StrictOctal */:
            report(parser, context & 16384 /* TaggedTemplate */ ?
                74 /* TemplateOctalLiteral */ :
                10 /* StrictOctalEscape */);
        case -3 /* EightOrNine */:
            report(parser, 11 /* InvalidEightAndNine */);
        case -4 /* InvalidHex */:
            report(parser, 73 /* MalformedEscape */, 'hexadecimal');
        case -5 /* OutOfRange */:
            report(parser, 12 /* UnicodeOutOfRange */);
        /* istanbul ignore next */
        default:
        // ignore
    }
}
/**
 * Scan a string literal
 *
 * @see [Link](https://tc39.github.io/ecma262/#sec-literals-string-literals)
 *
 * @param parser Parser object
 * @param context Context masks
 * @param quote codepoint
 */
function scanString(parser, context, quote) {
    const { index: start, lastValue } = parser;
    let ret = '';
    parser.index++;
    parser.column++; // consume quote
    let ch = parser.source.charCodeAt(parser.index);
    while (ch !== quote) {
        switch (ch) {
            case 8232 /* LineSeparator */:
            case 8233 /* ParagraphSeparator */:
            case 13 /* CarriageReturn */:
            case 10 /* LineFeed */:
                report(parser, 5 /* UnterminatedString */);
            case 92 /* Backslash */:
                ch = readNext(parser);
                if (ch > 128 /* MaxAsciiCharacter */) {
                    ret += fromCodePoint(ch);
                }
                else {
                    parser.lastValue = ch;
                    const code = scanEscapeSequence(parser, context, ch);
                    if (code >= 0)
                        ret += fromCodePoint(code);
                    else
                        throwStringError(parser, context, code);
                    ch = parser.lastValue;
                }
                break;
            default:
                ret += fromCodePoint(ch);
        }
        ch = readNext(parser);
    }
    parser.index++;
    parser.column++; // consume quote
    parser.tokenRaw = parser.source.slice(start, parser.index);
    parser.tokenValue = ret;
    parser.lastValue = lastValue;
    return 33554435 /* StringLiteral */;
}

/**
 * Consumes template brace
 *
 * @param parser Parser object
 * @param context Context masks
 */
function consumeTemplateBrace(parser, context) {
    if (parser.index >= parser.length)
        report(parser, 8 /* UnterminatedTemplate */);
    // Upon reaching a '}', consume it and rewind the scanner state
    parser.index--;
    parser.column--;
    return scanTemplate(parser, context);
}
/**
 * Scan template
 *
 * @param parser Parser object
 * @param context Context masks
 * @param first Codepoint
 */
function scanTemplate(parser, context) {
    const { index: start, lastValue } = parser;
    let tail = true;
    let ret = '';
    let ch = readNext(parser);
    loop: while (ch !== 96 /* Backtick */) {
        switch (ch) {
            // Break after a literal `${` (thus the dedicated code path).
            case 36 /* Dollar */:
                {
                    const index = parser.index + 1;
                    if (index < parser.length &&
                        parser.source.charCodeAt(index) === 123 /* LeftBrace */) {
                        parser.index = index;
                        parser.column++;
                        tail = false;
                        break loop;
                    }
                    ret += '$';
                    break;
                }
            case 92 /* Backslash */:
                ch = readNext(parser);
                if (ch >= 128) {
                    ret += fromCodePoint(ch);
                }
                else {
                    parser.lastValue = ch;
                    // Because octals are forbidden in escaped template sequences and the fact that
                    // both string and template scanning uses the same method - 'scanEscapeSequence',
                    // we set the strict context mask.
                    const code = scanEscapeSequence(parser, context | 4096 /* Strict */, ch);
                    if (code >= 0) {
                        ret += fromCodePoint(code);
                    }
                    else if (code !== -1 /* Empty */ && context & 16384 /* TaggedTemplate */) {
                        ret = undefined;
                        ch = scanLooserTemplateSegment(parser, parser.lastValue);
                        if (ch < 0) {
                            tail = false;
                        }
                        break loop;
                    }
                    else {
                        throwStringError(parser, context | 16384 /* TaggedTemplate */, code);
                    }
                    ch = parser.lastValue;
                }
                break;
            case 13 /* CarriageReturn */:
            case 10 /* LineFeed */:
            case 8232 /* LineSeparator */:
            case 8233 /* ParagraphSeparator */:
                parser.column = -1;
                parser.line++;
            // falls through
            default:
                if (ret != null)
                    ret += fromCodePoint(ch);
        }
        ch = readNext(parser);
    }
    parser.index++;
    parser.column++;
    parser.tokenValue = ret;
    parser.lastValue = lastValue;
    if (tail) {
        parser.tokenRaw = parser.source.slice(start + 1, parser.index - 1);
        return 33554441 /* TemplateTail */;
    }
    else {
        parser.tokenRaw = parser.source.slice(start + 1, parser.index - 2);
        return 33554440 /* TemplateCont */;
    }
}
/**
 * Scan looser template segment
 *
 * @param parser Parser object
 * @param ch codepoint
 */
function scanLooserTemplateSegment(parser, ch) {
    while (ch !== 96 /* Backtick */) {
        if (ch === 36 /* Dollar */ && parser.source.charCodeAt(parser.index + 1) === 123 /* LeftBrace */) {
            parser.index++;
            parser.column++;
            return -ch;
        }
        // Skip '\' and continue to scan the template token to search
        // for the end, without validating any escape sequences
        ch = readNext(parser);
    }
    return ch;
}

// 11.8.3 Numeric Literals
/**
 * Scans hex integer literal
 *
 * @see [Link](https://tc39.github.io/ecma262/#prod-HexIntegerLiteral)
 *
 * @param parser Parser object
 * @param context Context masks
 */
function scanHexIntegerLiteral(parser, context) {
    parser.index++;
    parser.column++;
    let state = 0 /* None */;
    let value = toHex(parser.source.charCodeAt(parser.index));
    if (value < 0)
        report(parser, 0 /* Unexpected */);
    parser.index++;
    parser.column++;
    while (parser.index < parser.length) {
        const next = parser.source.charCodeAt(parser.index);
        if (context & 1 /* OptionsNext */ && next === 95 /* Underscore */) {
            state = scanNumericSeparator(parser, state);
            continue;
        }
        state &= ~1 /* SeenSeparator */;
        const digit = toHex(next);
        if (digit < 0)
            break;
        value = value * 16 + digit;
        parser.index++;
        parser.column++;
    }
    if (state & 1 /* SeenSeparator */)
        report(parser, 57 /* TrailingNumericSeparator */);
    return assembleNumericLiteral(parser, context, value, consumeOpt(parser, 110 /* LowerN */));
}
/**
 * Scans binary and octal integer literal
 *
 * @see [Link](https://tc39.github.io/ecma262/#prod-OctalIntegerLiteral)
 * @see [Link](https://tc39.github.io/ecma262/#prod-BinaryIntegerLiteral)
 *
 * @param parser Parser object
 * @param context Context masks
 */
function scanOctalOrBinary(parser, context, base) {
    parser.index++;
    parser.column++;
    let digits = 0;
    let ch;
    let value = 0;
    let state = 0 /* None */;
    while (parser.index < parser.length) {
        ch = parser.source.charCodeAt(parser.index);
        if (context & 1 /* OptionsNext */ && ch === 95 /* Underscore */) {
            state = scanNumericSeparator(parser, state);
            continue;
        }
        state &= ~1 /* SeenSeparator */;
        const converted = ch - 48 /* Zero */;
        if (!(ch >= 48 /* Zero */ && ch <= 57 /* Nine */) || converted >= base)
            break;
        value = value * base + converted;
        parser.index++;
        parser.column++;
        digits++;
    }
    if (digits === 0)
        report(parser, 0 /* Unexpected */);
    if (state & 1 /* SeenSeparator */)
        report(parser, 57 /* TrailingNumericSeparator */);
    return assembleNumericLiteral(parser, context, value, consumeOpt(parser, 110 /* LowerN */));
}
/**
 * Scans implicit octal digits
 *
 * @see [Link](https://tc39.github.io/ecma262/#prod-OctalDigits)
 *
 * @param parser Parser object
 * @param context Context masks
 */
function scanImplicitOctalDigits(parser, context) {
    switch (parser.source.charCodeAt(parser.index)) {
        case 48 /* Zero */:
        case 49 /* One */:
        case 50 /* Two */:
        case 51 /* Three */:
        case 52 /* Four */:
        case 53 /* Five */:
        case 54 /* Six */:
        case 55 /* Seven */:
            {
                if (context & 4096 /* Strict */)
                    report(parser, 0 /* Unexpected */);
                let index = parser.index;
                let column = parser.column;
                let code = 0;
                parser.flags |= 128 /* HasOctal */;
                // Implicit octal, unless there is a non-octal digit.
                // (Annex B.1.1 on Numeric Literals)
                while (index < parser.length) {
                    const next = parser.source.charCodeAt(index);
                    if (next === 95 /* Underscore */) {
                        report(parser, 58 /* ZeroDigitNumericSeparator */);
                    }
                    else if (next < 48 /* Zero */ || next > 55 /* Seven */) {
                        return scanNumericLiteral(parser, context);
                    }
                    else {
                        code = code * 8 + (next - 48 /* Zero */);
                        index++;
                        column++;
                    }
                }
                parser.index = index;
                parser.column = column;
                return assembleNumericLiteral(parser, context, code, consumeOpt(parser, 110 /* LowerN */));
            }
        case 56 /* Eight */:
        case 57 /* Nine */:
            parser.flags |= 128 /* HasOctal */;
        default:
            if (context & 1 /* OptionsNext */ && parser.source.charCodeAt(parser.index) === 95 /* Underscore */) {
                report(parser, 58 /* ZeroDigitNumericSeparator */);
            }
            return scanNumericLiteral(parser, context);
    }
}
/**
 * Scans signed integer
 *
 * @see [Link](https://tc39.github.io/ecma262/#prod-SignedInteger)
 *
 * @param parser Parser object
 * @param context Context masks
 */
function scanSignedInteger(parser, end) {
    let next = parser.source.charCodeAt(parser.index);
    if (next === 43 /* Plus */ || next === 45 /* Hyphen */) {
        parser.index++;
        parser.column++;
        next = parser.source.charCodeAt(parser.index);
    }
    if (!(next >= 48 /* Zero */ && next <= 57 /* Nine */)) {
        report(parser, 0 /* Unexpected */);
    }
    const preNumericPart = parser.index;
    const finalFragment = scanDecimalDigitsOrSeparator(parser);
    return parser.source.substring(end, preNumericPart) + finalFragment;
}
/**
 * Scans numeric literal
 *
 * @see [Link](https://tc39.github.io/ecma262/#prod-NumericLiteral)
 *
 * @param parser Parser object
 * @param context Context masks
 */
function scanNumericLiteral(parser, context, state = 0 /* None */) {
    let value = state & 4 /* Float */ ?
        0 :
        scanDecimalAsSmi(parser, context);
    const next = parser.source.charCodeAt(parser.index);
    // I know I'm causing a bug here. The question is - will anyone figure this out?
    if (next !== 46 /* Period */ && next !== 95 /* Underscore */ && !isValidIdentifierStart(next)) {
        return assembleNumericLiteral(parser, context, value);
    }
    if (consumeOpt(parser, 46 /* Period */)) {
        if (context & 1 /* OptionsNext */ && parser.source.charCodeAt(parser.index) === 95 /* Underscore */) {
            report(parser, 58 /* ZeroDigitNumericSeparator */);
        }
        state |= 4 /* Float */;
        value = `${value}.${scanDecimalDigitsOrSeparator(parser)}`;
    }
    const end = parser.index;
    if (consumeOpt(parser, 110 /* LowerN */)) {
        if (state & 4 /* Float */)
            report(parser, 0 /* Unexpected */);
        state |= 8 /* BigInt */;
    }
    if (consumeOpt(parser, 101 /* LowerE */) || consumeOpt(parser, 69 /* UpperE */)) {
        state |= 4 /* Float */;
        value += scanSignedInteger(parser, end);
    }
    if (isValidIdentifierStart(parser.source.charCodeAt(parser.index))) {
        report(parser, 0 /* Unexpected */);
    }
    return assembleNumericLiteral(parser, context, state & 4 /* Float */ ? parseFloat(value) : parseInt(value, 10), !!(state & 8 /* BigInt */));
}
/**
 * Internal helper function for scanning numeric separators.
 *
 * @param parser Parser object
 * @param context Context masks
 * @param state NumericState state
 */
function scanNumericSeparator(parser, state) {
    parser.index++;
    parser.column++;
    if (state & 1 /* SeenSeparator */)
        report(parser, 57 /* TrailingNumericSeparator */);
    state |= 1 /* SeenSeparator */;
    return state;
}
/**
 * Internal helper function that scans numeric values
 *
 * @param parser Parser object
 * @param context Context masks
 */
function scanDecimalDigitsOrSeparator(parser) {
    let start = parser.index;
    let state = 0 /* None */;
    let ret = '';
    loop: while (parser.index < parser.length) {
        switch (parser.source.charCodeAt(parser.index)) {
            case 95 /* Underscore */:
                const preUnderscoreIndex = parser.index;
                state = scanNumericSeparator(parser, state);
                ret += parser.source.substring(start, preUnderscoreIndex);
                start = parser.index;
                continue;
            case 48 /* Zero */:
            case 49 /* One */:
            case 50 /* Two */:
            case 51 /* Three */:
            case 52 /* Four */:
            case 53 /* Five */:
            case 54 /* Six */:
            case 55 /* Seven */:
            case 56 /* Eight */:
            case 57 /* Nine */:
                state = state & ~1 /* SeenSeparator */;
                parser.index++;
                parser.column++;
                break;
            default:
                break loop;
        }
    }
    if (state & 1 /* SeenSeparator */)
        report(parser, 57 /* TrailingNumericSeparator */);
    return ret + parser.source.substring(start, parser.index);
}
/**
 * Internal helper function that scans numeric values
 *
 * @param parser Parser object
 * @param context Context masks
 */
function scanDecimalAsSmi(parser, context) {
    let state = 0 /* None */;
    let value = 0;
    let next = parser.source.charCodeAt(parser.index);
    while (next >= 48 /* Zero */ && next <= 57 /* Nine */ || next === 95 /* Underscore */) {
        if (context & 1 /* OptionsNext */ && next === 95 /* Underscore */) {
            state = scanNumericSeparator(parser, state);
            next = parser.source.charCodeAt(parser.index);
            continue;
        }
        state &= ~1 /* SeenSeparator */;
        value = value * 10 + (next - 48 /* Zero */);
        parser.index++;
        parser.column++;
        next = parser.source.charCodeAt(parser.index);
    }
    if (state & 1 /* SeenSeparator */)
        report(parser, 57 /* TrailingNumericSeparator */);
    return value;
}
/**
 * Internal helper function that assamble the number scanning parts and return
 *
 * @param parser Parser object
 * @param context Context masks
 * @param value The numeric value
 */
function assembleNumericLiteral(parser, context, value, isBigInt = false) {
    parser.tokenValue = value;
    if (context & 8 /* OptionsRaw */)
        parser.tokenRaw = parser.source.slice(parser.startIndex, parser.index);
    return isBigInt ? 33554551 /* BigIntLiteral */ : 33554434 /* NumericLiteral */;
}

/**
 * Scan identifier
 *
 * @see [Link](https://tc39.github.io/ecma262/#sec-names-and-keywords)
 * @see [Link](https://tc39.github.io/ecma262/#sec-literals-string-literals)
 *
 * @param Parser instance
 * @param Context masks
 */
function scanIdentifier(parser, context, first) {
    let start = parser.index;
    let ret = '';
    let isEscaped = false;
    if (first)
        advanceOnMaybeAstral(parser, first);
    loop: while (parser.index < parser.length) {
        const index = parser.index;
        let ch = parser.source.charCodeAt(index);
        switch (ch) {
            case 92 /* Backslash */:
                ret += parser.source.slice(start, index);
                ret += scanUnicodeCodePointEscape(parser);
                start = parser.index;
                isEscaped = true;
                break;
            default:
                if (ch >= 0xD800 && ch <= 0xDBFF) {
                    const lo = parser.source.charCodeAt(index + 1);
                    ch = (ch & 0x3FF) << 10 | lo & 0x3FF | 0x10000;
                }
                if (!isIdentifierPart(ch))
                    break loop;
                advanceOnMaybeAstral(parser, ch);
        }
    }
    if (start < parser.index)
        ret += parser.source.slice(start, parser.index);
    parser.tokenValue = ret;
    const len = ret.length;
    // Keywords are between 2 and 11 characters long and start with a lowercase letter
    // https://tc39.github.io/ecma262/#sec-keywords
    if (len >= 2 && len <= 11) {
        const token = descKeyword(ret);
        if (token > 0) {
            if (isEscaped) {
                if (context & 536870912 /* DisallowEscapedKeyword */) {
                    tolerant(parser, context, 2 /* InvalidEscapedReservedWord */);
                }
                // Here we fall back to a mutual parser flag if the escaped keyword isn't disallowed through
                // context masks. This is similiar to how V8 does it - they are using an
                // 'escaped_keyword' token.
                // - J.K. Thomas
                parser.flags |= 32768 /* EscapedKeyword */;
            }
            return token;
        }
    }
    if (context & 256 /* OptionsRawidentifiers */)
        parser.tokenRaw = parser.source.slice(start, parser.index);
    return 33619969 /* Identifier */;
}
/**
 * Scanning chars in the range 0...127, and treat them as an possible
 * identifier. This allows subsequent checking to be faster.
 *
 * @param parser Parser instance
 * @param context Context masks
 * @param first Code point
 */
function scanMaybeIdentifier(parser, context, first) {
    first = nextUnicodeChar(parser);
    if (!isValidIdentifierStart(first)) {
        report(parser, 9 /* UnexpectedChar */, escapeForPrinting(first));
    }
    return scanIdentifier(parser, context, first);
}
/**
 * Scan unicode codepoint escape
 *
 * @param Parser instance
 * @param Context masks
 */
function scanUnicodeCodePointEscape(parser) {
    const { index } = parser;
    if (index + 5 < parser.length) {
        if (parser.source.charCodeAt(index + 1) !== 117 /* LowerU */) {
            report(parser, 0 /* Unexpected */);
        }
        parser.index += 2;
        parser.column += 2;
        const code = scanIdentifierUnicodeEscape(parser);
        if (code >= 55296 /* LeadSurrogateMin */ && code <= 56319 /* LeadSurrogateMax */) {
            report(parser, 72 /* UnexpectedSurrogate */);
        }
        if (!isIdentifierPart(code)) {
            report(parser, 73 /* MalformedEscape */, 'unicode');
        }
        return fromCodePoint(code);
    }
    report(parser, 0 /* Unexpected */);
}
/**
 * Scan identifier unicode escape
 *
 * @param Parser instance
 * @param Context masks
 */
function scanIdentifierUnicodeEscape(parser) {
    // Accept both \uxxxx and \u{xxxxxx}. In the latter case, the number of
    // hex digits between { } is arbitrary. \ and u have already been read.
    let ch = parser.source.charCodeAt(parser.index);
    let codePoint = 0;
    // '\u{DDDDDDDD}'
    if (ch === 123 /* LeftBrace */) { // {
        ch = readNext(parser);
        let digit = toHex(ch);
        while (digit >= 0) {
            codePoint = (codePoint << 4) | digit;
            if (codePoint > 1114111 /* NonBMPMax */) {
                report(parser, 87 /* UndefinedUnicodeCodePoint */);
            }
            parser.index++;
            parser.column++;
            digit = toHex(parser.source.charCodeAt(parser.index));
        }
        if (parser.source.charCodeAt(parser.index) !== 125 /* RightBrace */) {
            report(parser, 73 /* MalformedEscape */, 'unicode');
        }
        consumeOpt(parser, 125 /* RightBrace */);
        // '\uDDDD'
    }
    else {
        for (let i = 0; i < 4; i++) {
            ch = parser.source.charCodeAt(parser.index);
            const digit = toHex(ch);
            if (digit < 0)
                report(parser, 73 /* MalformedEscape */, 'unicode');
            codePoint = (codePoint << 4) | digit;
            parser.index++;
            parser.column++;
        }
    }
    return codePoint;
}

// 11.4 Comments
/**
 * Skips single HTML comments. Same behavior as in V8.
 *
 * @param parser Parser Object
 * @param context Context masks.
 * @param state  Scanner state
 * @param type   Comment type
 */
function skipSingleHTMLComment(parser, context, state, type) {
    if (context & 8192 /* Module */)
        report(parser, 88 /* HtmlCommentInModule */);
    return skipSingleLineComment(parser, context, state, type);
}
/**
 * Skips SingleLineComment, SingleLineHTMLCloseComment and SingleLineHTMLOpenComment
 *
 *  @see [Link](https://tc39.github.io/ecma262/#prod-SingleLineComment)
 *  @see [Link](https://tc39.github.io/ecma262/#prod-annexB-SingleLineHTMLOpenComment)
 *  @see [Link](https://tc39.github.io/ecma262/#prod-annexB-SingleLineHTMLCloseComment)
 *
 * @param parser Parser instance
 * @param context Context masks
 * @param state  Scanner state
 * @param type   Comment type
 */
function skipSingleLineComment(parser, context, state, type) {
    const start = parser.index;
    const collectable = !!(context & 64 /* OptionsComments */);
    while (parser.index < parser.length) {
        switch (parser.source.charCodeAt(parser.index)) {
            case 13 /* CarriageReturn */:
                advanceNewline(parser);
                if ((parser.index < parser.length) && parser.source.charCodeAt(parser.index) === 10 /* LineFeed */)
                    parser.index++;
                return state | 1 /* NewLine */;
            case 10 /* LineFeed */:
            case 8232 /* LineSeparator */:
            case 8233 /* ParagraphSeparator */:
                advanceNewline(parser);
                if (collectable)
                    addComment(parser, context, type, start);
                return state | 1 /* NewLine */;
            default:
                parser.index++;
                parser.column++;
        }
    }
    if (collectable)
        addComment(parser, context, type, start);
    return state;
}
/**
 * Skips multiline comment
 *
 * @see [Link](https://tc39.github.io/ecma262/#prod-annexB-MultiLineComment)
 *
 * @param parser Parser instance
 * @param context Context masks
 * @param state Scanner state
 */
function skipMultiLineComment(parser, context, state) {
    const start = parser.index;
    const collectable = !!(context & 64 /* OptionsComments */);
    while (parser.index < parser.length) {
        switch (parser.source.charCodeAt(parser.index)) {
            case 42 /* Asterisk */:
                parser.index++;
                parser.column++;
                state &= ~2 /* LastIsCR */;
                if (consumeOpt(parser, 47 /* Slash */)) {
                    if (collectable)
                        addComment(parser, context, 'MultiLine', start);
                    return state;
                }
                break;
            // Mark multiline comments containing linebreaks as new lines
            // so we can perfectly handle edge cases like: '1/*\n*/--> a comment'
            case 13 /* CarriageReturn */:
                state |= 1 /* NewLine */ | 2 /* LastIsCR */;
                advanceNewline(parser);
                break;
            case 10 /* LineFeed */:
                consumeLineFeed(parser, state);
                state = state & ~2 /* LastIsCR */ | 1 /* NewLine */;
                break;
            case 8232 /* LineSeparator */:
            case 8233 /* ParagraphSeparator */:
                state = state & ~2 /* LastIsCR */ | 1 /* NewLine */;
                advanceNewline(parser);
                break;
            default:
                state &= ~2 /* LastIsCR */;
                parser.index++;
                parser.column++;
        }
    }
    // Unterminated multi-line comment.
    tolerant(parser, context, 7 /* UnterminatedComment */);
}
function addComment(parser, context, type, start) {
    const { index, startIndex, startLine, startColumn, lastLine, column } = parser;
    const comment = {
        type,
        value: parser.source.slice(start, type === 'MultiLine' ? index - 2 : index),
        start: startIndex,
        end: index,
    };
    if (context & 16 /* OptionsLoc */) {
        comment.loc = {
            start: {
                line: startLine,
                column: startColumn,
            },
            end: {
                line: lastLine,
                column,
            },
        };
    }
    parser.comments.push(comment);
}

/**
 * Scan
 *
 * @see [Link](https://tc39.github.io/ecma262/#sec-punctuatorss)
 * @see [Link](https://tc39.github.io/ecma262/#sec-names-and-keywords)
 *
 * @param parser Parser object
 * @param context Context masks
 */
function scan(parser, context) {
    parser.flags &= ~1 /* NewLine */ | 32768 /* EscapedKeyword */;
    const lineStart = parser.index === 0;
    let state = 0 /* None */;
    while (parser.index < parser.length) {
        if (!lineStart) {
            parser.startIndex = parser.index;
            parser.startColumn = parser.column;
            parser.startLine = parser.line;
        }
        const first = parser.source.charCodeAt(parser.index);
        if (first > 128 /* MaxAsciiCharacter */) {
            switch (first) {
                case 8232 /* LineSeparator */:
                case 8233 /* ParagraphSeparator */:
                    state = state & ~2 /* LastIsCR */ | 1 /* NewLine */;
                    advanceNewline(parser);
                    break;
                case 65519 /* ByteOrderMark */:
                case 160 /* NonBreakingSpace */:
                case 5760 /* Ogham */:
                case 8192 /* EnQuad */:
                case 8193 /* EmQuad */:
                case 8194 /* EnSpace */:
                case 8195 /* EmSpace */:
                case 8196 /* ThreePerEmSpace */:
                case 8197 /* FourPerEmSpace */:
                case 8198 /* SixPerEmSpace */:
                case 8199 /* FigureSpace */:
                case 8200 /* PunctuationSpace */:
                case 8201 /* ThinSpace */:
                case 8202 /* HairSpace */:
                case 8239 /* NarrowNoBreakSpace */:
                case 8287 /* MathematicalSpace */:
                case 12288 /* IdeographicSpace */:
                case 65279 /* Zwnbs */:
                case 8205 /* Zwj */:
                    parser.index++;
                    parser.column++;
                    break;
                default:
                    return scanMaybeIdentifier(parser, context, first);
            }
        }
        else {
            // Note: Here we first get rid of LT and  WS, then we make sure that the lookup time
            // for the single punctuator char is short as possible. A single punctuator
            // char is a valid token that cannot also be a prefix of a combination
            // of long tokens - e.g. '(', ')' and '=' is valid. '==' is not.
            switch (first) {
                case 13 /* CarriageReturn */:
                    state |= 1 /* NewLine */ | 2 /* LastIsCR */;
                    advanceNewline(parser);
                    break;
                case 10 /* LineFeed */:
                    consumeLineFeed(parser, state);
                    state = state & ~2 /* LastIsCR */ | 1 /* NewLine */;
                    break;
                case 9 /* Tab */:
                case 11 /* VerticalTab */:
                case 12 /* FormFeed */:
                case 32 /* Space */:
                    parser.index++;
                    parser.column++;
                    break;
                // `(`
                case 40 /* LeftParen */:
                    parser.index++;
                    parser.column++;
                    return 50331659 /* LeftParen */;
                // `)`
                case 41 /* RightParen */:
                    parser.index++;
                    parser.column++;
                    return 16 /* RightParen */;
                // `,`
                case 44 /* Comma */:
                    parser.index++;
                    parser.column++;
                    return 16777234 /* Comma */;
                // `:`
                case 58 /* Colon */:
                    parser.index++;
                    parser.column++;
                    return 16777237 /* Colon */;
                // `;`
                case 59 /* Semicolon */:
                    parser.index++;
                    parser.column++;
                    return 17301521 /* Semicolon */;
                // `?`
                case 63 /* QuestionMark */:
                    parser.index++;
                    parser.column++;
                    return 22 /* QuestionMark */;
                // `]`
                case 93 /* RightBracket */:
                    parser.index++;
                    parser.column++;
                    return 20 /* RightBracket */;
                // `{`
                case 123 /* LeftBrace */:
                    parser.index++;
                    parser.column++;
                    return 41943052 /* LeftBrace */;
                // `}`
                case 125 /* RightBrace */:
                    parser.index++;
                    parser.column++;
                    return 17301519 /* RightBrace */;
                // `~`
                case 126 /* Tilde */:
                    parser.index++;
                    parser.column++;
                    return 301989934 /* Complement */;
                // `[`
                case 91 /* LeftBracket */:
                    parser.index++;
                    parser.column++;
                    return 41943059 /* LeftBracket */;
                // `@`
                case 64 /* At */:
                    parser.index++;
                    parser.column++;
                    return 120 /* At */;
                // `/`, `/=`, `/>`
                case 47 /* Slash */:
                    {
                        parser.index++;
                        parser.column++;
                        if (parser.index >= parser.length)
                            return 167774773 /* Divide */;
                        switch (parser.source.charCodeAt(parser.index)) {
                            case 47 /* Slash */:
                                {
                                    parser.index++;
                                    parser.column++;
                                    state = skipSingleLineComment(parser, context, state, 'SingleLine');
                                    continue;
                                }
                            case 42 /* Asterisk */:
                                {
                                    parser.index++;
                                    parser.column++;
                                    state = skipMultiLineComment(parser, context, state);
                                    continue;
                                }
                            case 61 /* EqualSign */:
                                {
                                    parser.index++;
                                    parser.column++;
                                    return 100663333 /* DivideAssign */;
                                }
                            default:
                                return 167774773 /* Divide */;
                        }
                    }
                // `-`, `--`, `-=`
                case 45 /* Hyphen */:
                    {
                        parser.index++;
                        parser.column++; // skip `-`
                        const next = parser.source.charCodeAt(parser.index);
                        switch (next) {
                            case 45 /* Hyphen */:
                                {
                                    parser.index++;
                                    parser.column++;
                                    if ((state & 1 /* NewLine */ || lineStart) &&
                                        consumeOpt(parser, 62 /* GreaterThan */)) {
                                        state = skipSingleHTMLComment(parser, context, state, 'HTMLClose');
                                        continue;
                                    }
                                    return 570425372 /* Decrement */;
                                }
                            case 61 /* EqualSign */:
                                {
                                    parser.index++;
                                    parser.column++;
                                    return 67108899 /* SubtractAssign */;
                                }
                            default:
                                return 436209968 /* Subtract */;
                        }
                    }
                // `<`, `<=`, `<<`, `<<=`, `</`,  <!--
                case 60 /* LessThan */:
                    parser.index++;
                    parser.column++; // skip `<`
                    if (consumeOpt(parser, 33 /* Exclamation */) &&
                        consumeOpt(parser, 45 /* Hyphen */) &&
                        consumeOpt(parser, 45 /* Hyphen */)) {
                        state = skipSingleHTMLComment(parser, context, state, 'HTMLOpen');
                        continue;
                    }
                    switch (parser.source.charCodeAt(parser.index)) {
                        case 60 /* LessThan */:
                            parser.index++;
                            parser.column++;
                            return consumeOpt(parser, 61 /* EqualSign */) ?
                                67108894 /* ShiftLeftAssign */ :
                                167774273 /* ShiftLeft */;
                        case 61 /* EqualSign */:
                            parser.index++;
                            parser.column++;
                            return 167774013 /* LessThanOrEqual */;
                        case 47 /* Slash */:
                            {
                                if (!(context & 4 /* OptionsJSX */))
                                    break;
                                const index = parser.index + 1;
                                // Check that it's not a comment start.
                                if (index < parser.length) {
                                    const next = parser.source.charCodeAt(index);
                                    if (next === 42 /* Asterisk */ || next === 47 /* Slash */)
                                        break;
                                }
                                parser.index++;
                                parser.column++;
                                return 25 /* JSXClose */;
                            }
                        default: // ignore
                            return 167774015 /* LessThan */;
                    }
                // `!`, `!=`, `!==`
                case 33 /* Exclamation */:
                    parser.index++;
                    parser.column++;
                    if (!consumeOpt(parser, 61 /* EqualSign */))
                        return 301989933 /* Negate */;
                    if (!consumeOpt(parser, 61 /* EqualSign */))
                        return 167773756 /* LooseNotEqual */;
                    return 167773754 /* StrictNotEqual */;
                // `'string'`, `"string"`
                case 39 /* SingleQuote */:
                case 34 /* DoubleQuote */:
                    return scanString(parser, context, first);
                // `%`, `%=`
                case 37 /* Percent */:
                    parser.index++;
                    parser.column++;
                    if (!consumeOpt(parser, 61 /* EqualSign */))
                        return 167774772 /* Modulo */;
                    return 67108902 /* ModuloAssign */;
                // `&`, `&&`, `&=`
                case 38 /* Ampersand */:
                    {
                        parser.index++;
                        parser.column++;
                        const next = parser.source.charCodeAt(parser.index);
                        if (next === 38 /* Ampersand */) {
                            parser.index++;
                            parser.column++;
                            return 169869879 /* LogicalAnd */;
                        }
                        if (next === 61 /* EqualSign */) {
                            parser.index++;
                            parser.column++;
                            return 67108905 /* BitwiseAndAssign */;
                        }
                        return 167773508 /* BitwiseAnd */;
                    }
                // `*`, `**`, `*=`, `**=`
                case 42 /* Asterisk */:
                    {
                        parser.index++;
                        parser.column++;
                        if (parser.index >= parser.length)
                            return 167774771 /* Multiply */;
                        const next = parser.source.charCodeAt(parser.index);
                        if (next === 61 /* EqualSign */) {
                            parser.index++;
                            parser.column++;
                            return 67108900 /* MultiplyAssign */;
                        }
                        if (next !== 42 /* Asterisk */)
                            return 167774771 /* Multiply */;
                        parser.index++;
                        parser.column++;
                        if (!consumeOpt(parser, 61 /* EqualSign */))
                            return 167775030 /* Exponentiate */;
                        return 67108897 /* ExponentiateAssign */;
                    }
                // `+`, `++`, `+=`
                case 43 /* Plus */:
                    {
                        parser.index++;
                        parser.column++;
                        if (parser.index >= parser.length)
                            return 436209967 /* Add */;
                        const next = parser.source.charCodeAt(parser.index);
                        if (next === 43 /* Plus */) {
                            parser.index++;
                            parser.column++;
                            return 570425371 /* Increment */;
                        }
                        if (next === 61 /* EqualSign */) {
                            parser.index++;
                            parser.column++;
                            return 67108898 /* AddAssign */;
                        }
                        return 436209967 /* Add */;
                    }
                // `\\u{N}var`
                case 92 /* Backslash */:
                    return scanIdentifier(parser, context);
                // `=`, `==`, `===`, `=>`
                case 61 /* EqualSign */:
                    {
                        parser.index++;
                        parser.column++;
                        const next = parser.source.charCodeAt(parser.index);
                        if (next === 61 /* EqualSign */) {
                            parser.index++;
                            parser.column++;
                            if (consumeOpt(parser, 61 /* EqualSign */)) {
                                return 167773753 /* StrictEqual */;
                            }
                            else {
                                return 167773755 /* LooseEqual */;
                            }
                        }
                        else if (next === 62 /* GreaterThan */) {
                            parser.index++;
                            parser.column++;
                            return 10 /* Arrow */;
                        }
                        return 83886109 /* Assign */;
                    }
                // `>`, `>=`, `>>`, `>>>`, `>>=`, `>>>=`
                case 62 /* GreaterThan */:
                    {
                        parser.index++;
                        parser.column++;
                        if (parser.index >= parser.length)
                            return 167774016 /* GreaterThan */;
                        if (context & 268435456 /* InJSXChild */)
                            return 167774016 /* GreaterThan */;
                        let next = parser.source.charCodeAt(parser.index);
                        if (next === 61 /* EqualSign */) {
                            parser.index++;
                            parser.column++;
                            return 167774014 /* GreaterThanOrEqual */;
                        }
                        if (next !== 62 /* GreaterThan */)
                            return 167774016 /* GreaterThan */;
                        parser.index++;
                        parser.column++;
                        next = parser.source.charCodeAt(parser.index);
                        if (next === 62 /* GreaterThan */) {
                            parser.index++;
                            parser.column++;
                            if (consumeOpt(parser, 61 /* EqualSign */)) {
                                return 67108896 /* LogicalShiftRightAssign */;
                            }
                            else {
                                return 167774275 /* LogicalShiftRight */;
                            }
                        }
                        else if (next === 61 /* EqualSign */) {
                            parser.index++;
                            parser.column++;
                            return 67108895 /* ShiftRightAssign */;
                        }
                        return 167774274 /* ShiftRight */;
                    }
                // `^`, `^=`
                case 94 /* Caret */:
                    parser.index++;
                    parser.column++;
                    if (!consumeOpt(parser, 61 /* EqualSign */))
                        return 167773254 /* BitwiseXor */;
                    return 67108903 /* BitwiseXorAssign */;
                // ``string``
                case 96 /* Backtick */:
                    return scanTemplate(parser, context);
                // `|`, `||`, `|=`
                case 124 /* VerticalBar */:
                    {
                        parser.index++;
                        parser.column++;
                        const next = parser.source.charCodeAt(parser.index);
                        if (next === 124 /* VerticalBar */) {
                            parser.index++;
                            parser.column++;
                            return 169869624 /* LogicalOr */;
                        }
                        else if (next === 61 /* EqualSign */) {
                            parser.index++;
                            parser.column++;
                            return 67108904 /* BitwiseOrAssign */;
                        }
                        return 167772997 /* BitwiseOr */;
                    }
                // `.`, `...`, `.123` (numeric literal)
                case 46 /* Period */:
                    {
                        let index = parser.index + 1;
                        const next = parser.source.charCodeAt(index);
                        if (next >= 48 /* Zero */ && next <= 57 /* Nine */) {
                            scanNumericLiteral(parser, context, 4 /* Float */);
                            return 33554434 /* NumericLiteral */;
                        }
                        else if (next === 46 /* Period */) {
                            index++;
                            if (index < parser.length &&
                                parser.source.charCodeAt(index) === 46 /* Period */) {
                                parser.index = index + 1;
                                parser.column += 3;
                                return 14 /* Ellipsis */;
                            }
                        }
                        parser.index++;
                        parser.column++;
                        return 16777229 /* Period */;
                    }
                // `#`
                case 35 /* Hash */:
                    {
                        parser.index++;
                        parser.column++;
                        const index = parser.index;
                        const next = parser.source.charCodeAt(index);
                        if (context & 128 /* OptionsShebang */ &&
                            lineStart &&
                            next === 33 /* Exclamation */) {
                            parser.index = index + 1;
                            skipSingleLineComment(parser, context, 0 /* None */, 'SheBang');
                            continue;
                        }
                        return scanPrivateName(parser, context);
                    }
                // `0`...`9`
                case 48 /* Zero */:
                    {
                        parser.index++;
                        parser.column++;
                        switch (parser.source.charCodeAt(parser.index)) {
                            // Hex number - '0x', '0X'
                            case 88 /* UpperX */:
                            case 120 /* LowerX */:
                                return scanHexIntegerLiteral(parser, context);
                            // Binary number - '0b', '0B'
                            case 66 /* UpperB */:
                            case 98 /* LowerB */:
                                return scanOctalOrBinary(parser, context, 2);
                            // Octal number - '0o', '0O'
                            case 79 /* UpperO */:
                            case 111 /* LowerO */:
                                return scanOctalOrBinary(parser, context, 8);
                            default:
                                // Implicit octal digits startign with '0'
                                return scanImplicitOctalDigits(parser, context);
                        }
                    }
                case 49 /* One */:
                case 50 /* Two */:
                case 51 /* Three */:
                case 52 /* Four */:
                case 53 /* Five */:
                case 54 /* Six */:
                case 55 /* Seven */:
                case 56 /* Eight */:
                case 57 /* Nine */:
                    return scanNumericLiteral(parser, context);
                // `a`...`z`, `A`...`Z`, `_var`, `$var`
                case 65 /* UpperA */:
                case 66 /* UpperB */:
                case 67 /* UpperC */:
                case 68 /* UpperD */:
                case 69 /* UpperE */:
                case 70 /* UpperF */:
                case 71 /* UpperG */:
                case 72 /* UpperH */:
                case 73 /* UpperI */:
                case 74 /* UpperJ */:
                case 75 /* UpperK */:
                case 76 /* UpperL */:
                case 77 /* UpperM */:
                case 78 /* UpperN */:
                case 79 /* UpperO */:
                case 80 /* UpperP */:
                case 81 /* UpperQ */:
                case 82 /* UpperR */:
                case 83 /* UpperS */:
                case 84 /* UpperT */:
                case 85 /* UpperU */:
                case 86 /* UpperV */:
                case 87 /* UpperW */:
                case 88 /* UpperX */:
                case 89 /* UpperY */:
                case 90 /* UpperZ */:
                case 36 /* Dollar */:
                case 95 /* Underscore */:
                case 97 /* LowerA */:
                case 98 /* LowerB */:
                case 99 /* LowerC */:
                case 100 /* LowerD */:
                case 101 /* LowerE */:
                case 102 /* LowerF */:
                case 103 /* LowerG */:
                case 104 /* LowerH */:
                case 105 /* LowerI */:
                case 106 /* LowerJ */:
                case 107 /* LowerK */:
                case 108 /* LowerL */:
                case 109 /* LowerM */:
                case 110 /* LowerN */:
                case 111 /* LowerO */:
                case 112 /* LowerP */:
                case 113 /* LowerQ */:
                case 114 /* LowerR */:
                case 115 /* LowerS */:
                case 116 /* LowerT */:
                case 117 /* LowerU */:
                case 118 /* LowerV */:
                case 119 /* LowerW */:
                case 120 /* LowerX */:
                case 121 /* LowerY */:
                case 122 /* LowerZ */:
                default:
                    return scanIdentifier(parser, context, first);
            }
        }
    }
    return 524288 /* EndOfSource */;
}

/**
 * Validate break and continue statement
 *
 * @param parser Parser object
 * @param label label
 * @param isContinue true if validation continue statement
 */
function validateBreakOrContinueLabel(parser, context, label, isContinue) {
    const state = hasLabel(parser, label);
    if (!state)
        tolerant(parser, context, 30 /* UnknownLabel */, label);
    if (isContinue && !(state & 2 /* Nested */))
        tolerant(parser, context, 29 /* IllegalContinue */, label);
}
/**
 * Add label to the stack
 *
 * @param parser Parser object
 * @param label label
 */
function addLabel(parser, label) {
    if (parser.labelSet === undefined)
        parser.labelSet = {};
    parser.labelSet[`$${label}`] = parser.token & 16 /* IsIterationStatement */ ? 2 /* Nested */ : 1 /* NotNested */;
}
/**
 * Remove label from the stack
 *
 * @param parser Parser object
 * @param label label
 */
function popLabel(parser, label) {
    parser.labelSet[`$${label}`] = 0 /* None */;
}
/**
 * Returns either true or false. Depends if the label exist.
 *
 * @param parser Parser object
 * @param label Label
 */
function hasLabel(parser, label) {
    return !parser.labelSet ? 0 /* None */ : parser.labelSet[`$${label}`];
}
/**
 * Finish each the node for each parse. Set line / and column on the node if the
 * options are set for it
 *
 * @param parser Parser object
 * @param context Context masks
 * @param meta Line / column
 * @param node AST node
 */
function finishNode(context, parser, meta, node) {
    const { lastIndex, lastLine, lastColumn, sourceFile, index } = parser;
    if (context & 2 /* OptionsRanges */) {
        node.start = meta.index;
        node.end = lastIndex;
    }
    if (context & 16 /* OptionsLoc */) {
        node.loc = {
            start: {
                line: meta.line,
                column: meta.column
            },
            end: {
                line: lastLine,
                column: lastColumn
            }
        };
        if (sourceFile)
            node.loc.source = sourceFile;
    }
    return node;
}
/**
 * Consumes the next token. If the consumed token is not of the expected type
 * then report an error and return null. Otherwise return true.
 *
 * @param parser Parser object
 * @param context Context masks
 * @param t Token
 * @param Err Optionally error message to be thrown
 */
function expect(parser, context, token, err = 1 /* UnexpectedToken */) {
    if (parser.token !== token)
        report(parser, err, tokenDesc(parser.token));
    nextToken(parser, context);
    return true;
}
/**
 * If the next token matches the given token, this consumes the token
 * and returns true. Otherwise return false.
 *
 * @param parser Parser object
 * @param context Context masks
 * @param t Token
 */
function consume(parser, context, token) {
    if (parser.token !== token)
        return false;
    nextToken(parser, context);
    return true;
}
/**
 * Advance and return the next token in the stream
 *
 * @param parser Parser object
 * @param context Context masks
 */
function nextToken(parser, context) {
    parser.lastIndex = parser.index;
    parser.lastLine = parser.line;
    parser.lastColumn = parser.column;
    return (parser.token = scan(parser, context));
}
const hasBit = (mask, flags) => (mask & flags) === flags;
/**
 * Automatic Semicolon Insertion
 *
 * @see [Link](https://tc39.github.io/ecma262/#sec-automatic-semicolon-insertion)
 *
 * @param parser Parser object
 * @param context Context masks
 */
function consumeSemicolon(parser, context) {
    return parser.token & 524288 /* ASI */ || parser.flags & 1 /* NewLine */
        ? consume(parser, context, 17301521 /* Semicolon */)
        : report(parser, !(context & 131072 /* Async */) && parser.token & 131072 /* IsAwait */ ? 36 /* AwaitOutsideAsync */ : 1 /* UnexpectedToken */, tokenDesc(parser.token));
}
/**
 * Bit fiddle current grammar state and keep track of the state during the parse and restore
 * it back to original state after finish parsing or throw.
 *
 * Ideas for this is basicly from V8 and SM, but also the Esprima parser does this in a similar way.
 *
 * However this implementation is an major improvement over similiar implementations, and
 * does not require additonal bitmasks to be set / unset during the parsing outside this function.
 *
 * @param parser Parser state
 * @param context Context mask
 * @param callback Callback function
 * @param errMsg Optional error message
 */
function parseExpressionCoverGrammar(parser, context, callback) {
    const { flags, pendingExpressionError } = parser;
    parser.flags |= 2 /* AllowBinding */ | 4 /* AllowDestructuring */;
    parser.pendingExpressionError = undefined;
    const res = callback(parser, context);
    // If there exist an pending expression error, we throw an error at
    // the same location it was recorded
    if (!!parser.pendingExpressionError) {
        const { error, line, column, index } = parser.pendingExpressionError;
        constructError(parser, context, index, line, column, error);
    }
    // Here we - just in case - disallow both binding and destructuring
    // and only set the bitmaks if the previous flags (before the callback)
    // is positive.
    // Note that this bitmasks may have been turned off during parsing
    // the callback
    parser.flags &= ~(2 /* AllowBinding */ | 4 /* AllowDestructuring */);
    if (flags & 2 /* AllowBinding */)
        parser.flags |= 2 /* AllowBinding */;
    if (flags & 4 /* AllowDestructuring */)
        parser.flags |= 4 /* AllowDestructuring */;
    parser.pendingExpressionError = pendingExpressionError;
    return res;
}
/**
 * Restor current grammar to previous state, or unset necessary bitmasks
 *
 * @param parser Parser state
 * @param context Context mask
 * @param callback Callback function
 */
function restoreExpressionCoverGrammar(parser, context, callback) {
    const { flags, pendingExpressionError } = parser;
    parser.flags |= 2 /* AllowBinding */ | 4 /* AllowDestructuring */;
    // Clear pending expression error
    parser.pendingExpressionError = undefined;
    const res = callback(parser, context);
    // Both the previous bitmasks and bitmasks set during parsing the callback
    // has to be positive for us to allow further binding or destructuring.
    // Note that we allow both before the callback, so this is the only thing
    // we need to check for.
    if (!(parser.flags & 2 /* AllowBinding */) || !(flags & 2 /* AllowBinding */)) {
        parser.flags &= ~2 /* AllowBinding */;
    }
    if (!(parser.flags & 4 /* AllowDestructuring */) || !(flags & 4 /* AllowDestructuring */)) {
        parser.flags &= ~4 /* AllowDestructuring */;
    }
    // Here we either
    //  1) restore to previous pending expression error
    //  or
    //  2) if a pending expression error have been set during the parse (*only in object literal*)
    //  we overwrite previous error, and keep the new one
    parser.pendingExpressionError = pendingExpressionError || parser.pendingExpressionError;
    return res;
}
/**
 * Set / unset yield / await context masks based on the
 * ModifierState masks before invoking the callback and
 * returning it's content
 *
 * @param parser Parser object
 * @param context Context masks
 * @param state Modifier state
 * @param callback Callback function to be invoked
 * @param methodState Optional Objectstate.
 */
function swapContext(parser, context, state, callback, methodState = 0 /* None */) {
    context &= ~(131072 /* Async */ | 262144 /* Yield */ | 524288 /* InParameter */);
    if (state & 1 /* Generator */)
        context |= 262144 /* Yield */;
    if (state & 2 /* Await */)
        context |= 131072 /* Async */;
    return callback(parser, context, methodState);
}
/**
 * Validates function params
 *
 * Note! In case anyone want to enable full scoping, replace 'paramSet' with an similiar
 * object on the parser object itself. Then push / set the tokenValue to
 * it an use an bitmask to mark it as an 'variable' not 'blockscope'. Then when
 * implementing lexical scoping, you can use that for validation.
 *
 * @param parser  Parser object
 * @param context Context masks
 * @param params Array of token values
 */
function validateParams(parser, context, params) {
    const paramSet = new Map();
    for (let i = 0; i < params.length; i++) {
        const key = `@${params[i]}`;
        if (paramSet.get(key)) {
            tolerant(parser, context, 79 /* ParamDupe */);
        }
        else
            paramSet.set(key, true);
    }
}
/**
 * Reinterpret various expressions as pattern
 * This is only used for assignment and arrow parameter list
 *
 * @param parser  Parser object
 * @param context Context masks
 * @param node AST node
 */
const reinterpret = (parser, context, node) => {
    switch (node.type) {
        case 'Identifier':
        case 'ArrayPattern':
        case 'AssignmentPattern':
        case 'ObjectPattern':
        case 'RestElement':
        case 'MetaProperty':
            return;
        case 'ArrayExpression':
            node.type = 'ArrayPattern';
            for (let i = 0; i < node.elements.length; ++i) {
                // skip holes in pattern
                if (node.elements[i] !== null) {
                    reinterpret(parser, context, node.elements[i]);
                }
            }
            return;
        case 'ObjectExpression':
            node.type = 'ObjectPattern';
            for (let i = 0; i < node.properties.length; i++) {
                reinterpret(parser, context, node.properties[i]);
            }
            return;
        case 'Property':
            reinterpret(parser, context, node.value);
            return;
        case 'SpreadElement':
            node.type = 'RestElement';
            if (node.argument.type !== 'ArrayExpression' &&
                node.argument.type !== 'ObjectExpression' &&
                !isValidSimpleAssignmentTarget(node.argument)) {
                tolerant(parser, context, 69 /* RestDefaultInitializer */);
            }
            reinterpret(parser, context, node.argument);
            break;
        case 'AssignmentExpression':
            node.type = 'AssignmentPattern';
            delete node.operator; // operator is not relevant for assignment pattern
            reinterpret(parser, context, node.left); // recursive descent
            return;
        case 'MemberExpression':
            if (!(context & 524288 /* InParameter */))
                return;
        // Fall through
        default:
            tolerant(parser, context, context & 524288 /* InParameter */ ? 75 /* NotBindable */ : 71 /* InvalidDestructuringTarget */, node.type);
    }
};
/**
 * Does a lookahead.
 *
 * @param parser Parser object
 * @param context  Context masks
 * @param callback Callback function to be invoked
 */
function lookahead(parser, context, callback) {
    const { tokenValue, flags, line, column, startColumn, index, lastColumn, startLine, lastLine, lastIndex, startIndex, tokenRaw, token, lastValue, tokenRegExp } = parser;
    const res = callback(parser, context);
    parser.index = index;
    parser.token = token;
    parser.tokenValue = tokenValue;
    parser.tokenValue = tokenValue;
    parser.flags = flags;
    parser.line = line;
    parser.column = column;
    parser.tokenRaw = tokenRaw;
    parser.lastValue = lastValue;
    parser.startColumn = startColumn;
    parser.lastColumn = lastColumn;
    parser.startLine = startLine;
    parser.lastLine = lastLine;
    parser.lastIndex = lastIndex;
    parser.startIndex = startIndex;
    parser.tokenRegExp = tokenRegExp;
    return res;
}
/**
 * Returns true if this an valid simple assignment target
 *
 * @param parser Parser object
 * @param context  Context masks
 */
function isValidSimpleAssignmentTarget(node) {
    return node.type === 'Identifier' || node.type === 'MemberExpression' ? true : false;
}
/**
 * Get current node location
 *
 * @param parser Parser object
 * @param context  Context masks
 */
function getLocation(parser) {
    return {
        line: parser.startLine,
        column: parser.startColumn,
        index: parser.startIndex
    };
}
/**
 * Returns true if this is an valid identifier
 *
 * @param context  Context masks
 * @param t  Token
 */
function isValidIdentifier(context, t) {
    if (context & 4096 /* Strict */) {
        if (context & 8192 /* Module */ && t & 131072 /* IsAwait */)
            return false;
        if (t & 1073741824 /* IsYield */)
            return false;
        return (t & 65536 /* IsIdentifier */) === 65536 /* IsIdentifier */ || (t & 36864 /* Contextual */) === 36864 /* Contextual */;
    }
    return ((t & 65536 /* IsIdentifier */) === 65536 /* IsIdentifier */ ||
        (t & 36864 /* Contextual */) === 36864 /* Contextual */ ||
        (t & 20480 /* FutureReserved */) === 20480 /* FutureReserved */);
}
/**
 * Returns true if this an valid lexical binding and not an identifier
 *
 * @param parser Parser object
 * @param context  Context masks
 */
function isLexical(parser, context) {
    nextToken(parser, context);
    const { token } = parser;
    return !!(token & (65536 /* IsIdentifier */ | 8388608 /* IsBindingPattern */ | 1073741824 /* IsYield */ | 131072 /* IsAwait */) ||
        token === 33574984 /* LetKeyword */ ||
        (token & 36864 /* Contextual */) === 36864 /* Contextual */);
}
/**
 * Returns true if this is end of case or default clauses
 *
 * @param parser Parser object
 */
function isEndOfCaseOrDefaultClauses(parser) {
    return (parser.token === 12368 /* DefaultKeyword */ || parser.token === 17301519 /* RightBrace */ || parser.token === 12363 /* CaseKeyword */);
}
/**
 * Validates if the next token in the stream is a left paren or a period
 *
 * @param parser Parser object
 * @param context  Context masks
 */
function nextTokenIsLeftParenOrPeriod(parser, context) {
    nextToken(parser, context);
    return parser.token === 50331659 /* LeftParen */ || parser.token === 16777229 /* Period */;
}
/**
 * Validates if the next token in the stream is a identifier or left paren
 *
 * @param parser Parser object
 * @param context  Context masks
 */
function nextTokenisIdentifierOrParen(parser, context) {
    nextToken(parser, context);
    const { token } = parser;
    return token & (65536 /* IsIdentifier */ | 1073741824 /* IsYield */) || token === 50331659 /* LeftParen */;
}
/**
 * Validates if the next token in the stream is left parenthesis.
 *
 * @param parser Parser object
 * @param context  Context masks
 */
function nextTokenIsLeftParen(parser, context) {
    nextToken(parser, context);
    return parser.token === 50331659 /* LeftParen */;
}
/**
 * Validates if the next token in the stream is a function keyword on the same line.
 *
 * @param parser Parser object
 * @param context  Context masks
 */
function nextTokenIsFuncKeywordOnSameLine(parser, context) {
    nextToken(parser, context);
    return !(parser.flags & 1 /* NewLine */) && parser.token === 33566808 /* FunctionKeyword */;
}
/**
 * Checks if the property has any private field key
 *
 * @param parser Parser object
 * @param context  Context masks
 */
function isPropertyWithPrivateFieldKey(expr) {
    return !expr.property ? false : expr.property.type === 'PrivateName';
}
/**
 * Validates an identifier and either parse it or throw
 *
 * @param parser Parser object
 * @param context Context masks
 */
function parseAndValidateIdentifier(parser, context) {
    const { token } = parser;
    if (context & 4096 /* Strict */) {
        // Module code is also "strict mode code"
        if (context & 8192 /* Module */ && token & 131072 /* IsAwait */) {
            tolerant(parser, context, 38 /* DisallowedInContext */, tokenDesc(token));
        }
        if (token & 1073741824 /* IsYield */)
            tolerant(parser, context, 38 /* DisallowedInContext */, tokenDesc(token));
        if ((token & 65536 /* IsIdentifier */) === 65536 /* IsIdentifier */ || (token & 36864 /* Contextual */) === 36864 /* Contextual */) {
            return parseIdentifier(parser, context);
        }
        report(parser, 1 /* UnexpectedToken */, tokenDesc(token));
    }
    if (context & 262144 /* Yield */ && token & 1073741824 /* IsYield */) {
        tolerant(parser, context, 38 /* DisallowedInContext */, tokenDesc(token));
    }
    else if (context & 131072 /* Async */ && token & 131072 /* IsAwait */) {
        tolerant(parser, context, 38 /* DisallowedInContext */, tokenDesc(token));
    }
    if ((token & 65536 /* IsIdentifier */) === 65536 /* IsIdentifier */ ||
        (token & 36864 /* Contextual */) === 36864 /* Contextual */ ||
        (token & 20480 /* FutureReserved */) === 20480 /* FutureReserved */) {
        return parseIdentifier(parser, context);
    }
    report(parser, 1 /* UnexpectedToken */, tokenDesc(parser.token));
}
function nameIsArgumentsOrEval(value) {
    return value === 'eval' || value === 'arguments';
}
/**
 * Records an error from current position. If we report an error later, we'll do it from
 * this position.
 *
 * @param parser Parser object
 */
function setPendingError(parser) {
    parser.errorLocation = {
        line: parser.startLine,
        column: parser.startColumn,
        index: parser.startIndex
    };
}
/**
 * Returns tagName for JSX element
 *
 * @param elementName JSX Element name
 */
function isEqualTagNames(elementName) {
    // tslint:disable-next-line:switch-default | this switch is exhaustive
    switch (elementName.type) {
        case 'JSXIdentifier':
            return elementName.name;
        case 'JSXNamespacedName':
            return `${isEqualTagNames(elementName.namespace)}:${isEqualTagNames(elementName.name)}`;
        case 'JSXMemberExpression':
            return `${isEqualTagNames(elementName.object)}.${isEqualTagNames(elementName.property)}`;
    }
}
/**
 * Returns true if this is an instance field ( stage 3 proposal)
 *
 * @param parser Parser object
 */
function isInstanceField(parser) {
    const { token } = parser;
    return token === 17301519 /* RightBrace */ || token === 17301521 /* Semicolon */ || token === 83886109 /* Assign */;
}
/**
 *
 * @param parser Parser object
 * @param context Context masks
 * @param expr  AST expressions
 * @param prefix prefix
 */
function validateUpdateExpression(parser, context, expr, prefix) {
    if (context & 4096 /* Strict */ && nameIsArgumentsOrEval(expr.name)) {
        tolerant(parser, context, 66 /* StrictLHSPrefixPostFix */, prefix);
    }
    if (!isValidSimpleAssignmentTarget(expr)) {
        tolerant(parser, context, 4 /* InvalidLHSInAssignment */);
    }
}
/**
 * Record expression error
 *
 * @param parser Parser object
 * @param error Error message
 */
function setPendingExpressionError(parser, type) {
    parser.pendingExpressionError = {
        error: errorMessages[type],
        line: parser.line,
        column: parser.column,
        index: parser.index
    };
}
/**
 * Validate coer parenthesized expression
 *
 * @param parser Parser object
 * @param state CoverParenthesizedState
 */
function validateCoverParenthesizedExpression(parser, state) {
    const { token } = parser;
    if (token & 8388608 /* IsBindingPattern */) {
        parser.flags |= 8 /* SimpleParameterList */;
    }
    else {
        if ((token & 4194304 /* IsEvalOrArguments */) === 4194304 /* IsEvalOrArguments */) {
            setPendingError(parser);
            state |= 2 /* HasEvalOrArguments */;
        }
        else if ((token & 20480 /* FutureReserved */) === 20480 /* FutureReserved */) {
            setPendingError(parser);
            state |= 4 /* HasReservedWords */;
        }
        else if ((token & 131072 /* IsAwait */) === 131072 /* IsAwait */) {
            setPendingError(parser);
            parser.flags |= 8192 /* HasAwait */;
        }
    }
    return state;
}
/**
 * Validate coer parenthesized expression
 *
 * @param parser Parser object
 * @param state CoverParenthesizedState
 */
function validateAsyncArgumentList(parser, context, state) {
    const { token } = parser;
    if (!(parser.flags & 2 /* AllowBinding */)) {
        tolerant(parser, context, 75 /* NotBindable */);
    }
    else if (token & 8388608 /* IsBindingPattern */) {
        parser.flags |= 8 /* SimpleParameterList */;
    }
    else {
        if ((token & 4194304 /* IsEvalOrArguments */) === 4194304 /* IsEvalOrArguments */) {
            setPendingError(parser);
            state |= 8 /* EvalOrArguments */;
        }
        else if ((token & 131072 /* IsAwait */) === 131072 /* IsAwait */) {
            setPendingError(parser);
            state |= 32 /* Await */;
        }
        else if ((token & 1073741824 /* IsYield */) === 1073741824 /* IsYield */) {
            setPendingError(parser);
            state |= 16 /* Yield */;
        }
    }
    return state;
}

// JSX Specification
// https://facebook.github.io/jsx/
/**
 * Parses JSX element or JSX fragment
 *
 * @param parser Parser object
 * @param context Context masks
 */
function parseJSXRootElement(parser, context) {
    const pos = getLocation(parser);
    let children = [];
    let closingElement = null;
    let selfClosing = false;
    let openingElement;
    expect(parser, context, 167774015 /* LessThan */);
    const isFragment = parser.token === 167774016 /* GreaterThan */;
    if (isFragment) {
        openingElement = parseJSXOpeningFragment(parser, context, pos);
    }
    else {
        const name = parseJSXElementName(parser, context);
        const attributes = parseJSXAttributes(parser, context);
        selfClosing = consume(parser, context, 167774773 /* Divide */);
        openingElement = parseJSXOpeningElement(parser, context, name, attributes, selfClosing, pos);
    }
    if (isFragment)
        return parseJSXFragment(parser, context, openingElement, pos);
    if (!selfClosing) {
        children = parseJSXChildren(parser, context);
        closingElement = parseJSXClosingElement(parser, context);
        const open = isEqualTagNames(openingElement.name);
        const close = isEqualTagNames(closingElement.name);
        if (open !== close)
            report(parser, 83 /* ExpectedJSXClosingTag */, close);
    }
    return finishNode(context, parser, pos, {
        type: 'JSXElement',
        children,
        openingElement,
        closingElement,
    });
}
/**
 * Parses JSX opening element
 *
 * @param parser Parser object
 * @param context Context masks
 * @param name Element name
 * @param attributes Element attributes
 * @param selfClosing True if this is a selfclosing JSX Element
 * @param pos Line / Column tracking
 */
function parseJSXOpeningElement(parser, context, name, attributes, selfClosing, pos) {
    if (context & 268435456 /* InJSXChild */ && selfClosing)
        expect(parser, context, 167774016 /* GreaterThan */);
    else
        nextJSXToken(parser);
    return finishNode(context, parser, pos, {
        type: 'JSXOpeningElement',
        name,
        attributes,
        selfClosing,
    });
}
/**
 * Parse JSX fragment
 *
 * @param parser Parser object
 * @param context Context masks
 * @param openingElement Opening fragment
 * @param pos Line / Column location
 */
function parseJSXFragment(parser, context, openingElement, pos) {
    const children = parseJSXChildren(parser, context);
    const closingFragment = parseJSXClosingFragment(parser, context);
    return finishNode(context, parser, pos, {
        type: 'JSXFragment',
        children,
        openingElement,
        closingFragment,
    });
}
/**
 * Parse JSX opening fragmentD
 *
 * @param parser Parser object
 * @param context Context masks
 * @param pos Line / Column location
 */
function parseJSXOpeningFragment(parser, context, pos) {
    nextJSXToken(parser);
    return finishNode(context, parser, pos, {
        type: 'JSXOpeningFragment',
    });
}
/**
 * Prime the scanner and advance to the next JSX token in the stream
 *
 * @param parser Parser object
 * @param context Context masks
 */
function nextJSXToken(parser) {
    return parser.token = scanJSXToken(parser);
}
/**
 * Mini scanner
 *
 * @param parser Parser object
 * @param context Context masks
 */
function scanJSXToken(parser) {
    if (parser.index >= parser.source.length)
        return 524288 /* EndOfSource */;
    parser.lastIndex = parser.startIndex = parser.index;
    const char = parser.source.charCodeAt(parser.index);
    if (char === 60 /* LessThan */) {
        parser.index++;
        parser.column++;
        return consumeOpt(parser, 47 /* Slash */) ? 25 /* JSXClose */ : 167774015 /* LessThan */;
    }
    else if (char === 123 /* LeftBrace */) {
        parser.index++;
        parser.column++;
        return 41943052 /* LeftBrace */;
    }
    while (parser.index < parser.source.length) {
        parser.index++;
        parser.column++;
        const next = parser.source.charCodeAt(parser.index);
        if (next === 123 /* LeftBrace */ || next === 60 /* LessThan */)
            break;
    }
    return 121 /* JSXText */;
}
/**
 * Parses JSX children
 *
 * @param parser Parser object
 * @param context Context masks
 */
function parseJSXChildren(parser, context) {
    const children = [];
    while (parser.token !== 25 /* JSXClose */) {
        children.push(parseJSXChild(parser, context));
    }
    return children;
}
/**
 * Parses JSX Text
 *
 * @param parser Parser object
 * @param context Context masks
 */
function parseJSXText(parser, context) {
    const pos = getLocation(parser);
    const value = parser.source.slice(parser.startIndex, parser.index);
    parser.token = scanJSXToken(parser);
    const node = finishNode(context, parser, pos, {
        type: 'JSXText',
        value,
    });
    if (context & 8 /* OptionsRaw */)
        node.raw = value;
    return node;
}
/**
 * Parses JSX Child
 *
 * @param parser Parser object
 * @param context Context masks
 */
function parseJSXChild(parser, context) {
    switch (parser.token) {
        case 33619969 /* Identifier */:
        case 121 /* JSXText */:
            return parseJSXText(parser, context);
        case 41943052 /* LeftBrace */:
            return parseJSXExpression(parser, context & ~268435456 /* InJSXChild */);
        case 167774015 /* LessThan */:
            return parseJSXRootElement(parser, context & ~268435456 /* InJSXChild */);
        default:
            report(parser, 0 /* Unexpected */);
    }
    return undefined; // note: get rid of this
}
/**
 * Parses JSX attributes
 *
 * @param parser Parser object
 * @param context Context masks
 */
function parseJSXAttributes(parser, context) {
    const attributes = [];
    while (parser.index < parser.source.length) {
        if (parser.token === 167774773 /* Divide */ || parser.token === 167774016 /* GreaterThan */)
            break;
        attributes.push(parseJSXAttribute(parser, context));
    }
    return attributes;
}
/**
 * Parses JSX spread attribute
 *
 * @param parser Parser object
 * @param context Context masks
 */
function parseJSXSpreadAttribute(parser, context) {
    const pos = getLocation(parser);
    expect(parser, context, 41943052 /* LeftBrace */);
    expect(parser, context, 14 /* Ellipsis */);
    const expression = parseExpressionCoverGrammar(parser, context & ~268435456 /* InJSXChild */, parseAssignmentExpression);
    expect(parser, context, 17301519 /* RightBrace */);
    return finishNode(context, parser, pos, {
        type: 'JSXSpreadAttribute',
        argument: expression,
    });
}
/**
 * Parses JSX namespace name
 *
 * @param parser Parser object
 * @param context Context masks
 * @param namespace Identifier
 * @param pos Line / Column location
 */
function parseJSXNamespacedName(parser, context, namespace, pos) {
    expect(parser, context, 16777237 /* Colon */);
    const name = parseJSXIdentifier(parser, context);
    return finishNode(context, parser, pos, {
        type: 'JSXNamespacedName',
        namespace,
        name,
    });
}
/**
 * Parses JSX attribute name
 *
 * @param parser Parser object
 * @param context Context masks
 */
function parseJSXAttributeName(parser, context) {
    const pos = getLocation(parser);
    const identifier = parseJSXIdentifier(parser, context);
    return parser.token === 16777237 /* Colon */ ?
        parseJSXNamespacedName(parser, context, identifier, pos) :
        identifier;
}
/**
 * Parses JSX Attribute value
 *
 * @param parser Parser object
 * @param context Context masks
 */
function parseJSXAttributeValue(parser, context) {
    switch (scanJSXAttributeValue(parser, context)) {
        case 33554435 /* StringLiteral */:
            return parseLiteral(parser, context);
        case 41943052 /* LeftBrace */:
            return parseJSXExpressionContainer(parser, context | 268435456 /* InJSXChild */);
        case 167774015 /* LessThan */:
            return parseJSXRootElement(parser, context | 268435456 /* InJSXChild */);
        default:
            tolerant(parser, context, 85 /* InvalidJSXAttributeValue */);
    }
    return undefined; // note: get rid of this
}
/**
 * Parses JSX Attribute
 *
 * @param parser Parser object
 * @param context Context masks
 */
function parseJSXAttribute(parser, context) {
    const pos = getLocation(parser);
    if (parser.token === 41943052 /* LeftBrace */)
        return parseJSXSpreadAttribute(parser, context);
    scanJSXIdentifier(parser);
    const attrName = parseJSXAttributeName(parser, context);
    const value = parser.token === 83886109 /* Assign */ ? parseJSXAttributeValue(parser, context) : null;
    return finishNode(context, parser, pos, {
        type: 'JSXAttribute',
        value: value,
        name: attrName,
    });
}
/**
 * Parses JSX Attribute value
 *
 * @param parser Parser object
 * @param context Context masks
 */
function scanJSXAttributeValue(parser, context) {
    parser.lastIndex = parser.index;
    const ch = parser.source.charCodeAt(parser.index);
    switch (ch) {
        case 34 /* DoubleQuote */:
        case 39 /* SingleQuote */:
            return scanJSXString(parser, context, ch);
        default:
            return nextToken(parser, context);
    }
}
/**
 * Parses JSX String
 *
 * @param parser Parser object
 * @param context Context masks
 * @param quote Code point
 */
function scanJSXString(parser, context, quote) {
    const rawStart = parser.index;
    parser.index++;
    parser.column++;
    let ret = '';
    let ch = parser.source.charCodeAt(parser.index);
    while (ch !== quote) {
        ret += fromCodePoint(ch);
        parser.index++;
        parser.column++;
        ch = parser.source.charCodeAt(parser.index);
        if (parser.index >= parser.source.length)
            report(parser, 5 /* UnterminatedString */);
    }
    parser.index++;
    parser.column++; // skip the quote
    // raw
    if (context & 8 /* OptionsRaw */)
        parser.tokenRaw = parser.source.slice(rawStart, parser.index);
    parser.tokenValue = ret;
    return 33554435 /* StringLiteral */;
}
/**
 * Parses JJSX Empty Expression
 *
 * @param parser Parser object
 * @param context Context masks
 */
function parseJSXEmptyExpression(parser, context) {
    const pos = getLocation(parser);
    return finishNode(context, parser, pos, {
        type: 'JSXEmptyExpression',
    });
}
/**
 * Parses JSX Spread child
 *
 * @param parser Parser object
 * @param context Context masks
 */
function parseJSXSpreadChild(parser, context) {
    const pos = getLocation(parser);
    expect(parser, context, 14 /* Ellipsis */);
    const expression = parseExpression(parser, context);
    expect(parser, context, 17301519 /* RightBrace */);
    return finishNode(context, parser, pos, {
        type: 'JSXSpreadChild',
        expression,
    });
}
/**
 * Parses JSX Expression container
 *
 * @param parser Parser object
 * @param context Context masks
 */
function parseJSXExpressionContainer(parser, context) {
    const pos = getLocation(parser);
    expect(parser, context, 41943052 /* LeftBrace */);
    // Note: JSX Expressions can't be empty
    if (parser.token === 17301519 /* RightBrace */)
        tolerant(parser, context, 82 /* NonEmptyJSXExpression */);
    const expression = parseExpressionCoverGrammar(parser, context & ~268435456 /* InJSXChild */, parseAssignmentExpression);
    expect(parser, context, 17301519 /* RightBrace */);
    return finishNode(context, parser, pos, {
        type: 'JSXExpressionContainer',
        expression,
    });
}
/**
 * Parses JSX Expression
 *
 * @param parser Parser object
 * @param context Context masks
 * @param pos Line / Column location
 */
function parseJSXExpression(parser, context) {
    const pos = getLocation(parser);
    expect(parser, context, 41943052 /* LeftBrace */);
    if (parser.token === 14 /* Ellipsis */)
        return parseJSXSpreadChild(parser, context);
    const expression = parser.token === 17301519 /* RightBrace */ ?
        parseJSXEmptyExpression(parser, context) :
        parseExpressionCoverGrammar(parser, context, parseAssignmentExpression);
    nextJSXToken(parser);
    return finishNode(context, parser, pos, {
        type: 'JSXExpressionContainer',
        expression,
    });
}
/**
 * Parses JSX Closing fragment
 *
 * @param parser Parser object
 * @param context Context masks
 */
function parseJSXClosingFragment(parser, context) {
    const pos = getLocation(parser);
    expect(parser, context, 25 /* JSXClose */);
    expect(parser, context, 167774016 /* GreaterThan */);
    return finishNode(context, parser, pos, {
        type: 'JSXClosingFragment',
    });
}
/**
 * Parses JSX Closing Element
 *
 * @param parser Parser object
 * @param context Context masks
 * @param pos Line / Column location
 */
function parseJSXClosingElement(parser, context) {
    const pos = getLocation(parser);
    expect(parser, context, 25 /* JSXClose */);
    const name = parseJSXElementName(parser, context);
    if (context & 268435456 /* InJSXChild */)
        expect(parser, context, 167774016 /* GreaterThan */);
    else
        nextJSXToken(parser);
    return finishNode(context, parser, pos, {
        type: 'JSXClosingElement',
        name,
    });
}
/**
 * Parses JSX Identifier
 *
 * @param parser Parser object
 * @param context Context masks
 */
function parseJSXIdentifier(parser, context) {
    const { token, tokenValue: name, tokenRaw: raw } = parser;
    if (!(token & (65536 /* IsIdentifier */ | 4096 /* Keyword */))) {
        tolerant(parser, context, 1 /* UnexpectedToken */, tokenDesc(parser.token));
    }
    const pos = getLocation(parser);
    nextToken(parser, context);
    const node = finishNode(context, parser, pos, {
        type: 'JSXIdentifier',
        name,
    });
    if (context & 256 /* OptionsRawidentifiers */)
        node.raw = raw;
    return node;
}
/**
 * Parses JSX Member expression
 *
 * @param parser Parser object
 * @param context Context masks
 * @param pos Line / Column location
 */
function parseJSXMemberExpression(parser, context, expr, pos) {
    // Note: In order to be able to parse cases like ''<A.B.C.D.E.foo-bar />', where the dash is located at the
    // end, we must rescan for the JSX Identifier now. This because JSX identifiers differ from normal identifiers
    scanJSXIdentifier(parser);
    return finishNode(context, parser, pos, {
        type: 'JSXMemberExpression',
        object: expr,
        property: parseJSXIdentifier(parser, context),
    });
}
/**
 * Parses JSX Element name
 *
 * @param parser Parser object
 * @param context Context masks
 */
function parseJSXElementName(parser, context) {
    const pos = getLocation(parser);
    scanJSXIdentifier(parser);
    let elementName = parseJSXIdentifier(parser, context);
    if (parser.token === 16777237 /* Colon */)
        return parseJSXNamespacedName(parser, context, elementName, pos);
    while (consume(parser, context, 16777229 /* Period */)) {
        elementName = parseJSXMemberExpression(parser, context, elementName, pos);
    }
    return elementName;
}
/**
 * Scans JSX Identifier
 *
 * @param parser Parser object
 * @param context Context masks
 */
function scanJSXIdentifier(parser) {
    const { token } = parser;
    if (token & (65536 /* IsIdentifier */ | 4096 /* Keyword */)) {
        const firstCharPosition = parser.index;
        let ch = parser.source.charCodeAt(parser.index);
        while ((parser.index < parser.source.length) && (ch === 45 /* Hyphen */ || (isValidIdentifierPart(ch)))) {
            ch = readNext(parser);
        }
        parser.tokenValue += parser.source.substr(firstCharPosition, parser.index - firstCharPosition);
    }
    return parser.token;
}

/**
 * Expression :
 *   AssignmentExpression
 *   Expression , AssignmentExpression
 *
 * ExpressionNoIn :
 *   AssignmentExpressionNoIn
 *   ExpressionNoIn , AssignmentExpressionNoIn
 *
 * @see [Link](https://tc39.github.io/ecma262/#prod-Expression)
 *
 * @param parser Parser object
 * @param context Context masks
 */
function parseExpression(parser, context) {
    const pos = getLocation(parser);
    const saveDecoratorContext = parser.flags;
    const expr = parseExpressionCoverGrammar(parser, context, parseAssignmentExpression);
    return parser.token === 16777234 /* Comma */ ?
        parseSequenceExpression(parser, context, expr, pos) :
        expr;
}
/**
 * Parse secuence expression
 *
 * @param parser Parser object
 * @param context Context masks
 */
function parseSequenceExpression(parser, context, left, pos) {
    const expressions = [left];
    while (consume(parser, context, 16777234 /* Comma */)) {
        expressions.push(parseExpressionCoverGrammar(parser, context, parseAssignmentExpression));
    }
    return finishNode(context, parser, pos, {
        type: 'SequenceExpression',
        expressions,
    });
}
/**
 * Parse yield expression
 *
 * @see [Link](https://tc39.github.io/ecma262/#prod-YieldExpression)
 *
 * @param parser Parser object
 * @param context Context masks
 */
function parseYieldExpression(parser, context, pos) {
    // YieldExpression[In] :
    //    yield
    //    yield [no LineTerminator here] AssignmentExpression[?In, Yield]
    //    yield [no LineTerminator here] * AssignmentExpression[?In, Yield]
    // https://tc39.github.io/ecma262/#sec-generator-function-definitions-static-semantics-early-errors
    if (context & 524288 /* InParameter */)
        tolerant(parser, context, 49 /* YieldInParameter */);
    expect(parser, context, 1107316842 /* YieldKeyword */);
    let argument = null;
    let delegate = false;
    if (!(parser.flags & 1 /* NewLine */)) {
        delegate = consume(parser, context, 167774771 /* Multiply */);
        // 'Token.IsExpressionStart' bitmask contains the complete set of
        // tokens that can appear after an AssignmentExpression, and none of them
        // can start an AssignmentExpression.
        if (delegate || parser.token & 33554432 /* IsExpressionStart */) {
            argument = parseAssignmentExpression(parser, context);
        }
    }
    return finishNode(context, parser, pos, {
        type: 'YieldExpression',
        argument,
        delegate,
    });
}
/**
 * AssignmentExpression :
 *   ConditionalExpression
 *   YieldExpression
 *   ArrowFunction
 *   AsyncArrowFunction
 *   LeftHandSideExpression = AssignmentExpression
 *   LeftHandSideExpression AssignmentOperator AssignmentExpression
 *
 * AssignmentExpressionNoIn :
 *   ConditionalExpressionNoIn
 *   YieldExpression
 *   ArrowFunction
 *   AsyncArrowFunction
 *   LeftHandSideExpression = AssignmentExpressionNoIn
 *   LeftHandSideExpression AssignmentOperator AssignmentExpressionNoIn
 *
 *
 * @see [Link](https://tc39.github.io/ecma262/#prod-AssignmentExpression)
 *
 * @param parser Parser object
 * @param context Context masks
 */
function parseAssignmentExpression(parser, context) {
    const pos = getLocation(parser);
    let { token } = parser;
    if (context & 262144 /* Yield */ && token & 1073741824 /* IsYield */)
        return parseYieldExpression(parser, context, pos);
    let expr = token & 262144 /* IsAsync */ && lookahead(parser, context, nextTokenisIdentifierOrParen)
        ? parserCoverCallExpressionAndAsyncArrowHead(parser, context)
        : parseConditionalExpression(parser, context, pos);
    if (parser.token === 10 /* Arrow */) {
        if (token & (65536 /* IsIdentifier */ | 4096 /* Keyword */)) {
            if (token & (20480 /* FutureReserved */ | 4194304 /* IsEvalOrArguments */)) {
                // Invalid: ' yield => { 'use strict'; 0 };'
                if (token & 20480 /* FutureReserved */) {
                    parser.flags |= 64 /* HasStrictReserved */;
                }
                if (token & 4194304 /* IsEvalOrArguments */) {
                    if (context & 4096 /* Strict */)
                        tolerant(parser, context, 45 /* StrictEvalArguments */);
                    parser.flags |= 2048 /* StrictEvalArguments */;
                }
            }
            expr = [expr];
        }
        return parseArrowFunction(parser, context &= ~131072 /* Async */, pos, expr);
    }
    if (hasBit(parser.token, 67108864 /* IsAssignOp */)) {
        token = parser.token;
        if (context & 4096 /* Strict */ && nameIsArgumentsOrEval(expr.name)) {
            tolerant(parser, context, 15 /* StrictLHSAssignment */);
        }
        else if (consume(parser, context, 83886109 /* Assign */)) {
            if (!(parser.flags & 4 /* AllowDestructuring */)) {
                tolerant(parser, context, 71 /* InvalidDestructuringTarget */);
            }
            // Only re-interpret if not inside a formal parameter list
            if (!(context & 524288 /* InParameter */))
                reinterpret(parser, context, expr);
            if (context & 134217728 /* InParen */)
                parser.flags |= 8 /* SimpleParameterList */;
            if (parser.token & 131072 /* IsAwait */) {
                setPendingError(parser);
                parser.flags |= 8192 /* HasAwait */;
            }
            else if (context & 134217728 /* InParen */ &&
                context & (4096 /* Strict */ | 262144 /* Yield */) &&
                parser.token & 1073741824 /* IsYield */) {
                setPendingError(parser);
                parser.flags |= 16384 /* HasYield */;
            }
        }
        else {
            if (!isValidSimpleAssignmentTarget(expr)) {
                tolerant(parser, context, 4 /* InvalidLHSInAssignment */);
            }
            parser.flags &= ~(4 /* AllowDestructuring */ | 2 /* AllowBinding */);
            nextToken(parser, context);
        }
        const right = parseExpressionCoverGrammar(parser, context | 65536 /* AllowIn */, parseAssignmentExpression);
        parser.pendingExpressionError = null;
        return finishNode(context, parser, pos, {
            type: 'AssignmentExpression',
            left: expr,
            operator: tokenDesc(token),
            right,
        });
    }
    return expr;
}
/**
 * Parse conditional expression
 *
 * @see [Link](https://tc39.github.io/ecma262/#prod-ConditionalExpression)
 *
 * @param parser Parser object
 * @param context Context masks
 */
function parseConditionalExpression(parser, context, pos) {
    const test = parseBinaryExpression(parser, context, 0, pos);
    if (!consume(parser, context, 22 /* QuestionMark */))
        return test;
    const consequent = parseExpressionCoverGrammar(parser, context & ~1073741824 /* AllowDecorator */ | 65536 /* AllowIn */, parseAssignmentExpression);
    expect(parser, context, 16777237 /* Colon */);
    return finishNode(context, parser, pos, {
        type: 'ConditionalExpression',
        test,
        consequent,
        alternate: parseExpressionCoverGrammar(parser, context, parseAssignmentExpression),
    });
}
/**
 * Parse binary expression.
 *
 * @see [Link](https://tc39.github.io/ecma262/#sec-exp-operator)
 * @see [Link](https://tc39.github.io/ecma262/#sec-binary-logical-operators)
 * @see [Link](https://tc39.github.io/ecma262/#sec-additive-operators)
 * @see [Link](https://tc39.github.io/ecma262/#sec-bitwise-shift-operators)
 * @see [Link](https://tc39.github.io/ecma262/#sec-equality-operators)
 * @see [Link](https://tc39.github.io/ecma262/#sec-binary-logical-operators)
 * @see [Link](https://tc39.github.io/ecma262/#sec-relational-operators)
 * @see [Link](https://tc39.github.io/ecma262/#sec-multiplicative-operators)
 *
 * @param parser Parser object
 * @param context Context masks
 * @param minPrec Minimum precedence value
 * @param pos Line / Column info
 * @param Left Left hand side of the binary expression
 */
function parseBinaryExpression(parser, context, minPrec, pos, left = parseUnaryExpression(parser, context)) {
    // Shift-reduce parser for the binary operator part of the JS expression
    // syntax.
    const bit = context & 65536 /* AllowIn */ ^ 65536 /* AllowIn */;
    while (hasBit(parser.token, 167772160 /* IsBinaryOp */)) {
        const t = parser.token;
        if (bit && t === 168834865 /* InKeyword */)
            break;
        const prec = t & 3840 /* Precedence */;
        const delta = (t === 167775030 /* Exponentiate */) << 8 /* PrecStart */;
        // When the next token is no longer a binary operator, it's potentially the
        // start of an expression, so we break the loop
        if (prec + delta <= minPrec)
            break;
        nextToken(parser, context);
        left = finishNode(context, parser, pos, {
            type: t & 2097152 /* IsLogical */ ? 'LogicalExpression' : 'BinaryExpression',
            left,
            right: parseBinaryExpression(parser, context & ~65536 /* AllowIn */, prec, getLocation(parser)),
            operator: tokenDesc(t),
        });
    }
    return left;
}
/**
 * Parse await expression
 *
 * @see [Link](https://tc39.github.io/ecma262/#prod-AwaitExpression)
 *
 * @param parser Parser object
 * @param context Context masks
 * @param pos Location info
 */
function parseAwaitExpression(parser, context, pos) {
    if (context & 524288 /* InParameter */)
        tolerant(parser, context, 50 /* AwaitInParameter */);
    expect(parser, context, 33788013 /* AwaitKeyword */);
    return finishNode(context, parser, pos, {
        type: 'AwaitExpression',
        argument: parseUnaryExpression(parser, context),
    });
}
/**
 * Parses unary expression
 *
 * @see [Link](https://tc39.github.io/ecma262/#prod-UnaryExpression)
 *
 * @param parser Parser object
 * @param context Context masks
 */
function parseUnaryExpression(parser, context) {
    const pos = getLocation(parser);
    const { token } = parser;
    if (hasBit(token, 301989888 /* IsUnaryOp */)) {
        nextToken(parser, context);
        if (parser.flags & 32768 /* EscapedKeyword */)
            tolerant(parser, context, 2 /* InvalidEscapedReservedWord */);
        const argument = parseExpressionCoverGrammar(parser, context, parseUnaryExpression);
        if (parser.token === 167775030 /* Exponentiate */)
            tolerant(parser, context, 1 /* UnexpectedToken */, tokenDesc(parser.token));
        if (context & 4096 /* Strict */ && token === 302002219 /* DeleteKeyword */) {
            if (argument.type === 'Identifier') {
                tolerant(parser, context, 41 /* StrictDelete */);
            }
            else if (isPropertyWithPrivateFieldKey(argument)) {
                tolerant(parser, context, 42 /* DeletePrivateField */);
            }
        }
        return finishNode(context, parser, pos, {
            type: 'UnaryExpression',
            operator: tokenDesc(token),
            argument,
            prefix: true,
        });
    }
    return context & 131072 /* Async */ && token & 131072 /* IsAwait */
        ? parseAwaitExpression(parser, context, pos)
        : parseUpdateExpression(parser, context, pos);
}
/**
 * Parses update expression
 *
 * @see [Link](https://tc39.github.io/ecma262/#prod-UpdateExpression)
 *
 * @param parser Parser object
 * @param context Context masks
 */
function parseUpdateExpression(parser, context, pos) {
    const { token } = parser;
    if (hasBit(parser.token, 570425344 /* IsUpdateOp */)) {
        nextToken(parser, context);
        const expr = parseLeftHandSideExpression(parser, context, pos);
        validateUpdateExpression(parser, context, expr, 'Prefix');
        return finishNode(context, parser, pos, {
            type: 'UpdateExpression',
            argument: expr,
            operator: tokenDesc(token),
            prefix: true,
        });
    }
    else if (context & 4 /* OptionsJSX */ && token === 167774015 /* LessThan */) {
        return parseJSXRootElement(parser, context | 268435456 /* InJSXChild */);
    }
    const expression = parseLeftHandSideExpression(parser, context, pos);
    if (hasBit(parser.token, 570425344 /* IsUpdateOp */) && !(parser.flags & 1 /* NewLine */)) {
        validateUpdateExpression(parser, context, expression, 'Postfix');
        const operator = parser.token;
        nextToken(parser, context);
        return finishNode(context, parser, pos, {
            type: 'UpdateExpression',
            argument: expression,
            operator: tokenDesc(operator),
            prefix: false,
        });
    }
    return expression;
}
/**
 * Parse assignment rest element
 *
 * @see [Link](https://tc39.github.io/ecma262/#prod-AssignmentRestElement)
 *
 * @param parser Parser object
 * @param context Context masks
 */
function parseRestElement(parser, context, args = []) {
    const pos = getLocation(parser);
    expect(parser, context, 14 /* Ellipsis */);
    if (context & 134217728 /* InParen */ && parser.token & 131072 /* IsAwait */)
        parser.flags |= 8192 /* HasAwait */;
    const argument = parseBindingIdentifierOrPattern(parser, context, args);
    return finishNode(context, parser, pos, {
        type: 'RestElement',
        argument,
    });
}
/**
 * Parse spread element
 *
 * @see [Link](https://tc39.github.io/ecma262/#prod-SpreadElement)
 *
 * @param parser Parser object
 * @param context Context masks
 */
function parseSpreadElement(parser, context) {
    const pos = getLocation(parser);
    expect(parser, context, 14 /* Ellipsis */);
    const argument = restoreExpressionCoverGrammar(parser, context | 65536 /* AllowIn */, parseAssignmentExpression);
    return finishNode(context, parser, pos, {
        type: 'SpreadElement',
        argument,
    });
}
/**
 * Parse left hand side expression
 *
 * @see [Link](https://tc39.github.io/ecma262/#prod-LeftHandSideExpression)
 *
 * @param Parser Parer instance
 * @param Context Contextmasks
 * @param pos Location info
 */
function parseLeftHandSideExpression(parser, context, pos) {
    const expr = context & 1 /* OptionsNext */ && parser.token === 33566810 /* ImportKeyword */ ?
        parseCallImportOrMetaProperty(parser, context | 65536 /* AllowIn */) :
        parseMemberExpression(parser, context | 65536 /* AllowIn */, pos);
    return parseCallExpression(parser, context | 65536 /* AllowIn */, pos, expr);
}
/**
 * Parse member expression
 *
 * @see [Link](https://tc39.github.io/ecma262/#prod-MemberExpression)
 *
 * @param parser Parser object
 * @param context Context masks
 * @param pos Location info
 * @param expr Expression
 */
function parseMemberExpression(parser, context, pos, expr = parsePrimaryExpression(parser, context)) {
    while (true) {
        switch (parser.token) {
            case 16777229 /* Period */: {
                consume(parser, context, 16777229 /* Period */);
                parser.flags = parser.flags & ~2 /* AllowBinding */ | 4 /* AllowDestructuring */;
                const property = parseIdentifierNameOrPrivateName(parser, context);
                expr = finishNode(context, parser, pos, {
                    type: 'MemberExpression',
                    object: expr,
                    computed: false,
                    property,
                });
                continue;
            }
            case 41943059 /* LeftBracket */: {
                consume(parser, context, 41943059 /* LeftBracket */);
                parser.flags = parser.flags & ~2 /* AllowBinding */ | 4 /* AllowDestructuring */;
                const property = parseExpression(parser, context);
                expect(parser, context, 20 /* RightBracket */);
                expr = finishNode(context, parser, pos, {
                    type: 'MemberExpression',
                    object: expr,
                    computed: true,
                    property,
                });
                continue;
            }
            case 33554441 /* TemplateTail */: {
                expr = finishNode(context, parser, pos, {
                    type: 'TaggedTemplateExpression',
                    tag: expr,
                    quasi: parseTemplateLiteral(parser, context),
                });
                continue;
            }
            case 33554440 /* TemplateCont */: {
                expr = finishNode(context, parser, pos, {
                    type: 'TaggedTemplateExpression',
                    tag: expr,
                    quasi: parseTemplate(parser, context | 16384 /* TaggedTemplate */),
                });
                continue;
            }
            default:
                return expr;
        }
    }
}
/**
 * Parse call expression
 *
 * @param parser Parer instance
 * @param context Context masks
 * @param pos Line / Colum info
 * @param expr Expression
 */
function parseCallExpression(parser, context, pos, expr) {
    while (true) {
        expr = parseMemberExpression(parser, context, pos, expr);
        if (parser.token !== 50331659 /* LeftParen */)
            return expr;
        const args = parseArgumentList(parser, context & ~1073741824 /* AllowDecorator */);
        expr = finishNode(context, parser, pos, {
            type: 'CallExpression',
            callee: expr,
            arguments: args,
        });
    }
}
/**
 * Parse cover call expression and async arrow head
 *
 * @see [Link](https://tc39.github.io/ecma262/#prod-CoverCallExpressionAndAsyncArrowHead)
 *
 * @param parser  Parser object
 * @param context Context masks
 */
function parserCoverCallExpressionAndAsyncArrowHead(parser, context) {
    const pos = getLocation(parser);
    let expr = parseMemberExpression(parser, context | 65536 /* AllowIn */, pos);
    // Here we jump right into it and parse a simple, faster sub-grammar for
    // async arrow / async identifier + call expression. This could have been done different
    // but ESTree sucks!
    //
    // - J.K. Thomas
    if (parser.token & (65536 /* IsIdentifier */ | 4096 /* Keyword */)) {
        if (parser.token & 131072 /* IsAwait */)
            tolerant(parser, context, 38 /* DisallowedInContext */);
        return parseAsyncArrowFunction(parser, context, 2 /* Await */, pos, [parseAndValidateIdentifier(parser, context)]);
    }
    if (parser.flags & 1 /* NewLine */)
        tolerant(parser, context, 34 /* InvalidLineBreak */, 'async');
    while (parser.token === 50331659 /* LeftParen */) {
        expr = parseMemberExpression(parser, context, pos, expr);
        const args = parseAsyncArgumentList(parser, context);
        if (parser.token === 10 /* Arrow */) {
            expr = parseAsyncArrowFunction(parser, context, 2 /* Await */, pos, args);
            break;
        }
        expr = finishNode(context, parser, pos, {
            type: 'CallExpression',
            callee: expr,
            arguments: args,
        });
    }
    return expr;
}
/**
 * Parse argument list
 *
 * @see [https://tc39.github.io/ecma262/#prod-ArgumentList)
 *
 * @param Parser Parser object
 * @param Context Context masks
 */
function parseArgumentList(parser, context) {
    // ArgumentList :
    //   AssignmentOrSpreadExpression
    //   ArgumentList , AssignmentOrSpreadExpression
    //
    // AssignmentOrSpreadExpression :
    //   ... AssignmentExpression
    //   AssignmentExpression
    expect(parser, context, 50331659 /* LeftParen */);
    const expressions = [];
    while (parser.token !== 16 /* RightParen */) {
        if (parser.token === 14 /* Ellipsis */) {
            expressions.push(parseSpreadElement(parser, context));
        }
        else {
            if (context & 262144 /* Yield */ && hasBit(parser.token, 1073741824 /* IsYield */)) {
                parser.flags |= 16384 /* HasYield */;
                setPendingError(parser);
            }
            expressions.push(parseExpressionCoverGrammar(parser, context | 65536 /* AllowIn */, parseAssignmentExpression));
        }
        if (parser.token !== 16 /* RightParen */)
            expect(parser, context, 16777234 /* Comma */);
    }
    expect(parser, context, 16 /* RightParen */);
    return expressions;
}
/**
 * Parse argument list for async arrow / async call expression
 *
 * @see [https://tc39.github.io/ecma262/#prod-ArgumentList)
 *
 * @param Parser Parser object
 * @param Context Context masks
 */
function parseAsyncArgumentList(parser, context) {
    // Here we are parsing an "extended" argument list tweaked to handle async arrows. This is
    // done here to avoid overhead and possible performance loss if we only
    // parse out a simple call expression - E.g 'async(foo, bar)' or 'async(foo, bar)()';
    //
    // - J.K. Thomas
    expect(parser, context, 50331659 /* LeftParen */);
    const args = [];
    let { token } = parser;
    let state = 0 /* Empty */;
    while (parser.token !== 16 /* RightParen */) {
        if (parser.token === 14 /* Ellipsis */) {
            parser.flags |= 8 /* SimpleParameterList */;
            args.push(parseSpreadElement(parser, context));
            state = 2 /* HasSpread */;
        }
        else {
            token = parser.token;
            state = validateAsyncArgumentList(parser, context, state);
            args.push(restoreExpressionCoverGrammar(parser, context | 65536 /* AllowIn */, parseAssignmentExpression));
        }
        if (consume(parser, context, 16777234 /* Comma */)) {
            parser.flags &= ~4 /* AllowDestructuring */;
            if (state & 2 /* HasSpread */)
                state = 1 /* SeenSpread */;
        }
        if (parser.token === 16 /* RightParen */)
            break;
    }
    expect(parser, context, 16 /* RightParen */);
    if (parser.token === 10 /* Arrow */) {
        if (state & 1 /* SeenSpread */) {
            tolerant(parser, context, 76 /* ParamAfterRest */);
        }
        else if (state & 8 /* EvalOrArguments */) {
            if (context & 4096 /* Strict */)
                tolerant(parser, context, 45 /* StrictEvalArguments */);
            parser.flags |= 2048 /* StrictEvalArguments */;
        }
        else if (state & 16 /* Yield */) {
            if (context & 4096 /* Strict */)
                tolerant(parser, context, 49 /* YieldInParameter */);
            parser.flags |= 64 /* HasStrictReserved */;
        }
        else if (parser.flags & 16384 /* HasYield */) {
            tolerant(parser, context, 49 /* YieldInParameter */);
        }
        else if (state & 32 /* Await */ || parser.flags & 8192 /* HasAwait */) {
            tolerant(parser, context, 50 /* AwaitInParameter */);
        }
    }
    return args;
}
/**
 * Parse primary expression
 *
 * @see [Link](https://tc39.github.io/ecma262/#prod-PrimaryExpression)
 *
 * @param Parser Parser object
 * @param Context Context masks
 */
function parsePrimaryExpression(parser, context) {
    switch (parser.token) {
        case 33554434 /* NumericLiteral */:
        case 33554435 /* StringLiteral */:
            return parseLiteral(parser, context);
        case 33554551 /* BigIntLiteral */:
            return parseBigIntLiteral(parser, context);
        case 33619969 /* Identifier */:
            return parseIdentifier(parser, context);
        case 33566727 /* NullKeyword */:
        case 33566726 /* TrueKeyword */:
        case 33566725 /* FalseKeyword */:
            return parseNullOrTrueOrFalseLiteral(parser, context);
        case 33566808 /* FunctionKeyword */:
            return parseFunctionExpression(parser, context);
        case 33566815 /* ThisKeyword */:
            return parseThisExpression(parser, context);
        case 299116 /* AsyncKeyword */:
            return parseAsyncFunctionOrIdentifier(parser, context);
        case 50331659 /* LeftParen */:
            return parseCoverParenthesizedExpressionAndArrowParameterList(parser, context | 134217728 /* InParen */);
        case 41943059 /* LeftBracket */:
            return restoreExpressionCoverGrammar(parser, context, parseArrayLiteral);
        case 41943052 /* LeftBrace */:
            return restoreExpressionCoverGrammar(parser, context, parseObjectLiteral);
        case 115 /* Hash */:
            return parseIdentifierNameOrPrivateName(parser, context);
        case 120 /* At */:
        case 33566797 /* ClassKeyword */:
            return parseClassExpression(parser, context);
        case 33566811 /* NewKeyword */:
            return parseNewExpressionOrMetaProperty(parser, context);
        case 33566813 /* SuperKeyword */:
            return parseSuperProperty(parser, context);
        case 167774773 /* Divide */:
        case 100663333 /* DivideAssign */:
            scanRegularExpression(parser, context);
            return parseRegularExpressionLiteral(parser, context);
        case 33554441 /* TemplateTail */:
            return parseTemplateLiteral(parser, context);
        case 33554440 /* TemplateCont */:
            return parseTemplate(parser, context);
        case 33574984 /* LetKeyword */:
            return parseLetAsIdentifier(parser, context);
        default:
            return parseAndValidateIdentifier(parser, context);
    }
}
/**
 * Parse 'let' as identifier in 'sloppy mode', and throws
 * in 'strict mode'  / 'module code'. We also avoid a lookahead on the
 * ASI restictions while checking this after parsing out the 'let' keyword
 *
 * @param parser Parser object
 * @param context context mask
 */
function parseLetAsIdentifier(parser, context) {
    if (context & 4096 /* Strict */)
        tolerant(parser, context, 48 /* UnexpectedStrictReserved */);
    const pos = getLocation(parser);
    const name = parser.tokenValue;
    nextToken(parser, context);
    if (parser.flags & 1 /* NewLine */) {
        if (parser.token === 41943059 /* LeftBracket */)
            tolerant(parser, context, 1 /* UnexpectedToken */, 'let');
    }
    return finishNode(context, parser, pos, {
        type: 'Identifier',
        name,
    });
}
/**
 * Parse either async function expression or identifier
 *
 * @see [Link](https://tc39.github.io/ecma262/#prod-AsyncFunctionExpression)
 * @see [Link](https://tc39.github.io/ecma262/#prod-Identifier)
 *
 * @param parser Parser object
 * @param context  context mask
 */
function parseAsyncFunctionOrIdentifier(parser, context) {
    return lookahead(parser, context, nextTokenIsFuncKeywordOnSameLine) ?
        parseAsyncFunctionOrAsyncGeneratorExpression(parser, context) :
        parseIdentifier(parser, context);
}
/**
 * Parses identifier
 *
 * @see [Link](https://tc39.github.io/ecma262/#prod-Identifier)
 *
 * @param parser  Parser object
 * @param context Context masks
 */
function parseIdentifier(parser, context) {
    const pos = getLocation(parser);
    const name = parser.tokenValue;
    nextToken(parser, context | 16384 /* TaggedTemplate */);
    const node = finishNode(context, parser, pos, {
        type: 'Identifier',
        name,
    });
    if (context & 256 /* OptionsRawidentifiers */)
        node.raw = parser.tokenRaw;
    return node;
}
/**
 * Parse regular expression literal
 *
 * @see [Link](https://tc39.github.io/ecma262/#sec-literals-regular-expression-literals)
 *
 * @param parser Parser object
 * @param context Context masks
 */
function parseRegularExpressionLiteral(parser, context) {
    const pos = getLocation(parser);
    const { tokenRegExp, tokenValue, tokenRaw } = parser;
    nextToken(parser, context);
    const node = finishNode(context, parser, pos, {
        type: 'Literal',
        value: tokenValue,
        regex: tokenRegExp,
    });
    if (context & 8 /* OptionsRaw */)
        node.raw = tokenRaw;
    return node;
}
/**
 * Parses string and number literal
 *
 * @see [Link](https://tc39.github.io/ecma262/#prod-NumericLiteral)
 * @see [Link](https://tc39.github.io/ecma262/#prod-StringLiteral)
 *
 * @param parser  Parser object
 * @param context Context masks
 */
function parseLiteral(parser, context) {
    const pos = getLocation(parser);
    const value = parser.tokenValue;
    if (context & 4096 /* Strict */ && parser.flags & 128 /* HasOctal */) {
        tolerant(parser, context, 59 /* StrictOctalLiteral */);
    }
    nextToken(parser, context);
    const node = finishNode(context, parser, pos, {
        type: 'Literal',
        value,
    });
    if (context & 8 /* OptionsRaw */)
        node.raw = parser.tokenRaw;
    return node;
}
/**
 * Parses BigInt literal (stage 3 proposal)
 *
 * @see [Link](https://tc39.github.io/proposal-bigint/)
 *
 * @param parser  Parser object
 * @param context Context masks
 */
function parseBigIntLiteral(parser, context) {
    const pos = getLocation(parser);
    const { tokenValue, tokenRaw } = parser;
    nextToken(parser, context);
    const node = finishNode(context, parser, pos, {
        type: 'Literal',
        value: tokenValue,
        bigint: tokenRaw,
    });
    if (context & 8 /* OptionsRaw */)
        node.raw = parser.tokenRaw;
    return node;
}
/**
 * Parses either null or boolean literal
 *
 * @see [Link](https://tc39.github.io/ecma262/#prod-BooleanLiteral)
 *
 * @param parser  Parser object
 * @param context Context masks
 */
function parseNullOrTrueOrFalseLiteral(parser, context) {
    const pos = getLocation(parser);
    const { token } = parser;
    const raw = tokenDesc(token);
    if (parser.flags & 32768 /* EscapedKeyword */)
        tolerant(parser, context, 2 /* InvalidEscapedReservedWord */);
    nextToken(parser, context);
    const node = finishNode(context, parser, pos, {
        type: 'Literal',
        value: token === 33566727 /* NullKeyword */ ? null : raw === 'true',
    });
    if (context & 8 /* OptionsRaw */)
        node.raw = raw;
    return node;
}
/**
 * Parse this expression
 *
 * @param parser Parser object
 * @param context Context masks
 */
function parseThisExpression(parser, context) {
    if (parser.flags & 32768 /* EscapedKeyword */)
        tolerant(parser, context, 2 /* InvalidEscapedReservedWord */);
    const pos = getLocation(parser);
    nextToken(parser, context | 536870912 /* DisallowEscapedKeyword */);
    return finishNode(context, parser, pos, {
        type: 'ThisExpression',
    });
}
/**
 * Parse identifier name
 *
 * @see [Link](https://tc39.github.io/ecma262/#prod-IdentifierName)
 *
 * @param parser Parser object
 * @param context Context masks
 * @param t token
 */
function parseIdentifierName(parser, context, t) {
    if (!(t & (65536 /* IsIdentifier */ | 4096 /* Keyword */)))
        tolerant(parser, context, 3 /* UnexpectedKeyword */, tokenDesc(t));
    return parseIdentifier(parser, context);
}
/**
 * Parse identifier name or private name (stage 3 proposal)
 *
 * @see [Link](https://tc39.github.io/ecma262/#prod-StatementList)
 *
 * @param parser Parser object
 * @param context Context masks
 */
function parseIdentifierNameOrPrivateName(parser, context) {
    if (!consume(parser, context, 115 /* Hash */))
        return parseIdentifierName(parser, context, parser.token);
    const { tokenValue } = parser;
    const pos = getLocation(parser);
    const name = tokenValue;
    nextToken(parser, context);
    return finishNode(context, parser, pos, {
        type: 'PrivateName',
        name,
    });
}
/**
 * Parse array literal
 *
 * ArrayLiteral :
 *   [ Elisionopt ]
 *   [ ElementList ]
 *   [ ElementList , Elisionopt ]
 *
 * ElementList :
 *   Elisionopt AssignmentExpression
 *   Elisionopt ... AssignmentExpression
 *   ElementList , Elisionopt AssignmentExpression
 *   ElementList , Elisionopt SpreadElement
 *
 * Elision :
 *   ,
 *   Elision ,
 *
 * SpreadElement :
 *   ... AssignmentExpression
 *
 *
 * @see [Link](https://tc39.github.io/ecma262/#prod-ArrayLiteral)
 *
 * @param parser  Parser object
 * @param context Context masks
 */
function parseArrayLiteral(parser, context) {
    const pos = getLocation(parser);
    expect(parser, context, 41943059 /* LeftBracket */);
    const elements = [];
    while (parser.token !== 20 /* RightBracket */) {
        if (consume(parser, context, 16777234 /* Comma */)) {
            elements.push(null);
        }
        else if (parser.token === 14 /* Ellipsis */) {
            elements.push(parseSpreadElement(parser, context));
            if (parser.token !== 20 /* RightBracket */) {
                parser.flags &= ~(4 /* AllowDestructuring */ | 2 /* AllowBinding */);
                expect(parser, context, 16777234 /* Comma */);
            }
        }
        else {
            elements.push(restoreExpressionCoverGrammar(parser, context | 65536 /* AllowIn */, parseAssignmentExpression));
            if (parser.token !== 20 /* RightBracket */)
                expect(parser, context, 16777234 /* Comma */);
        }
    }
    expect(parser, context, 20 /* RightBracket */);
    return finishNode(context, parser, pos, {
        type: 'ArrayExpression',
        elements,
    });
}
/**
 * Parses cover parenthesized expression and arrow parameter list
 *
 * @see [Link](https://tc39.github.io/ecma262/#prod-parseCoverParenthesizedExpressionAndArrowParameterList)
 *
 * @param parser  Parser object
 * @param context Context masks
 */
function parseCoverParenthesizedExpressionAndArrowParameterList(parser, context) {
    expect(parser, context, 50331659 /* LeftParen */);
    switch (parser.token) {
        // ')'
        case 16 /* RightParen */:
            {
                expect(parser, context, 16 /* RightParen */);
                parser.flags &= ~(4 /* AllowDestructuring */ | 2 /* AllowBinding */);
                if (parser.token === 10 /* Arrow */)
                    return [];
            }
        // '...'
        case 14 /* Ellipsis */:
            {
                const expr = parseRestElement(parser, context);
                expect(parser, context, 16 /* RightParen */);
                parser.flags = parser.flags & ~(4 /* AllowDestructuring */ | 2 /* AllowBinding */) | 8 /* SimpleParameterList */;
                if (parser.token !== 10 /* Arrow */)
                    tolerant(parser, context, 1 /* UnexpectedToken */, tokenDesc(parser.token));
                return [expr];
            }
        default:
            {
                let state = 0 /* None */;
                // Record the sequence position
                const sequencepos = getLocation(parser);
                state = validateCoverParenthesizedExpression(parser, state);
                if (parser.token & 8388608 /* IsBindingPattern */)
                    state |= 16 /* HasBinding */;
                let expr = restoreExpressionCoverGrammar(parser, context | 65536 /* AllowIn */, parseAssignmentExpression);
                // Sequence expression
                if (parser.token === 16777234 /* Comma */) {
                    state |= 1 /* SequenceExpression */;
                    const expressions = [expr];
                    while (consume(parser, context | 536870912 /* DisallowEscapedKeyword */, 16777234 /* Comma */)) {
                        parser.flags &= ~4 /* AllowDestructuring */;
                        switch (parser.token) {
                            // '...'
                            case 14 /* Ellipsis */:
                                {
                                    if (!(parser.flags & 2 /* AllowBinding */))
                                        tolerant(parser, context, 75 /* NotBindable */);
                                    parser.flags |= 8 /* SimpleParameterList */;
                                    const restElement = parseRestElement(parser, context);
                                    expect(parser, context, 16 /* RightParen */);
                                    if (parser.token !== 10 /* Arrow */)
                                        tolerant(parser, context, 76 /* ParamAfterRest */);
                                    parser.flags &= ~2 /* AllowBinding */;
                                    expressions.push(restElement);
                                    return expressions;
                                }
                            // ')'
                            case 16 /* RightParen */:
                                {
                                    expect(parser, context, 16 /* RightParen */);
                                    if (parser.token !== 10 /* Arrow */)
                                        tolerant(parser, context, 1 /* UnexpectedToken */, tokenDesc(parser.token));
                                    return expressions;
                                }
                            default:
                                {
                                    state = validateCoverParenthesizedExpression(parser, state);
                                    expressions.push(restoreExpressionCoverGrammar(parser, context, parseAssignmentExpression));
                                }
                        }
                    }
                    expr = finishNode(context, parser, sequencepos, {
                        type: 'SequenceExpression',
                        expressions,
                    });
                }
                expect(parser, context, 16 /* RightParen */);
                if (parser.token === 10 /* Arrow */) {
                    if (state & 2 /* HasEvalOrArguments */) {
                        if (context & 4096 /* Strict */)
                            tolerant(parser, context, 45 /* StrictEvalArguments */);
                        parser.flags |= 2048 /* StrictEvalArguments */;
                    }
                    else if (state & 4 /* HasReservedWords */) {
                        if (context & 4096 /* Strict */)
                            tolerant(parser, context, 48 /* UnexpectedStrictReserved */);
                        parser.flags |= 64 /* HasStrictReserved */;
                    }
                    else if (!(parser.flags & 2 /* AllowBinding */)) {
                        tolerant(parser, context, 75 /* NotBindable */);
                    }
                    else if (parser.flags & 16384 /* HasYield */) {
                        tolerant(parser, context, 49 /* YieldInParameter */);
                    }
                    else if (context & 131072 /* Async */ && parser.flags & 8192 /* HasAwait */) {
                        tolerant(parser, context, 50 /* AwaitInParameter */);
                    }
                    parser.flags &= ~(2 /* AllowBinding */ | 8192 /* HasAwait */ | 16384 /* HasYield */);
                    return (state & 1 /* SequenceExpression */ ? expr.expressions : [expr]);
                }
                parser.flags &= ~(8192 /* HasAwait */ | 16384 /* HasYield */ | 2 /* AllowBinding */);
                if (!isValidSimpleAssignmentTarget(expr))
                    parser.flags &= ~4 /* AllowDestructuring */;
                return expr;
            }
    }
}
/**
 * Parses function expression
 *
 * @see [Link](https://tc39.github.io/ecma262/#prod-FunctionExpression)
 *
 * @param parser  Parser object
 * @param context Context masks
 */
function parseFunctionExpression(parser, context) {
    const pos = getLocation(parser);
    expect(parser, context, 33566808 /* FunctionKeyword */);
    const isGenerator = consume(parser, context, 167774771 /* Multiply */) ? 1 /* Generator */ : 0 /* None */;
    let id = null;
    const { token } = parser;
    if (token & (65536 /* IsIdentifier */ | 4096 /* Keyword */)) {
        if (token & 4194304 /* IsEvalOrArguments */) {
            if (context & 4096 /* Strict */)
                tolerant(parser, context, 45 /* StrictEvalArguments */);
            parser.flags |= 2048 /* StrictEvalArguments */;
        }
        if (parser.token & 1073741824 /* IsYield */ && isGenerator & 1 /* Generator */) {
            tolerant(parser, context, 47 /* YieldBindingIdentifier */);
        }
        id = parseBindingIdentifier(parser, context);
    }
    const { params, body } = swapContext(parser, context & ~(33554432 /* Method */ | 67108864 /* AllowSuperProperty */), isGenerator, parseFormalListAndBody);
    return finishNode(context, parser, pos, {
        type: 'FunctionExpression',
        params,
        body,
        async: false,
        generator: !!(isGenerator & 1 /* Generator */),
        expression: false,
        id,
    });
}
/**
 * Parses async function or async generator expression
 *
 * @see [Link](https://tc39.github.io/ecma262/#prod-AsyncFunctionExpression)
 *
 * @param parser  Parser object
 * @param context Context masks
 */
function parseAsyncFunctionOrAsyncGeneratorExpression(parser, context) {
    const pos = getLocation(parser);
    expect(parser, context, 299116 /* AsyncKeyword */);
    expect(parser, context, 33566808 /* FunctionKeyword */);
    const isGenerator = consume(parser, context, 167774771 /* Multiply */) ? 1 /* Generator */ : 0 /* None */;
    const isAwait = 2 /* Await */;
    let id = null;
    const { token } = parser;
    if (token & (65536 /* IsIdentifier */ | 4096 /* Keyword */)) {
        if (token & 4194304 /* IsEvalOrArguments */) {
            if (context & 4096 /* Strict */ || isAwait & 2 /* Await */)
                tolerant(parser, context, 45 /* StrictEvalArguments */);
            parser.flags |= 1024 /* StrictFunctionName */;
        }
        if (token & 131072 /* IsAwait */)
            tolerant(parser, context, 46 /* AwaitBindingIdentifier */);
        if (parser.token & 1073741824 /* IsYield */ && isGenerator & 1 /* Generator */)
            tolerant(parser, context, 47 /* YieldBindingIdentifier */);
        id = parseBindingIdentifier(parser, context);
    }
    const { params, body } = swapContext(parser, context & ~(33554432 /* Method */ | 67108864 /* AllowSuperProperty */), isGenerator | isAwait, parseFormalListAndBody);
    return finishNode(context, parser, pos, {
        type: 'FunctionExpression',
        params,
        body,
        async: true,
        generator: !!(isGenerator & 1 /* Generator */),
        expression: false,
        id,
    });
}
/**
 * Parse computed property names
 *
 * @see [Link](https://tc39.github.io/ecma262/#prod-ComputedPropertyName)
 *
 * @param parser Parser object
 * @param context Context masks
 */
function parseComputedPropertyName(parser, context) {
    expect(parser, context, 41943059 /* LeftBracket */);
    const key = parseAssignmentExpression(parser, context | 65536 /* AllowIn */);
    expect(parser, context, 20 /* RightBracket */);
    return key;
}
/**
 * Parse property name
 *
 * @see [Link](https://tc39.github.io/ecma262/#prod-PropertyName)
 *
 * @param parser Parser object
 * @param context Context masks
 */
function parsePropertyName(parser, context) {
    switch (parser.token) {
        case 33554434 /* NumericLiteral */:
        case 33554435 /* StringLiteral */:
            return parseLiteral(parser, context);
        case 41943059 /* LeftBracket */:
            return parseComputedPropertyName(parser, context);
        default:
            return parseIdentifier(parser, context);
    }
}
/**
 * Parse object spread properties
 *
 * @see [Link](https://tc39.github.io/proposal-object-rest-spread/#Spread)
 *
 * @param parser Parser object
 * @param context Context masks
 */
function parseSpreadProperties(parser, context) {
    const pos = getLocation(parser);
    expect(parser, context, 14 /* Ellipsis */);
    if (parser.token & 8388608 /* IsBindingPattern */)
        parser.flags &= ~4 /* AllowDestructuring */;
    const argument = parseAssignmentExpression(parser, context | 65536 /* AllowIn */);
    return finishNode(context, parser, pos, {
        type: 'SpreadElement',
        argument,
    });
}
/**
 * Parses object literal
 *
 * @see [Link](https://tc39.github.io/ecma262/#prod-ObjectLiteral)
 *
 * @param parser Parser object
 * @param context Context masks
 */
function parseObjectLiteral(parser, context) {
    const pos = getLocation(parser);
    expect(parser, context, 41943052 /* LeftBrace */);
    const properties = [];
    while (parser.token !== 17301519 /* RightBrace */) {
        properties.push(parser.token === 14 /* Ellipsis */ ?
            parseSpreadProperties(parser, context) :
            parsePropertyDefinition(parser, context));
        if (parser.token !== 17301519 /* RightBrace */)
            expect(parser, context, 16777234 /* Comma */);
    }
    expect(parser, context, 17301519 /* RightBrace */);
    parser.flags &= ~512 /* HasProtoField */;
    return finishNode(context, parser, pos, {
        type: 'ObjectExpression',
        properties,
    });
}
/**
 * Parse property definition
 *
 * @see [Link](https://tc39.github.io/ecma262/#prod-PropertyDefinition)
 *
 * @param parser Parser object
 * @param context Context masks
 */
function parsePropertyDefinition(parser, context) {
    const pos = getLocation(parser);
    const flags = parser.flags;
    let value;
    let state = consume(parser, context, 167774771 /* Multiply */) ? 2 /* Generator */ | 32 /* Method */ : 32 /* Method */;
    const t = parser.token;
    let key = parsePropertyName(parser, context);
    if (!(parser.token & 16777216 /* IsShorthandProperty */)) {
        if (flags & 32768 /* EscapedKeyword */) {
            tolerant(parser, context, 2 /* InvalidEscapedReservedWord */);
        }
        else if (!(state & 2 /* Generator */) && t & 262144 /* IsAsync */ && !(parser.flags & 1 /* NewLine */)) {
            state |= consume(parser, context, 167774771 /* Multiply */) ? 2 /* Generator */ | 1 /* Async */ : 1 /* Async */;
            key = parsePropertyName(parser, context);
        }
        else if (t === 36975 /* GetKeyword */) {
            state = state & ~32 /* Method */ | 4 /* Getter */;
            key = parsePropertyName(parser, context);
        }
        else if (t === 36976 /* SetKeyword */) {
            state = state & ~32 /* Method */ | 8 /* Setter */;
            key = parsePropertyName(parser, context);
        }
        if (state & (4 /* Getter */ | 8 /* Setter */)) {
            if (state & 2 /* Generator */)
                tolerant(parser, context, 1 /* UnexpectedToken */, tokenDesc(parser.token));
        }
    }
    if (parser.token === 50331659 /* LeftParen */) {
        value = parseMethodDeclaration(parser, context, state);
    }
    else {
        state &= ~32 /* Method */;
        if (parser.token === 16777237 /* Colon */) {
            if ((state & (1 /* Async */ | 2 /* Generator */))) {
                tolerant(parser, context, 1 /* UnexpectedToken */, tokenDesc(parser.token));
            }
            else if (t !== 41943059 /* LeftBracket */ && parser.tokenValue === '__proto__') {
                if (parser.flags & 512 /* HasProtoField */) {
                    // Record the error and put it on hold until we've determined
                    // whether or not we're destructuring
                    setPendingExpressionError(parser, 61 /* DuplicateProto */);
                }
                else
                    parser.flags |= 512 /* HasProtoField */;
            }
            expect(parser, context, 16777237 /* Colon */);
            // Invalid: 'async ({a: await}) => 1'
            if (parser.token & 131072 /* IsAwait */)
                parser.flags |= 8192 /* HasAwait */;
            value = restoreExpressionCoverGrammar(parser, context, parseAssignmentExpression);
        }
        else {
            if ((state & (2 /* Generator */ | 1 /* Async */)) || !isValidIdentifier(context, t)) {
                tolerant(parser, context, 1 /* UnexpectedToken */, tokenDesc(t));
            }
            else if (context & (4096 /* Strict */ | 262144 /* Yield */) && t & 1073741824 /* IsYield */) {
                setPendingError(parser);
                parser.flags |= 16384 /* HasYield */;
            }
            state |= 64 /* Shorthand */;
            if (parser.token === 83886109 /* Assign */) {
                setPendingExpressionError(parser, 89 /* InvalidCoverInitializedName */);
                expect(parser, context, 83886109 /* Assign */);
                if (context & (4096 /* Strict */ | 262144 /* Yield */ | 131072 /* Async */) && parser.token & (1073741824 /* IsYield */ | 131072 /* IsAwait */)) {
                    setPendingError(parser);
                    parser.flags |= parser.token & 1073741824 /* IsYield */ ? 16384 /* HasYield */ : 8192 /* HasAwait */;
                }
                value = parseAssignmentPattern(parser, context, key, pos);
            }
            else {
                if (t & 131072 /* IsAwait */) {
                    if (context & 131072 /* Async */)
                        tolerant(parser, context, 44 /* UnexpectedReserved */);
                    setPendingError(parser);
                    parser.flags |= 8192 /* HasAwait */;
                }
                value = key;
            }
        }
    }
    return finishNode(context, parser, pos, {
        type: 'Property',
        key,
        value,
        kind: !(state & 4 /* Getter */ | state & 8 /* Setter */) ? 'init' : (state & 8 /* Setter */) ? 'set' : 'get',
        computed: t === 41943059 /* LeftBracket */,
        method: !!(state & 32 /* Method */),
        shorthand: !!(state & 64 /* Shorthand */),
    });
}
/**
 * Parse statement list
 *
 * @see [Link](https://tc39.github.io/ecma262/#prod-StatementList)
 *
 * @param parser Parser object
 * @param context Context masks
 */
function parseMethodDeclaration(parser, context, state) {
    const pos = getLocation(parser);
    const isGenerator = state & 2 /* Generator */ ? 1 /* Generator */ : 0 /* None */;
    const isAsync = state & 1 /* Async */ ? 2 /* Await */ : 0 /* None */;
    const { params, body } = swapContext(parser, context | 33554432 /* Method */, isGenerator | isAsync, parseFormalListAndBody, state);
    return finishNode(context, parser, pos, {
        type: 'FunctionExpression',
        params,
        body,
        async: !!(state & 1 /* Async */),
        generator: !!(state & 2 /* Generator */),
        expression: false,
        id: null,
    });
}
/**
 * Parse arrow function
 *
 * @see [Link](https://tc39.github.io/ecma262/#prod-ArrowFunction)
 *
 * @param parser Parser object
 * @param context Context masks
 */
function parseArrowFunction(parser, context, pos, params) {
    parser.flags &= ~(4 /* AllowDestructuring */ | 2 /* AllowBinding */);
    if (parser.flags & 1 /* NewLine */)
        tolerant(parser, context, 34 /* InvalidLineBreak */, '=>');
    expect(parser, context, 10 /* Arrow */);
    return parseArrowBody(parser, context & ~131072 /* Async */, params, pos, 0 /* None */);
}
/**
 * Parse async arrow function
 *
 * @see [Link](https://tc39.github.io/ecma262/#prod-AsyncArrowFunction)
 *
 * @param parser Parser object
 * @param context Context masks
 */
function parseAsyncArrowFunction(parser, context, state, pos, params) {
    parser.flags &= ~(4 /* AllowDestructuring */ | 2 /* AllowBinding */);
    if (parser.flags & 1 /* NewLine */)
        tolerant(parser, context, 34 /* InvalidLineBreak */, 'async');
    expect(parser, context, 10 /* Arrow */);
    return parseArrowBody(parser, context | 131072 /* Async */, params, pos, state);
}
/**
 * Shared helper function for both async arrow and arrows
 *
 * @see [Link](https://tc39.github.io/ecma262/#prod-ArrowFunction)
 * @see [Link](https://tc39.github.io/ecma262/#prod-AsyncArrowFunction)
 *
 * @param parser Parser object
 * @param context Context masks
 */
// https://tc39.github.io/ecma262/#prod-AsyncArrowFunction
function parseArrowBody(parser, context, params, pos, state) {
    parser.pendingExpressionError = null;
    for (const i in params)
        reinterpret(parser, context | 524288 /* InParameter */, params[i]);
    const expression = parser.token !== 41943052 /* LeftBrace */;
    const body = expression ? parseExpressionCoverGrammar(parser, context & ~(262144 /* Yield */ | 524288 /* InParameter */), parseAssignmentExpression) :
        swapContext(parser, context & ~(262144 /* Yield */ | 1073741824 /* AllowDecorator */) | 1048576 /* InFunctionBody */, state, parseFunctionBody);
    return finishNode(context, parser, pos, {
        type: 'ArrowFunctionExpression',
        body,
        params,
        id: null,
        async: !!(state & 2 /* Await */),
        generator: false,
        expression,
    });
}
/**
 * Parses formal parameters and function body.
 *
 * @see [Link](https://tc39.github.io/ecma262/#prod-FunctionBody)
 * @see [Link](https://tc39.github.io/ecma262/#prod-FormalParameters)
 *
 * @param parser Parser object
 * @param context Context masks
 */
function parseFormalListAndBody(parser, context, state) {
    const paramList = parseFormalParameters(parser, context | 524288 /* InParameter */, state);
    const args = paramList.args;
    const params = paramList.params;
    const body = parseFunctionBody(parser, context & ~1073741824 /* AllowDecorator */ | 1048576 /* InFunctionBody */, args);
    return { params, body };
}
/**
 * Parse funciton body
 *
 * @see [Link](https://tc39.github.io/ecma262/#prod-FunctionBody)
 *
 * @param parser Parser object
 * @param context Context masks
 */
function parseFunctionBody(parser, context, params) {
    // Note! The 'params' has an 'any' type now because it's really shouldn't be there. This should have been
    // on the parser object instead. So for now the 'params' arg are only used within the
    // 'parseFormalListAndBody' method, and not within the arrow function body.
    const pos = getLocation(parser);
    expect(parser, context | 536870912 /* DisallowEscapedKeyword */, 41943052 /* LeftBrace */);
    const body = [];
    while (parser.token === 33554435 /* StringLiteral */) {
        const { tokenRaw, tokenValue } = parser;
        body.push(parseDirective(parser, context));
        if (tokenRaw.length === /* length of prologue*/ 12 && tokenValue === 'use strict') {
            if (parser.flags & 8 /* SimpleParameterList */) {
                tolerant(parser, context, 62 /* IllegalUseStrict */);
            }
            else if (parser.flags & (64 /* HasStrictReserved */ | 1024 /* StrictFunctionName */)) {
                tolerant(parser, context, 48 /* UnexpectedStrictReserved */);
            }
            else if (parser.flags & 2048 /* StrictEvalArguments */) {
                tolerant(parser, context, 45 /* StrictEvalArguments */);
            }
            context |= 4096 /* Strict */;
        }
    }
    if (context & 4096 /* Strict */) {
        validateParams(parser, context, params);
    }
    const { labelSet } = parser;
    parser.labelSet = {};
    const savedFlags = parser.flags;
    parser.flags = parser.flags & ~(1024 /* StrictFunctionName */ | 2048 /* StrictEvalArguments */ | 16 /* InSwitchStatement */ | 32 /* InIterationStatement */) | 4 /* AllowDestructuring */;
    while (parser.token !== 17301519 /* RightBrace */) {
        body.push(parseStatementListItem(parser, context));
    }
    if (savedFlags & 32 /* InIterationStatement */)
        parser.flags |= 32 /* InIterationStatement */;
    if (savedFlags & 16 /* InSwitchStatement */)
        parser.flags |= 16 /* InSwitchStatement */;
    parser.labelSet = labelSet;
    expect(parser, context, 17301519 /* RightBrace */);
    return finishNode(context, parser, pos, {
        type: 'BlockStatement',
        body,
    });
}
/**
 * Parse formal parameters
 *
 * @see [Link](https://tc39.github.io/ecma262/#prod-FormalParameters)
 *
 * @param Parser object
 * @param Context masks
 * @param Optional objectstate. Default to none
 */
function parseFormalParameters(parser, context, state) {
    // FormalParameterList :
    //   [empty]
    //   FunctionRestParameter
    //   FormalsList
    //   FormalsList , FunctionRestParameter
    //
    // FunctionRestParameter :
    //   ... BindingIdentifier
    //
    // FormalsList :
    //   FormalParameter
    //   FormalsList , FormalParameter
    //
    // FormalParameter :
    //   BindingElement
    //
    // BindingElement :
    //   SingleNameBinding
    //   BindingPattern Initializeropt
    expect(parser, context, 50331659 /* LeftParen */);
    parser.flags &= ~(8 /* SimpleParameterList */ | 64 /* HasStrictReserved */);
    const args = [];
    const params = [];
    while (parser.token !== 16 /* RightParen */) {
        if (parser.token === 14 /* Ellipsis */) {
            if (state & 8 /* Setter */)
                tolerant(parser, context, 65 /* BadSetterRestParameter */);
            parser.flags |= 8 /* SimpleParameterList */;
            params.push(parseRestElement(parser, context, args));
            break;
        }
        params.push(parseFormalParameterList(parser, context, args));
        if (!consume(parser, context, 16777234 /* Comma */))
            break;
        if (parser.token === 16 /* RightParen */)
            break;
    }
    if (state & 8 /* Setter */ && params.length !== 1) {
        tolerant(parser, context, 64 /* AccessorWrongArgs */, 'Setter', 'one', '');
    }
    if (state & 4 /* Getter */ && params.length > 0) {
        tolerant(parser, context, 64 /* AccessorWrongArgs */, 'Getter', 'no', 's');
    }
    expect(parser, context, 16 /* RightParen */);
    return { params, args };
}
/**
 * Parse formal parameter list
 *
 * @see [Link](https://tc39.github.io/ecma262/#prod-FormalParameterList)
 *
 * @param parser Parser object
 * @param context Context masks
 */
function parseFormalParameterList(parser, context, args) {
    const pos = getLocation(parser);
    if (parser.token & (65536 /* IsIdentifier */ | 4096 /* Keyword */)) {
        if (hasBit(parser.token, 20480 /* FutureReserved */)) {
            if (context & 4096 /* Strict */)
                tolerant(parser, context, 48 /* UnexpectedStrictReserved */);
            parser.flags |= 1024 /* StrictFunctionName */;
        }
        if (hasBit(parser.token, 4194304 /* IsEvalOrArguments */)) {
            if (context & 4096 /* Strict */)
                tolerant(parser, context, 45 /* StrictEvalArguments */);
            parser.flags |= 2048 /* StrictEvalArguments */;
        }
    }
    else {
        parser.flags |= 8 /* SimpleParameterList */;
    }
    const left = parseBindingIdentifierOrPattern(parser, context, args);
    if (!consume(parser, context, 83886109 /* Assign */))
        return left;
    if (parser.token & (1073741824 /* IsYield */ | 131072 /* IsAwait */) && context & (262144 /* Yield */ | 131072 /* Async */)) {
        tolerant(parser, context, parser.token & 131072 /* IsAwait */ ? 50 /* AwaitInParameter */ : 49 /* YieldInParameter */);
    }
    parser.flags |= 8 /* SimpleParameterList */;
    return finishNode(context, parser, pos, {
        type: 'AssignmentPattern',
        left,
        right: parseExpressionCoverGrammar(parser, context, parseAssignmentExpression),
    });
}
/**
 * Parse class expression
 *
 * @see [Link](https://tc39.github.io/ecma262/#prod-ClassExpression)
 *
 * @param parser Parser object
 * @param context Context masks
 */
function parseClassExpression(parser, context) {
    const pos = getLocation(parser);
    let decorators = [];
    if (context & 2048 /* OptionsExperimental */)
        decorators = parseDecorators(parser, context);
    expect(parser, context | 536870912 /* DisallowEscapedKeyword */, 33566797 /* ClassKeyword */);
    const { token } = parser;
    let state = 0 /* None */;
    let id = null;
    let superClass = null;
    if ((token !== 41943052 /* LeftBrace */ && token !== 12372 /* ExtendsKeyword */)) {
        if (context & 131072 /* Async */ && token & 131072 /* IsAwait */) {
            tolerant(parser, context, 46 /* AwaitBindingIdentifier */);
        }
        id = parseBindingIdentifier(parser, context | 4096 /* Strict */);
    }
    if (consume(parser, context, 12372 /* ExtendsKeyword */)) {
        superClass = parseLeftHandSideExpression(parser, context | 4096 /* Strict */, pos);
        state |= 512 /* Heritage */;
    }
    const body = parseClassBodyAndElementList(parser, context | 4096 /* Strict */, state);
    return finishNode(context, parser, pos, context & 2048 /* OptionsExperimental */ ? {
        type: 'ClassExpression',
        id,
        superClass,
        body,
        decorators
    } : {
        type: 'ClassExpression',
        id,
        superClass,
        body,
    });
}
/**
 * Parse class body and element list
 *
 * @see [Link](https://tc39.github.io/ecma262/#prod-ClassBody)
 * @see [Link](https://tc39.github.io/ecma262/#prod-ClassElementList)
 *
 *
 * @param parser Parser object
 * @param context Context masks
 */
function parseClassBodyAndElementList(parser, context, state) {
    const pos = getLocation(parser);
    expect(parser, context, 41943052 /* LeftBrace */);
    const body = [];
    let decorators = [];
    while (parser.token !== 17301519 /* RightBrace */) {
        if (!consume(parser, context, 17301521 /* Semicolon */)) {
            if (context & 2048 /* OptionsExperimental */) {
                decorators = parseDecorators(parser, context);
                if (parser.token === 17301519 /* RightBrace */)
                    report(parser, 90 /* TrailingDecorators */);
                if (decorators.length !== 0 && parser.tokenValue === 'constructor') {
                    report(parser, 91 /* GeneratorConstructor */);
                }
            }
            body.push(context & 1 /* OptionsNext */ && parser.token === 115 /* Hash */
                ? parsePrivateFields(parser, context, decorators)
                : parseClassElement(parser, context, state, decorators));
        }
    }
    expect(parser, context, 17301519 /* RightBrace */);
    return finishNode(context, parser, pos, {
        type: 'ClassBody',
        body,
    });
}
/**
 * Parse class element and class public instance fields & private instance fields
 *
 * @see [Link](https://tc39.github.io/ecma262/#prod-ClassElement)
 * @see [Link](https://tc39.github.io/proposal-class-public-fields/)
 *
 * @param parser Parser object
 * @param context Context masks
 */
function parseClassElement(parser, context, state, decorators) {
    const pos = getLocation(parser);
    let { tokenValue, token } = parser;
    const flags = parser.flags;
    if (consume(parser, context, 167774771 /* Multiply */)) {
        state |= 2 /* Generator */;
    }
    if (parser.token === 41943059 /* LeftBracket */)
        state |= 16 /* Computed */;
    if (parser.tokenValue === 'constructor') {
        if (state & 2 /* Generator */)
            tolerant(parser, context, 43 /* InvalidConstructor */, 'generator');
        else if (state & 512 /* Heritage */)
            context |= 67108864 /* AllowSuperProperty */;
        state |= 256 /* Constructor */;
    }
    let key = parsePropertyName(parser, context);
    let value;
    if (!(parser.token & 16777216 /* IsShorthandProperty */)) {
        if (flags & 32768 /* EscapedKeyword */)
            tolerant(parser, context, 2 /* InvalidEscapedReservedWord */);
        if (token === 20585 /* StaticKeyword */) {
            token = parser.token;
            if (consume(parser, context, 167774771 /* Multiply */))
                state |= 2 /* Generator */;
            tokenValue = parser.tokenValue;
            if (parser.token === 41943059 /* LeftBracket */)
                state |= 16 /* Computed */;
            if (parser.tokenValue === 'prototype')
                tolerant(parser, context, 63 /* StaticPrototype */);
            state |= 128 /* Static */;
            key = parsePropertyName(parser, context);
            if (context & 1 /* OptionsNext */ && isInstanceField(parser)) {
                if (tokenValue === 'constructor')
                    tolerant(parser, context, 1 /* UnexpectedToken */, tokenDesc(parser.token));
                return parseFieldDefinition(parser, context, key, state, pos, decorators);
            }
        }
        if (parser.token !== 50331659 /* LeftParen */) {
            if (token & 262144 /* IsAsync */ && !(state & 2 /* Generator */) && !(parser.flags & 1 /* NewLine */)) {
                token = parser.token;
                tokenValue = parser.tokenValue;
                state |= 1 /* Async */;
                if (consume(parser, context, 167774771 /* Multiply */))
                    state |= 2 /* Generator */;
                if (parser.token === 41943059 /* LeftBracket */)
                    state |= 16 /* Computed */;
                key = parsePropertyName(parser, context);
            }
            else if ((token === 36975 /* GetKeyword */ || token === 36976 /* SetKeyword */)) {
                state |= token === 36975 /* GetKeyword */ ? 4 /* Getter */ : 8 /* Setter */;
                tokenValue = parser.tokenValue;
                if (parser.token === 41943059 /* LeftBracket */)
                    state |= 16 /* Computed */;
                key = parsePropertyName(parser, context);
            }
            if (tokenValue === 'prototype') {
                tolerant(parser, context, 63 /* StaticPrototype */);
            }
            else if (!(state & 128 /* Static */) && tokenValue === 'constructor') {
                tolerant(parser, context, 43 /* InvalidConstructor */, 'accessor');
            }
        }
    }
    if (parser.token === 50331659 /* LeftParen */) {
        value = parseMethodDeclaration(parser, context, state);
    }
    else {
        if (context & 1 /* OptionsNext */)
            return parseFieldDefinition(parser, context, key, state, pos, decorators);
        tolerant(parser, context, 1 /* UnexpectedToken */, tokenDesc(token));
    }
    const kind = (state & 256 /* Constructor */) ? 'constructor' : (state & 4 /* Getter */) ? 'get' :
        (state & 8 /* Setter */) ? 'set' : 'method';
    return finishNode(context, parser, pos, context & 2048 /* OptionsExperimental */ ? {
        type: 'MethodDefinition',
        kind,
        static: !!(state & 128 /* Static */),
        computed: !!(state & 16 /* Computed */),
        key,
        value,
        decorators
    } : {
        type: 'MethodDefinition',
        kind,
        static: !!(state & 128 /* Static */),
        computed: !!(state & 16 /* Computed */),
        key,
        value,
    });
}
/**
 * Parses field definition.
 *
 * @param parser Parser object
 * @param context Context masks
 */
function parseFieldDefinition(parser, context, key, state, pos, decorators) {
    if (state & 256 /* Constructor */)
        tolerant(parser, context, 0 /* Unexpected */);
    let value = null;
    if (state & (1 /* Async */ | 2 /* Generator */))
        tolerant(parser, context, 0 /* Unexpected */);
    if (consume(parser, context, 83886109 /* Assign */)) {
        if (parser.token & 4194304 /* IsEvalOrArguments */)
            tolerant(parser, context, 45 /* StrictEvalArguments */);
        value = parseAssignmentExpression(parser, context);
    }
    consume(parser, context, 16777234 /* Comma */);
    return finishNode(context, parser, pos, context & 2048 /* OptionsExperimental */ ? {
        type: 'FieldDefinition',
        key,
        value,
        computed: !!(state & 16 /* Computed */),
        static: !!(state & 128 /* Static */),
        decorators
    } : {
        type: 'FieldDefinition',
        key,
        value,
        computed: !!(state & 16 /* Computed */),
        static: !!(state & 128 /* Static */),
    });
}
/**
 * Parse private name
 *
 * @param parser Parser object
 * @param context Context masks
 */
function parsePrivateName(parser, context, pos) {
    const name = parser.tokenValue;
    nextToken(parser, context);
    return finishNode(context, parser, pos, {
        type: 'PrivateName',
        name,
    });
}
/**
 * Parses private instance fields
 *
 * @see [Link](https://tc39.github.io/proposal-class-public-fields/)
 *
 * @param parser Parser object
 * @param context Context masks
 */
function parsePrivateFields(parser, context, decorators) {
    const pos = getLocation(parser);
    expect(parser, context | 32768 /* InClass */, 115 /* Hash */);
    if (parser.tokenValue === 'constructor')
        tolerant(parser, context, 39 /* PrivateFieldConstructor */);
    const key = parsePrivateName(parser, context, pos);
    if (parser.token === 50331659 /* LeftParen */)
        return parsePrivateMethod(parser, context, key, pos, decorators);
    let value = null;
    if (consume(parser, context, 83886109 /* Assign */)) {
        if (parser.token & 4194304 /* IsEvalOrArguments */)
            tolerant(parser, context, 45 /* StrictEvalArguments */);
        value = parseAssignmentExpression(parser, context);
    }
    consume(parser, context, 16777234 /* Comma */);
    return finishNode(context, parser, pos, context & 2048 /* OptionsExperimental */ ? {
        type: 'FieldDefinition',
        key,
        value,
        computed: false,
        static: false,
        decorators
    } : {
        type: 'FieldDefinition',
        key,
        value,
        computed: false,
        static: false,
    });
}
function parsePrivateMethod(parser, context, key, pos, decorators) {
    const value = parseMethodDeclaration(parser, context | 4096 /* Strict */, 0 /* None */);
    parser.flags &= ~(4 /* AllowDestructuring */ | 2 /* AllowBinding */);
    return finishNode(context, parser, pos, context & 2048 /* OptionsExperimental */ ? {
        type: 'MethodDefinition',
        kind: 'method',
        static: false,
        computed: false,
        key,
        value,
        decorators
    } : {
        type: 'MethodDefinition',
        kind: 'method',
        static: false,
        computed: false,
        key,
        value,
    });
}
/**
 * Parse either call expression or import expressions
 *
 * @param parser Parser object
 * @param context Context masks
 */
function parseCallImportOrMetaProperty(parser, context) {
    const pos = getLocation(parser);
    const id = parseIdentifier(parser, context);
    // Import.meta - Stage 3 proposal
    if (consume(parser, context, 16777229 /* Period */)) {
        if (context & 8192 /* Module */ && parser.tokenValue === 'meta')
            return parseMetaProperty(parser, context, id, pos);
        tolerant(parser, context, 1 /* UnexpectedToken */, tokenDesc(parser.token));
    }
    let expr = parseImportExpression(parser, context, pos);
    expect(parser, context, 50331659 /* LeftParen */);
    const args = parseExpressionCoverGrammar(parser, context | 65536 /* AllowIn */, parseAssignmentExpression);
    expect(parser, context, 16 /* RightParen */);
    expr = finishNode(context, parser, pos, {
        type: 'CallExpression',
        callee: expr,
        arguments: [args],
    });
    return expr;
}
/**
 * Parse Import() expression. (Stage 3 proposal)
 *
 * @param parser Parser object
 * @param context Context masks
 * @param pos Location
 */
function parseImportExpression(parser, context, pos) {
    return finishNode(context, parser, pos, {
        type: 'Import',
    });
}
/**
 * Parse meta property
 *
 * @see [Link](https://tc39.github.io/ecma262/#prod-StatementList)
 *
 * @param parser Parser object
 * @param context Context masks
 * @param meta Identifier
 * @param pos Location
 */
function parseMetaProperty(parser, context, meta, pos) {
    return finishNode(context, parser, pos, {
        meta,
        type: 'MetaProperty',
        property: parseIdentifier(parser, context),
    });
}
/**
 * Parse new expression
 *
 * @see [Link](https://tc39.github.io/ecma262/#prod-NewExpression)
 *
 * @param parser Parser object
 * @param context Context masks
 */
function parseNewExpressionOrMetaProperty(parser, context) {
    const pos = getLocation(parser);
    const id = parseIdentifier(parser, context);
    if (consume(parser, context, 16777229 /* Period */)) {
        if (parser.tokenValue !== 'target' ||
            !(context & (524288 /* InParameter */ | 1048576 /* InFunctionBody */)))
            tolerant(parser, context, 51 /* MetaNotInFunctionBody */);
        return parseMetaProperty(parser, context, id, pos);
    }
    return finishNode(context, parser, pos, {
        type: 'NewExpression',
        callee: parseImportOrMemberExpression(parser, context, pos),
        arguments: parser.token === 50331659 /* LeftParen */ ? parseArgumentList(parser, context) : [],
    });
}
/**
 * Parse either import or member expression
 *
 * @see [Link](https://tc39.github.io/ecma262/#prod-MemberExpression)
 *
 * @param parser Parser object
 * @param context Context masks
 */
function parseImportOrMemberExpression(parser, context, pos) {
    const { token } = parser;
    if (context & 1 /* OptionsNext */ && token === 33566810 /* ImportKeyword */) {
        // Invalid: '"new import(x)"'
        if (lookahead(parser, context, nextTokenIsLeftParen))
            tolerant(parser, context, 1 /* UnexpectedToken */, tokenDesc(token));
        // Fixes cases like ''new import.meta','
        return parseCallImportOrMetaProperty(parser, context);
    }
    return parseMemberExpression(parser, context, pos);
}
/**
 * Parse super property
 *
 * @see [Link](https://tc39.github.io/ecma262/#prod-SuperProperty)
 *
 * @param parser Parser object
 * @param context Context masks
 */
function parseSuperProperty(parser, context) {
    // SuperProperty[Yield, Await]:
    //  super[Expression[+In, ?Yield, ?Await]]
    //  super.IdentifierName
    const pos = getLocation(parser);
    expect(parser, context, 33566813 /* SuperKeyword */);
    switch (parser.token) {
        case 50331659 /* LeftParen */:
            // The super property has to be within a class constructor
            if (!(context & 67108864 /* AllowSuperProperty */))
                tolerant(parser, context, 52 /* BadSuperCall */);
            break;
        case 41943059 /* LeftBracket */:
        case 16777229 /* Period */:
            if (!(context & 33554432 /* Method */))
                tolerant(parser, context, 53 /* UnexpectedSuper */);
            break;
        default:
            tolerant(parser, context, 54 /* LoneSuper */);
    }
    return finishNode(context, parser, pos, {
        type: 'Super',
    });
}
/**
 * Parse statement list
 *
 * @see [Link](https://tc39.github.io/ecma262/#prod-StatementList)
 *
 * @param parser Parser object
 * @param context Context masks
 */
function parseTemplateLiteral(parser, context) {
    const pos = getLocation(parser);
    return finishNode(context, parser, pos, {
        type: 'TemplateLiteral',
        expressions: [],
        quasis: [parseTemplateSpans(parser, context)],
    });
}
/**
 * Parse statement list
 *
 * @see [Link](https://tc39.github.io/ecma262/#prod-StatementList)
 *
 * @param parser Parser object
 * @param context Context masks
 */
function parseTemplateHead(parser, context, cooked = null, raw, pos) {
    parser.token = consumeTemplateBrace(parser, context);
    return finishNode(context, parser, pos, {
        type: 'TemplateElement',
        value: {
            cooked,
            raw,
        },
        tail: false,
    });
}
/**
 * Parse statement list
 *
 * @see [Link](https://tc39.github.io/ecma262/#prod-StatementList)
 *
 * @param parser Parser object
 * @param context Context masks
 */
function parseTemplate(parser, context, expressions = [], quasis = []) {
    const pos = getLocation(parser);
    const { tokenValue, tokenRaw } = parser;
    expect(parser, context, 33554440 /* TemplateCont */);
    expressions.push(parseExpression(parser, context));
    const t = getLocation(parser);
    quasis.push(parseTemplateHead(parser, context, tokenValue, tokenRaw, pos));
    if (parser.token === 33554441 /* TemplateTail */) {
        quasis.push(parseTemplateSpans(parser, context, t));
    }
    else {
        parseTemplate(parser, context, expressions, quasis);
    }
    return finishNode(context, parser, pos, {
        type: 'TemplateLiteral',
        expressions,
        quasis,
    });
}
/**
 * Parse statement list
 *
 * @see [Link](https://tc39.github.io/ecma262/#prod-StatementList)
 *
 * @param parser Parser object
 * @param context Context masks
 */
function parseTemplateSpans(parser, context, pos = getLocation(parser)) {
    const { tokenValue, tokenRaw } = parser;
    expect(parser, context, 33554441 /* TemplateTail */);
    return finishNode(context, parser, pos, {
        type: 'TemplateElement',
        value: {
            cooked: tokenValue,
            raw: tokenRaw,
        },
        tail: true,
    });
}
/**
 * Parses decorators
 *
 * @param parser Parser object
 * @param context Context masks
 */
function parseDecoratorList(parser, context) {
    const pos = getLocation(parser);
    return finishNode(context, parser, pos, {
        type: 'Decorator',
        expression: parseLeftHandSideExpression(parser, context, pos)
    });
}
/**
 * Parses a list of decorators
 *
 * @param parser Parser object
 * @param context Context masks
 */
function parseDecorators(parser, context) {
    const decoratorList = [];
    while (consume(parser, context, 120 /* At */)) {
        decoratorList.push(parseDecoratorList(parser, context | 1073741824 /* AllowDecorator */));
    }
    return decoratorList;
}

// 12.15.5 Destructuring Assignment
/**
 * Parses either a binding identifier or binding pattern
 *
 * @param parser  Parser object
 * @param context Context masks
 */
function parseBindingIdentifierOrPattern(parser, context, args = []) {
    const { token } = parser;
    if (token & 8388608 /* IsBindingPattern */) {
        return token === 41943052 /* LeftBrace */ ?
            parserObjectAssignmentPattern(parser, context) :
            parseArrayAssignmentPattern(parser, context, args);
    }
    else if (token & (131072 /* IsAwait */ | 1073741824 /* IsYield */)) {
        if (token & 131072 /* IsAwait */ && (context & (131072 /* Async */ | 8192 /* Module */))) {
            tolerant(parser, context, 46 /* AwaitBindingIdentifier */);
        }
        else if (token & 1073741824 /* IsYield */ && (context & (262144 /* Yield */ | 4096 /* Strict */))) {
            tolerant(parser, context, 47 /* YieldBindingIdentifier */);
        }
    }
    args.push(parser.tokenValue);
    return parseBindingIdentifier(parser, context);
}
/**
 * Parse binding identifier
 *
 * @see [Link](https://tc39.github.io/ecma262/#prod-BindingIdentifier)
 *
 * @param parser  Parser object
 * @param context Context masks
 */
function parseBindingIdentifier(parser, context) {
    const { token } = parser;
    if (token & 4194304 /* IsEvalOrArguments */) {
        if (context & 4096 /* Strict */)
            tolerant(parser, context, 15 /* StrictLHSAssignment */);
        parser.flags |= 2048 /* StrictEvalArguments */;
    }
    else if (context & 4194304 /* BlockScope */ && token === 33574984 /* LetKeyword */) {
        // let is disallowed as a lexically bound name
        tolerant(parser, context, 25 /* LetInLexicalBinding */);
    }
    else if (hasBit(token, 20480 /* FutureReserved */)) {
        if (context & 4096 /* Strict */)
            tolerant(parser, context, 1 /* UnexpectedToken */, tokenDesc(token));
        parser.flags |= 1024 /* StrictFunctionName */;
    }
    else if (!isValidIdentifier(context, token)) {
        tolerant(parser, context, 1 /* UnexpectedToken */, tokenDesc(token));
    }
    const pos = getLocation(parser);
    const name = parser.tokenValue;
    nextToken(parser, context);
    return finishNode(context, parser, pos, {
        type: 'Identifier',
        name,
    });
}
/**
 * Parse assignment rest element
 *
 * @see [Link](https://tc39.github.io/ecma262/#prod-AssignmentRestElement)
 *
 * @param parser  Parser object
 * @param context Context masks
 */
function parseAssignmentRestElement(parser, context, args) {
    const pos = getLocation(parser);
    expect(parser, context, 14 /* Ellipsis */);
    const argument = parseBindingIdentifierOrPattern(parser, context, args);
    if (parser.token === 16777234 /* Comma */)
        tolerant(parser, context, 86 /* RestWithComma */);
    return finishNode(context, parser, pos, {
        type: 'RestElement',
        argument,
    });
}
/**
 * Parse rest property
 *
 * @see [Link](https://tc39.github.io/ecma262/#prod-AssignmentRestProperty)
 *
 * @param parser  Parser object
 * @param context Context masks
 */
// tslint:disable-next-line:function-name
function AssignmentRestProperty(parser, context) {
    const pos = getLocation(parser);
    expect(parser, context, 14 /* Ellipsis */);
    const { token } = parser;
    const argument = parseBindingIdentifierOrPattern(parser, context);
    if (hasBit(token, 8388608 /* IsBindingPattern */))
        tolerant(parser, context, 92 /* InvalidRestBindingPattern */);
    if (parser.token === 16777234 /* Comma */)
        tolerant(parser, context, 86 /* RestWithComma */);
    return finishNode(context, parser, pos, {
        type: 'RestElement',
        argument,
    });
}
/**
 * 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]
 *
 * @see [Link](https://tc39.github.io/ecma262/#prod-ArrayAssignmentPattern)
 *
 * @param Parser object
 * @param Context masks
 */
function parseArrayAssignmentPattern(parser, context, args) {
    const pos = getLocation(parser);
    expect(parser, context, 41943059 /* LeftBracket */);
    const elements = [];
    while (parser.token !== 20 /* RightBracket */) {
        if (consume(parser, context, 16777234 /* Comma */)) {
            elements.push(null);
        }
        else {
            if (parser.token === 14 /* Ellipsis */) {
                elements.push(parseAssignmentRestElement(parser, context, args));
                break;
            }
            else {
                elements.push(parseExpressionCoverGrammar(parser, context | 65536 /* AllowIn */, parseBindingInitializer));
            }
            if (parser.token !== 20 /* RightBracket */)
                expect(parser, context, 16777234 /* Comma */);
        }
    }
    expect(parser, context, 20 /* RightBracket */);
    // tslint:disable-next-line:no-object-literal-type-assertion
    return finishNode(context, parser, pos, {
        type: 'ArrayPattern',
        elements,
    });
}
/**
 * Parse object assignment pattern
 *
 * @param Parser Parser object
 * @param Context Context masks
 */
function parserObjectAssignmentPattern(parser, context) {
    const pos = getLocation(parser);
    const properties = [];
    expect(parser, context, 41943052 /* LeftBrace */);
    while (parser.token !== 17301519 /* RightBrace */) {
        if (parser.token === 14 /* Ellipsis */) {
            properties.push(AssignmentRestProperty(parser, context));
            break;
        }
        properties.push(parseAssignmentProperty(parser, context));
        if (parser.token !== 17301519 /* RightBrace */)
            expect(parser, context, 16777234 /* Comma */);
    }
    expect(parser, context, 17301519 /* RightBrace */);
    return finishNode(context, parser, pos, {
        type: 'ObjectPattern',
        properties,
    });
}
/** Parse assignment pattern
 *
 * @see [Link](https://tc39.github.io/ecma262/#prod-AssignmentPattern)
 * @see [Link](https://tc39.github.io/ecma262/#prod-ArrayAssignmentPattern)
 *
 * @param parser Parser object
 * @param context Context masks
 * @param left LHS of assignment pattern
 * @param pos Location
 */
function parseAssignmentPattern(parser, context, left, pos) {
    return finishNode(context, parser, pos, {
        type: 'AssignmentPattern',
        left,
        right: parseExpressionCoverGrammar(parser, context | 65536 /* AllowIn */, parseAssignmentExpression),
    });
}
/**
 * Parse binding initializer
 *
 * @see [Link](https://tc39.github.io/ecma262/#prod-AssignmentPattern)
 * @see [Link](https://tc39.github.io/ecma262/#prod-ArrayAssignmentPattern)
 *
 * @param parser Parser object
 * @param context Context masks
 */
function parseBindingInitializer(parser, context) {
    const pos = getLocation(parser);
    const left = parseBindingIdentifierOrPattern(parser, context);
    return !consume(parser, context, 83886109 /* Assign */) ?
        left :
        finishNode(context, parser, pos, {
            type: 'AssignmentPattern',
            left,
            right: parseAssignmentExpression(parser, context | 65536 /* AllowIn */),
        });
}
/**
 * Parse assignment property
 *
 * @see [Link](https://tc39.github.io/ecma262/#prod-AssignmentProperty)
 *
 * @param parser Parser object
 * @param context Context masks
 */
function parseAssignmentProperty(parser, context) {
    const pos = getLocation(parser);
    const { token } = parser;
    let key;
    let value;
    let computed = false;
    let shorthand = false;
    // single name binding
    if (token & (65536 /* IsIdentifier */ | 4096 /* Keyword */)) {
        key = parseIdentifier(parser, context);
        shorthand = !consume(parser, context, 16777237 /* Colon */);
        if (shorthand) {
            const hasInitializer = consume(parser, context, 83886109 /* Assign */);
            if (context & 262144 /* Yield */ && token & 1073741824 /* IsYield */)
                tolerant(parser, context, 47 /* YieldBindingIdentifier */);
            if (!isValidIdentifier(context, token))
                tolerant(parser, context, 44 /* UnexpectedReserved */);
            value = hasInitializer ? parseAssignmentPattern(parser, context, key, pos) : key;
        }
        else
            value = parseBindingInitializer(parser, context);
    }
    else {
        computed = token === 41943059 /* LeftBracket */;
        key = parsePropertyName(parser, context);
        expect(parser, context, 16777237 /* Colon */);
        value = parseExpressionCoverGrammar(parser, context, parseBindingInitializer);
    }
    // Note! The specs specifically state that this is "assignment property", but
    // nothing in ESTree specs explains the difference between this "property" and the "property" for object literals.
    return finishNode(context, parser, pos, {
        type: 'Property',
        kind: 'init',
        key,
        computed,
        value,
        method: false,
        shorthand,
    });
}

// Declarations
/**
 * Parses class declaration
 *
 * @see [Link](https://tc39.github.io/ecma262/#prod-ClassDeclaration)
 *
 * @param parser  Parser object
 * @param context Context masks
 */
function parseClassDeclaration(parser, context) {
    const pos = getLocation(parser);
    let decorators = [];
    if (context & 2048 /* OptionsExperimental */)
        decorators = parseDecorators(parser, context);
    expect(parser, context | 536870912 /* DisallowEscapedKeyword */, 33566797 /* ClassKeyword */);
    const id = (context & 16777216 /* RequireIdentifier */ && (parser.token !== 33619969 /* Identifier */))
        ? null :
        parseBindingIdentifier(parser, context | 4096 /* Strict */ | 536870912 /* DisallowEscapedKeyword */);
    let state = 0 /* None */;
    let superClass = null;
    if (consume(parser, context, 12372 /* ExtendsKeyword */)) {
        superClass = parseLeftHandSideExpression(parser, context | 4096 /* Strict */, pos);
        state |= 512 /* Heritage */;
    }
    const body = parseClassBodyAndElementList(parser, context & ~16777216 /* RequireIdentifier */ | 4096 /* Strict */ | 32768 /* InClass */, state);
    return finishNode(context, parser, pos, context & 2048 /* OptionsExperimental */ ? {
        type: 'ClassDeclaration',
        id,
        superClass,
        body,
        decorators
    } : {
        type: 'ClassDeclaration',
        id,
        superClass,
        body
    });
}
/**
 * Parses function declaration
 *
 * @see [Link](https://tc39.github.io/ecma262/#prod-FunctionDeclaration)
 *
 * @param parser  Parser object
 * @param context Context masks
 */
function parseFunctionDeclaration(parser, context) {
    const pos = getLocation(parser);
    expect(parser, context, 33566808 /* FunctionKeyword */);
    let isGenerator = 0 /* None */;
    if (consume(parser, context, 167774771 /* Multiply */)) {
        if (context & 2097152 /* AllowSingleStatement */ && !(context & 1048576 /* InFunctionBody */)) {
            tolerant(parser, context, 20 /* GeneratorInSingleStatementContext */);
        }
        isGenerator = 1 /* Generator */;
    }
    return parseFunctionDeclarationBody(parser, context, isGenerator, pos);
}
/**
 * Parses out a function declartion body
 *
 * @see [Link](https://tc39.github.io/ecma262/#prod-AsyncFunctionDeclaration)
 * @see [Link](https://tc39.github.io/ecma262/#prod-AsyncGeneratorDeclaration)
 *
 * @param parser Parser object
 * @param context Context mask
 * @param state Modifier state
 * @param pos Current location
 */
function parseFunctionDeclarationBody(parser, context, state, pos) {
    const id = parseFunctionDeclarationName(parser, context);
    const { params, body } = swapContext(parser, context & ~(33554432 /* Method */ | 67108864 /* AllowSuperProperty */ | 16777216 /* RequireIdentifier */), state, parseFormalListAndBody);
    return finishNode(context, parser, pos, {
        type: 'FunctionDeclaration',
        params,
        body,
        async: !!(state & 2 /* Await */),
        generator: !!(state & 1 /* Generator */),
        expression: false,
        id,
    });
}
/**
 * Parses async function or async generator declaration
 *
 * @see [Link](https://tc39.github.io/ecma262/#prod-AsyncFunctionDeclaration)
 * @see [Link](https://tc39.github.io/ecma262/#prod-AsyncGeneratorDeclaration)
 *
 * @param parser  Parser object
 * @param context Context masks
 */
function parseAsyncFunctionOrAsyncGeneratorDeclaration(parser, context) {
    const pos = getLocation(parser);
    expect(parser, context, 299116 /* AsyncKeyword */);
    expect(parser, context, 33566808 /* FunctionKeyword */);
    const isAwait = 2 /* Await */;
    const isGenerator = consume(parser, context, 167774771 /* Multiply */) ? 1 /* Generator */ : 0 /* None */;
    return parseFunctionDeclarationBody(parser, context, isGenerator | isAwait, pos);
}
/**
 * Shared helper function for "parseFunctionDeclaration" and "parseAsyncFunctionOrAsyncGeneratorDeclaration"
 * so we can re-use the same logic when parsing out the function name, or throw an
 * error if the 'RequireIdentifier' mask is not set
 *
 * @param parser  Parser object
 * @param context Context masks
 */
function parseFunctionDeclarationName(parser, context) {
    const { token } = parser;
    let id = null;
    if (context & 262144 /* Yield */ && token & 1073741824 /* IsYield */)
        tolerant(parser, context, 47 /* YieldBindingIdentifier */);
    if (context & 131072 /* Async */ && token & 131072 /* IsAwait */)
        tolerant(parser, context, 46 /* AwaitBindingIdentifier */);
    if (token !== 50331659 /* LeftParen */) {
        id = parseBindingIdentifier(parser, context);
        // Unnamed functions are forbidden in statement context.
    }
    else if (!(context & 16777216 /* RequireIdentifier */))
        tolerant(parser, context, 37 /* UnNamedFunctionDecl */);
    return id;
}
/**
 * VariableDeclaration :
 *   BindingIdentifier Initializeropt
 *   BindingPattern Initializer
 *
 * VariableDeclarationNoIn :
 *   BindingIdentifier InitializerNoInopt
 *   BindingPattern InitializerNoIn
 *
 *
 * @see [Link](https://tc39.github.io/ecma262/#prod-VariableDeclaration)
 *
 * @param parser  Parser object
 * @param context Context masks
 */
function parseVariableDeclaration(parser, context, isConst) {
    const pos = getLocation(parser);
    const isBindingPattern = (parser.token & 8388608 /* IsBindingPattern */) !== 0;
    const id = parseBindingIdentifierOrPattern(parser, context);
    let init = null;
    if (consume(parser, context | 536870912 /* DisallowEscapedKeyword */, 83886109 /* Assign */)) {
        init = parseExpressionCoverGrammar(parser, context & ~(4194304 /* BlockScope */ | 8388608 /* ForStatement */), parseAssignmentExpression);
        if (parser.token & 1048576 /* IsInOrOf */ && (context & 8388608 /* ForStatement */ || isBindingPattern)) {
            if (parser.token === 168834865 /* InKeyword */) {
                // https://github.com/tc39/test262/blob/master/test/annexB/language/statements/for-in/strict-initializer.js
                if (context & (4194304 /* BlockScope */ | 4096 /* Strict */ | 131072 /* Async */) || isBindingPattern) {
                    tolerant(parser, context, 23 /* ForInOfLoopInitializer */, tokenDesc(parser.token));
                }
            }
            else
                tolerant(parser, context, 23 /* ForInOfLoopInitializer */, tokenDesc(parser.token));
        }
        // Note: Initializers are required for 'const' and binding patterns
    }
    else if (!(parser.token & 1048576 /* IsInOrOf */) && (isConst || isBindingPattern)) {
        tolerant(parser, context, 22 /* DeclarationMissingInitializer */, isConst ? 'const' : 'destructuring');
    }
    return finishNode(context, parser, pos, {
        type: 'VariableDeclarator',
        init,
        id,
    });
}
/**
 * Parses variable declaration list
 *
 * @see [Link](https://tc39.github.io/ecma262/#prod-VariableDeclarationList)
 *
 * @param parser  Parser object
 * @param context Context masks
 */
function parseVariableDeclarationList(parser, context, isConst) {
    const list = [parseVariableDeclaration(parser, context, isConst)];
    while (consume(parser, context, 16777234 /* Comma */))
        list.push(parseVariableDeclaration(parser, context, isConst));
    if (context & 8388608 /* ForStatement */ && parser.token & 1048576 /* IsInOrOf */ && list.length !== 1) {
        tolerant(parser, context, 24 /* ForInOfLoopMultiBindings */, tokenDesc(parser.token));
    }
    return list;
}

// Statements
/**
 * Parses statement list items
 *
 * @see [Link](https://tc39.github.io/ecma262/#prod-StatementListItem)
 *
 * @param parser  Parser object
 * @param context Context masks
 */
function parseStatementListItem(parser, context) {
    switch (parser.token) {
        case 33566808 /* FunctionKeyword */:
            return parseFunctionDeclaration(parser, context);
        case 120 /* At */:
        case 33566797 /* ClassKeyword */:
            return parseClassDeclaration(parser, context);
        case 33574984 /* LetKeyword */:
            return parseLetOrExpressionStatement(parser, context | 65536 /* AllowIn */);
        case 33566793 /* ConstKeyword */:
            return parseVariableStatement(parser, context | 4194304 /* BlockScope */ | 65536 /* AllowIn */);
        case 299116 /* AsyncKeyword */:
            return parseAsyncFunctionDeclarationOrStatement(parser, context);
        case 33566810 /* ImportKeyword */: {
            if (context & 1 /* OptionsNext */ && lookahead(parser, context, nextTokenIsLeftParenOrPeriod)) {
                return parseExpressionStatement(parser, context | 65536 /* AllowIn */);
            }
        }
        case 12371 /* ExportKeyword */:
            if (context & 8192 /* Module */) {
                tolerant(parser, context, 32 /* ImportExportDeclAtTopLevel */, tokenDesc(parser.token));
            }
        default:
            return parseStatement(parser, context | 2097152 /* AllowSingleStatement */);
    }
}
/**
 * Parses statements
 *
 * @see [Link](https://tc39.github.io/ecma262/#prod-Statement)
 *
 * @param parser  Parser object
 * @param context Context masks
 */
function parseStatement(parser, context) {
    switch (parser.token) {
        case 33566791 /* VarKeyword */:
            return parseVariableStatement(parser, context | 65536 /* AllowIn */);
        case 17301521 /* Semicolon */:
            return parseEmptyStatement(parser, context);
        case 33566814 /* SwitchKeyword */:
            return parseSwitchStatement(parser, context);
        case 41943052 /* LeftBrace */:
            return parseBlockStatement(parser, context);
        case 12380 /* ReturnKeyword */:
            return parseReturnStatement(parser, context);
        case 12377 /* IfKeyword */:
            return parseIfStatement(parser, context);
        case 12369 /* DoKeyword */:
            return parseDoWhileStatement(parser, context);
        case 12402 /* WhileKeyword */:
            return parseWhileStatement(parser, context);
        case 12387 /* WithKeyword */:
            return parseWithStatement(parser, context);
        case 12362 /* BreakKeyword */:
            return parseBreakStatement(parser, context);
        case 12366 /* ContinueKeyword */:
            return parseContinueStatement(parser, context);
        case 12367 /* DebuggerKeyword */:
            return parseDebuggerStatement(parser, context);
        case 302002272 /* ThrowKeyword */:
            return parseThrowStatement(parser, context);
        case 12385 /* TryKeyword */:
            return parseTryStatement(parser, context | 536870912 /* DisallowEscapedKeyword */);
        case 12374 /* ForKeyword */:
            return parseForStatement(parser, context | 8388608 /* ForStatement */);
        case 299116 /* AsyncKeyword */:
            if (lookahead(parser, context, nextTokenIsFuncKeywordOnSameLine)) {
                tolerant(parser, context, 33 /* AsyncFunctionInSingleStatementContext */);
            }
            return parseExpressionOrLabelledStatement(parser, context | 2097152 /* AllowSingleStatement */);
        case 33566808 /* FunctionKeyword */:
            // V8
            tolerant(parser, context, context & 4096 /* Strict */ ? 17 /* StrictFunction */ : 18 /* SloppyFunction */);
        case 33566797 /* ClassKeyword */:
            tolerant(parser, context, 19 /* ForbiddenAsStatement */, tokenDesc(parser.token));
        default:
            return parseExpressionOrLabelledStatement(parser, context);
    }
}
/**
 * Parses empty statement
 *
 * @see [Link](https://tc39.github.io/ecma262/#prod-EmptyStatement)
 *
 * @param parser  Parser object
 * @param context Context masks
 */
function parseEmptyStatement(parser, context) {
    const pos = getLocation(parser);
    nextToken(parser, context);
    return finishNode(context, parser, pos, {
        type: 'EmptyStatement'
    });
}
/**
 * Parses the continue statement production
 *
 * @see [Link](https://tc39.github.io/ecma262/#prod-ContinueStatement)
 *
 * @param parser  Parser object
 * @param context Context masks
 */
function parseContinueStatement(parser, context) {
    const pos = getLocation(parser);
    expect(parser, context, 12366 /* ContinueKeyword */);
    // Appearing of continue without an IterationStatement leads to syntax error
    if (!(parser.flags & 48 /* AllowBreakOrContinue */)) {
        tolerant(parser, context, 28 /* InvalidNestedStatement */, tokenDesc(parser.token));
    }
    let label = null;
    const { tokenValue } = parser;
    if (!(parser.flags & 1 /* NewLine */) && parser.token & (65536 /* IsIdentifier */ | 4096 /* Keyword */)) {
        label = parseIdentifier(parser, context);
        validateBreakOrContinueLabel(parser, context, tokenValue, /* isContinue */ true);
    }
    consumeSemicolon(parser, context);
    return finishNode(context, parser, pos, {
        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
 */
function parseBreakStatement(parser, context) {
    const pos = getLocation(parser);
    expect(parser, context, 12362 /* BreakKeyword */);
    let label = null;
    // Use 'tokenValue' to avoid accessing another object shape which in turn can lead to
    // a "'deopt" when getting the identifier value (*if any*)
    const { tokenValue } = parser;
    if (!(parser.flags & 1 /* NewLine */) && parser.token & (65536 /* IsIdentifier */ | 4096 /* Keyword */)) {
        label = parseIdentifier(parser, context);
        validateBreakOrContinueLabel(parser, context, tokenValue, /* isContinue */ false);
    }
    else if (!(parser.flags & 48 /* AllowBreakOrContinue */)) {
        tolerant(parser, context, 28 /* InvalidNestedStatement */, 'break');
    }
    consumeSemicolon(parser, context);
    return finishNode(context, parser, pos, {
        type: 'BreakStatement',
        label
    });
}
/**
 * Parses the if statement production
 *
 * @see [Link](https://tc39.github.io/ecma262/#sec-if-statement)
 *
 * @param parser  Parser object
 * @param context Context masks
 */
function parseIfStatement(parser, context) {
    const pos = getLocation(parser);
    expect(parser, context, 12377 /* IfKeyword */);
    expect(parser, context, 50331659 /* LeftParen */);
    const test = parseExpression(parser, (context & ~1073741824 /* AllowDecorator */) | 65536 /* AllowIn */);
    expect(parser, context, 16 /* RightParen */);
    const consequent = parseConsequentOrAlternate(parser, context | 536870912 /* DisallowEscapedKeyword */);
    const alternate = consume(parser, context, 12370 /* ElseKeyword */) ? parseConsequentOrAlternate(parser, context) : null;
    return finishNode(context, parser, pos, {
        type: 'IfStatement',
        test,
        consequent,
        alternate
    });
}
/**
 * Parse either consequent or alternate. Supports AnnexB.
 * @param parser  Parser object
 * @param context Context masks
 */
function parseConsequentOrAlternate(parser, context) {
    return context & 4096 /* Strict */ || parser.token !== 33566808 /* FunctionKeyword */
        ? parseStatement(parser, context & ~2097152 /* AllowSingleStatement */)
        : parseFunctionDeclaration(parser, context);
}
/**
 * Parses the debugger statement production
 *
 * @see [Link](https://tc39.github.io/ecma262/#prod-DebuggerStatement)
 *
 * @param parser  Parser object
 * @param context Context masks
 */
function parseDebuggerStatement(parser, context) {
    const pos = getLocation(parser);
    expect(parser, context, 12367 /* DebuggerKeyword */);
    consumeSemicolon(parser, context);
    return finishNode(context, parser, pos, {
        type: 'DebuggerStatement'
    });
}
/**
 * Parses try statement
 *
 * @see [Link](https://tc39.github.io/ecma262/#prod-TryStatement)
 *
 * @param parser  Parser object
 * @param context Context masks
 */
function parseTryStatement(parser, context) {
    const pos = getLocation(parser);
    expect(parser, context, 12385 /* TryKeyword */);
    const block = parseBlockStatement(parser, context);
    const handler = parser.token === 12364 /* CatchKeyword */ ? parseCatchBlock(parser, context) : null;
    const finalizer = consume(parser, context, 12373 /* FinallyKeyword */) ? parseBlockStatement(parser, context) : null;
    if (!handler && !finalizer)
        tolerant(parser, context, 77 /* NoCatchOrFinally */);
    return finishNode(context, parser, pos, {
        type: 'TryStatement',
        block,
        handler,
        finalizer
    });
}
/**
 * Parsescatch block
 *
 * @see [Link](https://tc39.github.io/ecma262/#prod-Catch)
 *
 * @param parser  Parser object
 * @param context Context masks
 */
function parseCatchBlock(parser, context) {
    const pos = getLocation(parser);
    expect(parser, context, 12364 /* CatchKeyword */);
    let param = null;
    if (context & 1 /* OptionsNext */
        ? consume(parser, context, 50331659 /* LeftParen */)
        : expect(parser, context, 50331659 /* LeftParen */)) {
        const params = [];
        param = parseBindingIdentifierOrPattern(parser, context, params);
        validateParams(parser, context, params);
        expect(parser, context, 16 /* RightParen */);
    }
    const body = parseBlockStatement(parser, context);
    return finishNode(context, parser, pos, {
        type: 'CatchClause',
        param,
        body
    });
}
/**
 * Parses throw statement
 *
 * @see [Link](https://tc39.github.io/ecma262/#prod-ThrowStatement)
 *
 * @param parser  Parser object
 * @param context Context masks
 */
function parseThrowStatement(parser, context) {
    const pos = getLocation(parser);
    expect(parser, context, 302002272 /* ThrowKeyword */);
    if (parser.flags & 1 /* NewLine */)
        tolerant(parser, context, 78 /* NewlineAfterThrow */);
    const argument = parseExpression(parser, (context & ~1073741824 /* AllowDecorator */) | 65536 /* AllowIn */);
    consumeSemicolon(parser, context);
    return finishNode(context, parser, pos, {
        type: 'ThrowStatement',
        argument
    });
}
/**
 * Parses expression statement
 *
 * @see [Link](https://tc39.github.io/ecma262/#prod-ExpressionStatement)
 *
 * @param parser  Parser object
 * @param context Context masks
 */
function parseExpressionStatement(parser, context) {
    const pos = getLocation(parser);
    const expr = parseExpression(parser, (context & ~1073741824 /* AllowDecorator */) | 65536 /* AllowIn */);
    consumeSemicolon(parser, context);
    return finishNode(context, parser, pos, {
        type: 'ExpressionStatement',
        expression: expr
    });
}
/**
 * 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
 */
function parseDirective(parser, context) {
    const pos = getLocation(parser);
    const directive = parser.tokenRaw.slice(1, -1);
    const expr = parseExpression(parser, (context & ~1073741824 /* AllowDecorator */) | 65536 /* AllowIn */);
    consumeSemicolon(parser, context);
    return finishNode(context, parser, pos, {
        type: 'ExpressionStatement',
        expression: expr,
        directive
    });
}
/**
 * Parses either expression or labelled statement
 *
 * @see [Link](https://tc39.github.io/ecma262/#prod-ExpressionStatement)
 * @see [Link](https://tc39.github.io/ecma262/#prod-LabelledStatement)
 *
 * @param parser  Parser object
 * @param context Context masks
 */
function parseExpressionOrLabelledStatement(parser, context) {
    const pos = getLocation(parser);
    const { tokenValue, token } = parser;
    const expr = parseExpression(parser, (context & ~(2097152 /* AllowSingleStatement */ | 1073741824 /* AllowDecorator */)) | 65536 /* AllowIn */);
    if (token & (65536 /* IsIdentifier */ | 4096 /* Keyword */) && parser.token === 16777237 /* Colon */) {
        // If within generator function bodies, we do it like this so we can throw an nice error message
        if (context & 262144 /* Yield */ && token & 1073741824 /* IsYield */)
            tolerant(parser, context, 55 /* YieldReservedKeyword */);
        expect(parser, context, 16777237 /* Colon */, 81 /* LabelNoColon */);
        if (hasLabel(parser, tokenValue))
            tolerant(parser, context, 27 /* LabelRedeclaration */, tokenValue);
        addLabel(parser, tokenValue);
        let body;
        if (!(context & 4096 /* Strict */) &&
            context & 2097152 /* AllowSingleStatement */ &&
            parser.token === 33566808 /* FunctionKeyword */) {
            body = parseFunctionDeclaration(parser, context);
        }
        else {
            body = parseStatement(parser, context);
        }
        popLabel(parser, tokenValue);
        return finishNode(context, parser, pos, {
            type: 'LabeledStatement',
            label: expr,
            body
        });
    }
    consumeSemicolon(parser, context);
    return finishNode(context, parser, pos, {
        type: 'ExpressionStatement',
        expression: expr
    });
}
/**
 * Parses either a binding identifier or bindign pattern
 *
 * @see [Link](https://tc39.github.io/ecma262/#prod-EmptyStatement)
 *
 * @param parser  Parser object
 * @param context Context masks
 */
function parseDoWhileStatement(parser, context) {
    const pos = getLocation(parser);
    expect(parser, context, 12369 /* DoKeyword */);
    const body = parseIterationStatement(parser, context);
    expect(parser, context, 12402 /* WhileKeyword */);
    expect(parser, context, 50331659 /* LeftParen */);
    const test = parseExpression(parser, (context & ~1073741824 /* AllowDecorator */) | 65536 /* AllowIn */);
    expect(parser, context, 16 /* RightParen */);
    consume(parser, context, 17301521 /* Semicolon */);
    return finishNode(context, parser, pos, {
        type: 'DoWhileStatement',
        body,
        test
    });
}
/**
 * Parses while statement
 *
 * @see [Link](https://tc39.github.io/ecma262/#prod-grammar-notation-WhileStatement)
 *
 * @param parser  Parser object
 * @param context Context masks
 */
function parseWhileStatement(parser, context) {
    const pos = getLocation(parser);
    expect(parser, context, 12402 /* WhileKeyword */);
    expect(parser, context, 50331659 /* LeftParen */);
    const test = parseExpression(parser, (context & ~1073741824 /* AllowDecorator */) | 65536 /* AllowIn */);
    expect(parser, context, 16 /* RightParen */);
    const body = parseIterationStatement(parser, context);
    return finishNode(context, parser, pos, {
        type: 'WhileStatement',
        test,
        body
    });
}
/**
 * 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
 */
function parseBlockStatement(parser, context) {
    const pos = getLocation(parser);
    const body = [];
    expect(parser, context, 41943052 /* LeftBrace */);
    while (parser.token !== 17301519 /* RightBrace */) {
        body.push(parseStatementListItem(parser, context));
    }
    expect(parser, context, 17301519 /* RightBrace */);
    return finishNode(context, parser, pos, {
        type: 'BlockStatement',
        body
    });
}
/**
 * Parses return statement
 *
 * @see [Link](https://tc39.github.io/ecma262/#prod-ReturnStatement)
 *
 * @param parser  Parser object
 * @param context Context masks
 */
function parseReturnStatement(parser, context) {
    const pos = getLocation(parser);
    if (!(context & (32 /* OptionsGlobalReturn */ | 1048576 /* InFunctionBody */))) {
        tolerant(parser, context, 16 /* IllegalReturn */);
    }
    if (parser.flags & 32768 /* EscapedKeyword */)
        tolerant(parser, context, 2 /* InvalidEscapedReservedWord */);
    expect(parser, context, 12380 /* ReturnKeyword */);
    const argument = !(parser.token & 524288 /* ASI */) && !(parser.flags & 1 /* NewLine */)
        ? parseExpression(parser, (context & ~(1048576 /* InFunctionBody */ | 1073741824 /* AllowDecorator */)) | 65536 /* AllowIn */)
        : null;
    consumeSemicolon(parser, context);
    return finishNode(context, parser, pos, {
        type: 'ReturnStatement',
        argument
    });
}
/**
 * Sets the necessary mutable parser flags. The parser flags will
 * be unset after done parsing out the statements.
 *
 * @see [Link](https://tc39.github.io/ecma262/#prod-grammar-notation-IterationStatement)
 *
 * @param parser  Parser object
 * @param context Context masks
 */
function parseIterationStatement(parser, context) {
    // Note: We are deviating from the original grammar here beauce the original grammar says that the
    // 'iterationStatement' should return either'for', 'do' or 'while' statements. We are doing some
    // bitfiddling before and after to modify the parser state before we let the 'parseStatement'
    // return the mentioned statements (to match the original grammar).
    const savedFlags = parser.flags;
    parser.flags |= 32 /* InIterationStatement */ | 4 /* AllowDestructuring */;
    const body = parseStatement(parser, (context & ~2097152 /* AllowSingleStatement */) | 536870912 /* DisallowEscapedKeyword */);
    parser.flags = savedFlags;
    return body;
}
/**
 * Parses with statement
 *
 * @see [Link](https://tc39.github.io/ecma262/#prod-WithStatement)
 *
 * @param parser  Parser object
 * @param context Context masks
 */
function parseWithStatement(parser, context) {
    if (context & 4096 /* Strict */)
        tolerant(parser, context, 35 /* StrictModeWith */);
    const pos = getLocation(parser);
    expect(parser, context, 12387 /* WithKeyword */);
    expect(parser, context, 50331659 /* LeftParen */);
    const object = parseExpression(parser, (context & ~1073741824 /* AllowDecorator */) | 65536 /* AllowIn */);
    expect(parser, context, 16 /* RightParen */);
    const body = parseStatement(parser, context & ~2097152 /* AllowSingleStatement */);
    return finishNode(context, parser, pos, {
        type: 'WithStatement',
        object,
        body
    });
}
/**
 * Parses switch statement
 *
 * @see [Link](https://tc39.github.io/ecma262/#prod-SwitchStatement)
 *
 * @param parser  Parser object
 * @param context Context masks
 */
function parseSwitchStatement(parser, context) {
    const pos = getLocation(parser);
    expect(parser, context, 33566814 /* SwitchKeyword */);
    expect(parser, context, 50331659 /* LeftParen */);
    const discriminant = parseExpression(parser, (context & ~1073741824 /* AllowDecorator */) | 65536 /* AllowIn */);
    expect(parser, context, 16 /* RightParen */);
    expect(parser, context | 536870912 /* DisallowEscapedKeyword */, 41943052 /* LeftBrace */);
    const cases = [];
    const savedFlags = parser.flags;
    parser.flags |= 16 /* InSwitchStatement */;
    let seenDefault = false;
    while (parser.token !== 17301519 /* RightBrace */) {
        const clause = parseCaseOrDefaultClauses(parser, context);
        cases.push(clause);
        if (clause.test === null) {
            if (seenDefault)
                tolerant(parser, context, 31 /* MultipleDefaultsInSwitch */);
            seenDefault = true;
        }
    }
    parser.flags = savedFlags;
    expect(parser, context, 17301519 /* RightBrace */);
    return finishNode(context, parser, pos, {
        type: 'SwitchStatement',
        discriminant,
        cases
    });
}
/**
 * Parses either default clause or case clauses
 *
 * @see [Link](https://tc39.github.io/ecma262/#prod-CaseClauses)
 * @see [Link](https://tc39.github.io/ecma262/#prod-DefaultClause)
 *
 * @param parser  Parser object
 * @param context Context masks
 */
function parseCaseOrDefaultClauses(parser, context) {
    const pos = getLocation(parser);
    let test = null;
    if (consume(parser, context, 12363 /* CaseKeyword */)) {
        test = parseExpression(parser, (context & ~1073741824 /* AllowDecorator */) | 65536 /* AllowIn */);
    }
    else {
        expect(parser, context, 12368 /* DefaultKeyword */);
    }
    expect(parser, context, 16777237 /* Colon */);
    const consequent = [];
    while (!isEndOfCaseOrDefaultClauses(parser)) {
        consequent.push(parseStatementListItem(parser, context | 65536 /* AllowIn */));
    }
    return finishNode(context, parser, pos, {
        type: 'SwitchCase',
        test,
        consequent
    });
}
/**
 * Parses variable statement
 *
 * @see [Link](https://tc39.github.io/ecma262/#prod-VariableStatement)
 *
 * @param parser  Parser object
 * @param context Context masks
 */
function parseVariableStatement(parser, context, shouldConsume = true) {
    const pos = getLocation(parser);
    const { token } = parser;
    const isConst = token === 33566793 /* ConstKeyword */;
    nextToken(parser, context);
    const declarations = parseVariableDeclarationList(parser, context, isConst);
    // Only consume semicolons if not inside the 'ForStatement' production
    if (shouldConsume)
        consumeSemicolon(parser, context);
    return finishNode(context, parser, pos, {
        type: 'VariableDeclaration',
        kind: tokenDesc(token),
        declarations
    });
}
/**
 * Parses either an lexical declaration (let) or an expression statement
 *
 * @see [Link](https://tc39.github.io/ecma262/#sec-let-and-const-declarations)
 * @see [Link](https://tc39.github.io/ecma262/#prod-ExpressionStatement)
 *
 * @param parser  Parser object
 * @param context Context masks
 */
function parseLetOrExpressionStatement(parser, context, shouldConsume = true) {
    return lookahead(parser, context, isLexical)
        ? parseVariableStatement(parser, context | 4194304 /* BlockScope */, shouldConsume)
        : parseExpressionOrLabelledStatement(parser, context);
}
/**
 * Parses either async function declaration or statement
 *
 * @see [Link](https://tc39.github.io/ecma262/#prod-AsyncFunctionDeclaration)
 * @see [Link](https://tc39.github.io/ecma262/#prod-Statement)
 *
 * @param parser  Parser object
 * @param context Context masks
 */
function parseAsyncFunctionDeclarationOrStatement(parser, context) {
    return lookahead(parser, context, nextTokenIsFuncKeywordOnSameLine)
        ? parseAsyncFunctionOrAsyncGeneratorDeclaration(parser, context)
        : parseStatement(parser, context);
}
/**
 * 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
 */
function parseForStatement(parser, context) {
    const pos = getLocation(parser);
    expect(parser, context, 12374 /* ForKeyword */);
    const awaitToken = !!(context & 131072 /* Async */ && consume(parser, context, 33788013 /* AwaitKeyword */));
    expect(parser, context | 536870912 /* DisallowEscapedKeyword */, 50331659 /* LeftParen */);
    const { token } = parser;
    let init = null;
    let sequencePos = null;
    let variableStatement = null;
    let type = 'ForStatement';
    let test = null;
    let update = null;
    let right;
    if (token === 33566793 /* ConstKeyword */ || (token === 33574984 /* LetKeyword */ && lookahead(parser, context, isLexical))) {
        variableStatement = parseVariableStatement(parser, (context & ~65536 /* AllowIn */) | 4194304 /* BlockScope */, /* shouldConsume */ false);
    }
    else if (token === 33566791 /* VarKeyword */) {
        variableStatement = parseVariableStatement(parser, context & ~65536 /* AllowIn */, /* shouldConsume */ false);
    }
    else if (token !== 17301521 /* Semicolon */) {
        sequencePos = getLocation(parser);
        init = restoreExpressionCoverGrammar(parser, (context & ~65536 /* AllowIn */) | 536870912 /* DisallowEscapedKeyword */, parseAssignmentExpression);
    }
    if (consume(parser, context, 1085554 /* OfKeyword */)) {
        type = 'ForOfStatement';
        if (init) {
            if (!(parser.flags & 4 /* AllowDestructuring */) || init.type === 'AssignmentExpression') {
                tolerant(parser, context, 71 /* InvalidDestructuringTarget */);
            }
            reinterpret(parser, context, init);
        }
        else
            init = variableStatement;
        right = parseAssignmentExpression(parser, context | 65536 /* AllowIn */);
    }
    else if (consume(parser, context, 168834865 /* InKeyword */)) {
        if (init) {
            if (!(parser.flags & 4 /* AllowDestructuring */))
                tolerant(parser, context, 71 /* InvalidDestructuringTarget */);
            reinterpret(parser, context, init);
        }
        else
            init = variableStatement;
        type = 'ForInStatement';
        right = parseExpression(parser, (context & ~1073741824 /* AllowDecorator */) | 65536 /* AllowIn */);
    }
    else {
        if (parser.token === 16777234 /* Comma */)
            init = parseSequenceExpression(parser, context, init, sequencePos);
        if (variableStatement)
            init = variableStatement;
        expect(parser, context, 17301521 /* Semicolon */);
        test = parser.token !== 17301521 /* Semicolon */
            ? parseExpression(parser, (context & ~1073741824 /* AllowDecorator */) | 65536 /* AllowIn */)
            : null;
        expect(parser, context, 17301521 /* Semicolon */);
        update = parser.token !== 16 /* RightParen */
            ? parseExpression(parser, (context & ~1073741824 /* AllowDecorator */) | 65536 /* AllowIn */)
            : null;
    }
    expect(parser, context, 16 /* RightParen */);
    const body = parseIterationStatement(parser, context);
    return finishNode(context, parser, pos, type === 'ForOfStatement'
        ? {
            type,
            body,
            left: init,
            right,
            await: awaitToken
        }
        : right
            ? {
                type: type,
                body,
                left: init,
                right
            }
            : {
                type: type,
                body,
                init,
                test,
                update
            });
}

// 15.2 Modules
/**
 * Parse module item list
 *
 * @see [Link](https://tc39.github.io/ecma262/#prod-ModuleItemList)
 *
 * @param parser  Parser object
 * @param context Context masks
 */
function parseModuleItemList(parser, context) {
    // Prime the scanner
    nextToken(parser, context);
    const statements = [];
    while (parser.token !== 524288 /* EndOfSource */) {
        statements.push(parser.token === 33554435 /* StringLiteral */ ?
            parseDirective(parser, context) :
            parseModuleItem(parser, context | 65536 /* AllowIn */));
    }
    return statements;
}
/**
 * Parse module item
 *
 * @see [Link](https://tc39.github.io/ecma262/#prod-ModuleItem)
 *
 * @param parser  Parser object
 * @param context Context masks
 */
function parseModuleItem(parser, context) {
    switch (parser.token) {
        // @decorator
        case 120 /* At */:
            return parseDecorators(parser, context);
        // ExportDeclaration
        case 12371 /* ExportKeyword */:
            return parseExportDeclaration(parser, context);
        // ImportDeclaration
        case 33566810 /* ImportKeyword */:
            // 'Dynamic Import' or meta property disallowed here
            if (!(context & 1 /* OptionsNext */ && lookahead(parser, context, nextTokenIsLeftParenOrPeriod))) {
                return parseImportDeclaration(parser, context);
            }
        default:
            return parseStatementListItem(parser, context);
    }
}
/**
 * Parse export declaration
 *
 * @see [Link](https://tc39.github.io/ecma262/#prod-ExportDeclaration)
 *
 * @param parser  Parser object
 * @param context Context masks
 */
function parseExportDeclaration(parser, context) {
    const pos = getLocation(parser);
    const specifiers = [];
    let source = null;
    let declaration = null;
    expect(parser, context | 536870912 /* DisallowEscapedKeyword */, 12371 /* ExportKeyword */);
    switch (parser.token) {
        // export * FromClause ;
        case 167774771 /* Multiply */:
            return parseExportAllDeclaration(parser, context, pos);
        case 12368 /* DefaultKeyword */:
            return parseExportDefault(parser, context, pos);
        case 41943052 /* LeftBrace */:
            {
                // export ExportClause FromClause ;
                // export ExportClause ;
                expect(parser, context, 41943052 /* LeftBrace */);
                let hasReservedWord = false;
                while (parser.token !== 17301519 /* RightBrace */) {
                    if (parser.token & 12288 /* Reserved */) {
                        hasReservedWord = true;
                        setPendingError(parser);
                    }
                    specifiers.push(parseNamedExportDeclaration(parser, context));
                    if (parser.token !== 17301519 /* RightBrace */)
                        expect(parser, context, 16777234 /* Comma */);
                }
                expect(parser, context | 536870912 /* DisallowEscapedKeyword */, 17301519 /* RightBrace */);
                if (parser.token === 36977 /* FromKeyword */) {
                    source = parseModuleSpecifier(parser, context);
                    //  The left hand side can't be a keyword where there is no
                    // 'from' keyword since it references a local binding.
                }
                else if (hasReservedWord) {
                    tolerant(parser, context, 44 /* UnexpectedReserved */);
                }
                consumeSemicolon(parser, context);
                break;
            }
        // export ClassDeclaration
        case 33566797 /* ClassKeyword */:
            declaration = (parseClassDeclaration(parser, context));
            break;
        // export LexicalDeclaration
        case 33574984 /* LetKeyword */:
        case 33566793 /* ConstKeyword */:
            declaration = parseVariableStatement(parser, context | 4194304 /* BlockScope */);
            break;
        // export VariableDeclaration
        case 33566791 /* VarKeyword */:
            declaration = parseVariableStatement(parser, context);
            break;
        // export HoistableDeclaration
        case 33566808 /* FunctionKeyword */:
            declaration = parseFunctionDeclaration(parser, context);
            break;
        // export HoistableDeclaration
        case 299116 /* AsyncKeyword */:
            if (lookahead(parser, context, nextTokenIsFuncKeywordOnSameLine)) {
                declaration = parseAsyncFunctionOrAsyncGeneratorDeclaration(parser, context);
                break;
            }
        // Falls through
        default:
            report(parser, 1 /* UnexpectedToken */, tokenDesc(parser.token));
    }
    return finishNode(context, parser, pos, {
        type: 'ExportNamedDeclaration',
        source,
        specifiers,
        declaration,
    });
}
/**
 * Parse export all declaration
 *
 * @param parser  Parser object
 * @param context Context masks
 */
function parseExportAllDeclaration(parser, context, pos) {
    expect(parser, context, 167774771 /* Multiply */);
    const source = parseModuleSpecifier(parser, context);
    consumeSemicolon(parser, context);
    return finishNode(context, parser, pos, {
        type: 'ExportAllDeclaration',
        source,
    });
}
/**
 * Parse named export declaration
 *
 * @param parser  Parser object
 * @param context Context masks
 */
function parseNamedExportDeclaration(parser, context) {
    const pos = getLocation(parser);
    // ExportSpecifier :
    // IdentifierName
    // IdentifierName as IdentifierName
    const local = parseIdentifierName(parser, context | 536870912 /* DisallowEscapedKeyword */, parser.token);
    const exported = consume(parser, context, 36971 /* AsKeyword */)
        ? parseIdentifierName(parser, context, parser.token)
        : local;
    return finishNode(context, parser, pos, {
        type: 'ExportSpecifier',
        local,
        exported,
    });
}
/**
 * Parse export default
 *
 * @see [Link](https://tc39.github.io/ecma262/#prod-HoistableDeclaration)
 * @see [Link](https://tc39.github.io/ecma262/#prod-ClassDeclaration)
 * @see [Link](https://tc39.github.io/ecma262/#prod-HoistableDeclaration)
 *
 * @param parser  Parser object
 * @param context Context masks
 * @param pos Location
 */
function parseExportDefault(parser, context, pos) {
    expect(parser, context | 536870912 /* DisallowEscapedKeyword */, 12368 /* DefaultKeyword */);
    let declaration;
    switch (parser.token) {
        // export default HoistableDeclaration[Default]
        case 33566808 /* FunctionKeyword */:
            declaration = parseFunctionDeclaration(parser, context | 16777216 /* RequireIdentifier */);
            break;
        // export default ClassDeclaration[Default]
        // export default  @decl ClassDeclaration[Default]
        case 120 /* At */:
        case 33566797 /* ClassKeyword */:
            declaration = parseClassDeclaration(parser, context & ~65536 /* AllowIn */ | 16777216 /* RequireIdentifier */);
            break;
        // export default HoistableDeclaration[Default]
        case 299116 /* AsyncKeyword */:
            declaration = parseAsyncFunctionOrAssignmentExpression(parser, context | 16777216 /* RequireIdentifier */);
            break;
        default:
            {
                // export default [lookahead ∉ {function, class}] AssignmentExpression[In] ;
                declaration = parseAssignmentExpression(parser, context | 65536 /* AllowIn */);
                consumeSemicolon(parser, context);
            }
    }
    return finishNode(context, parser, pos, {
        type: 'ExportDefaultDeclaration',
        declaration,
    });
}
/**
 * Parse import declaration
 *
 * @see [Link](https://tc39.github.io/ecma262/#prod-ImportDeclaration)
 *
 * @param parser  Parser object
 * @param context Context masks
 */
function parseImportDeclaration(parser, context) {
    const pos = getLocation(parser);
    expect(parser, context, 33566810 /* ImportKeyword */);
    let source;
    let specifiers = [];
    // 'import' ModuleSpecifier ';'
    if (parser.token === 33554435 /* StringLiteral */) {
        source = parseLiteral(parser, context);
    }
    else {
        specifiers = parseImportClause(parser, context | 536870912 /* DisallowEscapedKeyword */);
        source = parseModuleSpecifier(parser, context);
    }
    consumeSemicolon(parser, context);
    return finishNode(context, parser, pos, {
        type: 'ImportDeclaration',
        specifiers,
        source,
    });
}
/**
 * Parse import clause
 *
 * @see [Link](https://tc39.github.io/ecma262/#prod-ImportClause)
 *
 * @param parser  Parser object
 * @param context Context masks
 */
function parseImportClause(parser, context) {
    const specifiers = [];
    switch (parser.token) {
        // 'import' ModuleSpecifier ';'
        case 33619969 /* Identifier */:
            {
                specifiers.push(parseImportDefaultSpecifier(parser, context));
                if (consume(parser, context, 16777234 /* Comma */)) {
                    switch (parser.token) {
                        // import a, * as foo
                        case 167774771 /* Multiply */:
                            parseImportNamespaceSpecifier(parser, context, specifiers);
                            break;
                        // import a, {bar}
                        case 41943052 /* LeftBrace */:
                            parseNamedImports(parser, context, specifiers);
                            break;
                        default:
                            tolerant(parser, context, 1 /* UnexpectedToken */, tokenDesc(parser.token));
                    }
                }
                break;
            }
        // import {bar}
        case 41943052 /* LeftBrace */:
            parseNamedImports(parser, context, specifiers);
            break;
        // import * as foo
        case 167774771 /* Multiply */:
            parseImportNamespaceSpecifier(parser, context, specifiers);
            break;
        default:
            report(parser, 1 /* UnexpectedToken */, tokenDesc(parser.token));
    }
    return specifiers;
}
/**
 * Parse named imports
 *
 * @see [Link](https://tc39.github.io/ecma262/#prod-NamedImports)
 *
 * @param parser  Parser object
 * @param context Context masks
 */
function parseNamedImports(parser, context, specifiers) {
    expect(parser, context, 41943052 /* LeftBrace */);
    while (parser.token !== 17301519 /* RightBrace */) {
        specifiers.push(parseImportSpecifier(parser, context));
        if (parser.token !== 17301519 /* RightBrace */) {
            expect(parser, context, 16777234 /* Comma */);
        }
    }
    expect(parser, context, 17301519 /* RightBrace */);
}
/**
 * Parse import specifier
 *
 * @see [Link](https://tc39.github.io/ecma262/#prod-ImportSpecifier)
 *
 * @param parser  Parser object
 * @param context Context masks
 */
function parseImportSpecifier(parser, context) {
    const pos = getLocation(parser);
    const { token } = parser;
    const imported = parseIdentifierName(parser, context | 536870912 /* DisallowEscapedKeyword */, token);
    let local;
    if (parser.token === 36971 /* AsKeyword */) {
        expect(parser, context, 36971 /* AsKeyword */);
        local = parseBindingIdentifier(parser, context);
    }
    else {
        // An import name that is a keyword is a syntax error if it is not followed
        // by the keyword 'as'.
        if (hasBit(token, 12288 /* Reserved */))
            tolerant(parser, context, 44 /* UnexpectedReserved */);
        if (hasBit(token, 4194304 /* IsEvalOrArguments */))
            tolerant(parser, context, 45 /* StrictEvalArguments */);
        local = imported;
    }
    return finishNode(context, parser, pos, {
        type: 'ImportSpecifier',
        local,
        imported,
    });
}
/**
 * Parse binding identifier
 *
 * @see [Link](https://tc39.github.io/ecma262/#prod-NameSpaceImport)
 *
 * @param parser  Parser object
 * @param context Context masks
 */
function parseImportNamespaceSpecifier(parser, context, specifiers) {
    const pos = getLocation(parser);
    expect(parser, context, 167774771 /* Multiply */);
    expect(parser, context, 36971 /* AsKeyword */, 80 /* AsAfterImportStart */);
    const local = parseBindingIdentifier(parser, context);
    specifiers.push(finishNode(context, parser, pos, {
        type: 'ImportNamespaceSpecifier',
        local,
    }));
}
/**
 * Parse binding identifier
 *
 * @see [Link](https://tc39.github.io/ecma262/#prod-BindingIdentifier)
 *
 * @param parser  Parser object
 * @param context Context masks
 */
function parseModuleSpecifier(parser, context) {
    // ModuleSpecifier :
    //   StringLiteral
    expect(parser, context, 36977 /* FromKeyword */);
    if (parser.token !== 33554435 /* StringLiteral */)
        report(parser, 1 /* UnexpectedToken */, tokenDesc(parser.token));
    return parseLiteral(parser, context);
}
/**
 * Parse import default specifier
 *
 * @see [Link](https://tc39.github.io/ecma262/#prod-BindingIdentifier)
 *
 * @param parser  Parser object
 * @param context Context masks
 */
function parseImportDefaultSpecifier(parser, context) {
    return finishNode(context, parser, getLocation(parser), {
        type: 'ImportDefaultSpecifier',
        local: parseIdentifier(parser, context),
    });
}
/**
 * Parses either async function or assignment expression
 *
 * @see [Link](https://tc39.github.io/ecma262/#prod-AssignmentExpression)
 * @see [Link](https://tc39.github.io/ecma262/#prod-AsyncFunctionDeclaration)
 * @see [Link](https://tc39.github.io/ecma262/#prod-AsyncGeneratorDeclaration)
 *
 * @param parser  Parser object
 * @param context Context masks
 */
function parseAsyncFunctionOrAssignmentExpression(parser, context) {
    return lookahead(parser, context, nextTokenIsFuncKeywordOnSameLine) ?
        parseAsyncFunctionOrAsyncGeneratorDeclaration(parser, context | 16777216 /* RequireIdentifier */) :
        parseAssignmentExpression(parser, context | 65536 /* AllowIn */);
}

/**
 * Creates the parser object
 *
 * @param source The source coode to parser
 * @param sourceFile Optional source file info to be attached in every node
 */
function createParser(source, sourceFile) {
    return {
        // The source code to parse
        source,
        // Source length
        length: source.length,
        // Current position
        index: 0,
        // Current line
        line: 1,
        // Current column
        column: 0,
        // Start position  before current token
        startIndex: 0,
        // Start position column before current token
        startColumn: 0,
        // Start position line before current token
        startLine: 1,
        // End position after parsing after current token
        lastIndex: 0,
        // End column position after current token
        lastColumn: 0,
        // End line position after current token
        lastLine: 0,
        // Pending cover grammar errors
        pendingExpressionError: undefined,
        // Mutable parser flags. Allows destructuring by default.
        flags: 4 /* AllowDestructuring */,
        // The tokens
        token: 524288 /* EndOfSource */,
        // Misc
        tokenRaw: '',
        lastValue: 0,
        comments: [],
        sourceFile,
        tokenRegExp: undefined,
        tokenValue: undefined,
        labelSet: undefined,
        errorLocation: undefined,
        errors: [],
    };
}
/**
 * Parse either script code or module code
 *
 * @param source source code to parse
 * @param options parser options
 */
function parse(source, options) {
    return options && options.module
        ? parseSource(source, options, 4096 /* Strict */ | 8192 /* Module */)
        : parseSource(source, options, 0 /* Empty */);
}
/**
 * Creating the parser
 *
 * @param source The source coode to parser
 * @param options The parser options
 * @param context Context masks
 */
function parseSource(source, options, /*@internal*/ context) {
    let sourceFile = '';
    if (!!options) {
        // The flag to enable module syntax support
        if (options.module)
            context |= 8192 /* Module */;
        // The flag to enable stage 3 support (ESNext)
        if (options.next)
            context |= 1 /* OptionsNext */;
        // The flag to enable React JSX parsing
        if (options.jsx)
            context |= 4 /* OptionsJSX */;
        // The flag to enable start and end offsets to each node
        if (options.ranges)
            context |= 2 /* OptionsRanges */;
        // The flag to enable line/column location information to each node
        if (options.loc)
            context |= 16 /* OptionsLoc */;
        // The flag to attach raw property to each literal node
        if (options.raw)
            context |= 8 /* OptionsRaw */;
        // Attach raw property to each identifier node
        if (options.rawIdentifier)
            context |= 256 /* OptionsRawidentifiers */;
        // The flag to allow return in the global scope
        if (options.globalReturn)
            context |= 32 /* OptionsGlobalReturn */;
        // The flag to allow to skip shebang - '#'
        if (options.skipShebang)
            context |= 128 /* OptionsShebang */;
        // Enable tolerant mode
        if (options.tolerant)
            context |= 512 /* OptionsTolerant */;
        // Set to true to record the source file in every node's loc object when the loc option is set.
        if (!!options.source)
            sourceFile = options.source;
        // Create a top-level comments array containing all comments
        if (!!options.comments)
            context |= 64 /* OptionsComments */;
        // The flag to enable implied strict mode
        if (options.impliedStrict)
            context |= 4096 /* Strict */;
        // The flag to enable experimental features
        if (options.experimental)
            context |= 2048 /* OptionsExperimental */;
        // The flag to set to bypass methods in Node
        if (options.node)
            context |= 1024 /* OptionsNode */;
        // Accepts a callback function to be invoked for each syntax node (as the node is constructed)
    }
    const parser = createParser(source, sourceFile);
    const body = context & 8192 /* Module */
        ? parseModuleItemList(parser, context)
        : parseStatementList(parser, context);
    const node = {
        type: 'Program',
        sourceType: context & 8192 /* Module */ ? 'module' : 'script',
        body: body,
    };
    if (context & 2 /* OptionsRanges */) {
        node.start = 0;
        node.end = source.length;
    }
    if (context & 16 /* OptionsLoc */) {
        node.loc = {
            start: {
                line: 1,
                column: 0,
            },
            end: {
                line: parser.line,
                column: parser.column,
            },
        };
        if (sourceFile)
            node.loc.source = sourceFile;
    }
    if (context & 64 /* OptionsComments */)
        node.comments = parser.comments;
    if (context & 512 /* OptionsTolerant */)
        node.errors = parser.errors;
    return node;
}
/**
 * Parse statement list
 *
 * @see [Link](https://tc39.github.io/ecma262/#prod-StatementList)
 *
 * @param Parser instance
 * @param Context masks
 */
function parseStatementList(parser, context) {
    const statements = [];
    nextToken(parser, context | 536870912 /* DisallowEscapedKeyword */);
    while (parser.token === 33554435 /* StringLiteral */) {
        // We do a strict check here too speed up things in case someone is crazy eenough to
        // write "use strict"; "use strict"; at Top-level. // J.K
        if (!(context & 4096 /* Strict */) && parser.tokenRaw.length === /* length of prologue*/ 12 && parser.tokenValue === 'use strict') {
            context |= 4096 /* Strict */;
        }
        statements.push(parseDirective(parser, context));
    }
    while (parser.token !== 524288 /* EndOfSource */) {
        statements.push(parseStatementListItem(parser, context));
    }
    return statements;
}
/**
 * Parse script code
 *
 * @see [Link](https://tc39.github.io/ecma262/#sec-scripts)
 *
 * @param source source code to parse
 * @param options parser options
 */
function parseScript(source, options) {
    return parseSource(source, options, 0 /* Empty */);
}
/**
 * Parse module code
 *
 * @see [Link](https://tc39.github.io/ecma262/#sec-modules)
 *
 * @param source source code to parse
 * @param options parser options
 */
function parseModule(source, options) {
    return parseSource(source, options, 4096 /* Strict */ | 8192 /* Module */);
}



var estree = /*#__PURE__*/Object.freeze({

});



var index = /*#__PURE__*/Object.freeze({
  scanIdentifier: scanIdentifier,
  scanMaybeIdentifier: scanMaybeIdentifier,
  scanHexIntegerLiteral: scanHexIntegerLiteral,
  scanOctalOrBinary: scanOctalOrBinary,
  scanImplicitOctalDigits: scanImplicitOctalDigits,
  scanSignedInteger: scanSignedInteger,
  scanNumericLiteral: scanNumericLiteral,
  scanNumericSeparator: scanNumericSeparator,
  scanDecimalDigitsOrSeparator: scanDecimalDigitsOrSeparator,
  scanDecimalAsSmi: scanDecimalAsSmi,
  scanRegularExpression: scanRegularExpression,
  scan: scan,
  scanEscapeSequence: scanEscapeSequence,
  throwStringError: throwStringError,
  scanString: scanString,
  consumeTemplateBrace: consumeTemplateBrace,
  scanTemplate: scanTemplate,
  skipSingleHTMLComment: skipSingleHTMLComment,
  skipSingleLineComment: skipSingleLineComment,
  skipMultiLineComment: skipMultiLineComment,
  addComment: addComment,
  nextUnicodeChar: nextUnicodeChar,
  isIdentifierPart: isIdentifierPart,
  escapeForPrinting: escapeForPrinting,
  consumeOpt: consumeOpt,
  consumeLineFeed: consumeLineFeed,
  scanPrivateName: scanPrivateName,
  advanceNewline: advanceNewline,
  fromCodePoint: fromCodePoint,
  readNext: readNext,
  toHex: toHex,
  advanceOnMaybeAstral: advanceOnMaybeAstral
});



var parser = /*#__PURE__*/Object.freeze({
  parseClassDeclaration: parseClassDeclaration,
  parseFunctionDeclaration: parseFunctionDeclaration,
  parseAsyncFunctionOrAsyncGeneratorDeclaration: parseAsyncFunctionOrAsyncGeneratorDeclaration,
  parseVariableDeclarationList: parseVariableDeclarationList,
  parseExpression: parseExpression,
  parseSequenceExpression: parseSequenceExpression,
  parseAssignmentExpression: parseAssignmentExpression,
  parseRestElement: parseRestElement,
  parseLeftHandSideExpression: parseLeftHandSideExpression,
  parsePrimaryExpression: parsePrimaryExpression,
  parseIdentifier: parseIdentifier,
  parseLiteral: parseLiteral,
  parseBigIntLiteral: parseBigIntLiteral,
  parseIdentifierName: parseIdentifierName,
  parseFunctionExpression: parseFunctionExpression,
  parseAsyncFunctionOrAsyncGeneratorExpression: parseAsyncFunctionOrAsyncGeneratorExpression,
  parsePropertyName: parsePropertyName,
  parseObjectLiteral: parseObjectLiteral,
  parseFormalListAndBody: parseFormalListAndBody,
  parseFunctionBody: parseFunctionBody,
  parseFormalParameters: parseFormalParameters,
  parseFormalParameterList: parseFormalParameterList,
  parseClassBodyAndElementList: parseClassBodyAndElementList,
  parseClassElement: parseClassElement,
  parseDecorators: parseDecorators,
  parseModuleItemList: parseModuleItemList,
  parseModuleItem: parseModuleItem,
  parseExportDeclaration: parseExportDeclaration,
  parseImportDeclaration: parseImportDeclaration,
  createParser: createParser,
  parse: parse,
  parseSource: parseSource,
  parseStatementList: parseStatementList,
  parseScript: parseScript,
  parseModule: parseModule,
  parseBindingIdentifierOrPattern: parseBindingIdentifierOrPattern,
  parseBindingIdentifier: parseBindingIdentifier,
  parseAssignmentRestElement: parseAssignmentRestElement,
  parseAssignmentPattern: parseAssignmentPattern,
  parseBindingInitializer: parseBindingInitializer,
  parseStatementListItem: parseStatementListItem,
  parseStatement: parseStatement,
  parseEmptyStatement: parseEmptyStatement,
  parseContinueStatement: parseContinueStatement,
  parseBreakStatement: parseBreakStatement,
  parseIfStatement: parseIfStatement,
  parseDebuggerStatement: parseDebuggerStatement,
  parseTryStatement: parseTryStatement,
  parseCatchBlock: parseCatchBlock,
  parseThrowStatement: parseThrowStatement,
  parseExpressionStatement: parseExpressionStatement,
  parseDirective: parseDirective,
  parseExpressionOrLabelledStatement: parseExpressionOrLabelledStatement,
  parseDoWhileStatement: parseDoWhileStatement,
  parseWhileStatement: parseWhileStatement,
  parseBlockStatement: parseBlockStatement,
  parseReturnStatement: parseReturnStatement,
  parseIterationStatement: parseIterationStatement,
  parseWithStatement: parseWithStatement,
  parseSwitchStatement: parseSwitchStatement,
  parseCaseOrDefaultClauses: parseCaseOrDefaultClauses,
  parseVariableStatement: parseVariableStatement,
  parseJSXRootElement: parseJSXRootElement,
  parseJSXOpeningElement: parseJSXOpeningElement,
  nextJSXToken: nextJSXToken,
  scanJSXToken: scanJSXToken,
  parseJSXText: parseJSXText,
  parseJSXAttributes: parseJSXAttributes,
  parseJSXSpreadAttribute: parseJSXSpreadAttribute,
  parseJSXNamespacedName: parseJSXNamespacedName,
  parseJSXAttributeName: parseJSXAttributeName,
  parseJSXAttribute: parseJSXAttribute,
  parseJSXEmptyExpression: parseJSXEmptyExpression,
  parseJSXSpreadChild: parseJSXSpreadChild,
  parseJSXExpressionContainer: parseJSXExpressionContainer,
  parseJSXExpression: parseJSXExpression,
  parseJSXClosingFragment: parseJSXClosingFragment,
  parseJSXClosingElement: parseJSXClosingElement,
  parseJSXIdentifier: parseJSXIdentifier,
  parseJSXMemberExpression: parseJSXMemberExpression,
  parseJSXElementName: parseJSXElementName,
  scanJSXIdentifier: scanJSXIdentifier
});

// tslint:disable:max-classes-per-file
/**
 * Class that creates RouteConfigs for the @routeConfig() decorator
 */
class RouteConfigFactory {
}
/**
 * The default RouteConfig factory
 */
class DefaultRouteConfigFactory extends RouteConfigFactory {
    /**
     * Creates `RouteConfig` objects based an instruction for a class that can be navigated to
     *
     * @param instruction Instruction containing all information based on which the `RouteConfig` objects
     * will be created
     */
    createRouteConfigs(instruction) {
        return __awaiter(this, void 0, void 0, function* () {
            const resource = routerMetadata.getOrCreateOwn(instruction.target);
            yield resource.load();
            return buildRouteConfigCollection(instruction);
        });
    }
    /**
     * Creates `RouteConfig` objects based an instruction for a class that can navigate to others
     *
     * @param instruction Instruction containing all information based on which the `RouteConfig` objects
     * will be created
     */
    createChildRouteConfigs(instruction) {
        return __awaiter(this, void 0, void 0, function* () {
            const resource = routerMetadata.getOrCreateOwn(instruction.target);
            yield resource.load();
            return buildCompleteChildRouteConfigCollection(instruction);
        });
    }
}
const buildRouteConfigCollection = (instruction) => {
    const result = [];
    const defaults = getRouteConfigDefaults(instruction);
    const overrides = buildRouteConfigOverrides(instruction);
    const configs = ensureArray(instruction.routes).concat(ensureArray(instruction.target.routes));
    // if there are no configs on any static properties, use the convention-based defaults for the target
    if (configs.length === 0) {
        configs.push(defaults);
    }
    let i = configs.length;
    while (i--) {
        const config = {};
        mergeRouteConfig(config, defaults);
        mergeRouteConfig(config, configs[i]);
        if (Array.isArray(config.route)) {
            let j = config.route.length;
            while (j--) {
                const multiConfig = {};
                mergeRouteConfig(multiConfig, config);
                multiConfig.route = config.route[j];
                mergeRouteConfig(multiConfig, overrides);
                result.push(multiConfig);
            }
        }
        else {
            mergeRouteConfig(config, overrides);
            result.push(config);
        }
    }
    const settings = getSettings(instruction);
    return settings.transformRouteConfigs(result, instruction);
};
const getRouteConfigDefaults = (instruction) => {
    const result = {};
    const settings = getSettings(instruction);
    mergeRouteConfig(result, settings.routeConfigDefaults);
    const hyphenatedName = hyphenate(instruction.target.name);
    result.route = hyphenatedName;
    result.name = hyphenatedName;
    result.title = toTitle(instruction.target.name);
    mergeRouteConfig(result, instruction.target);
    mergeRouteConfig(result, instruction.target.baseRoute);
    return result;
};
const getContainer = (x) => {
    if (x === aureliaDependencyInjection.Container) {
        return aureliaDependencyInjection.Container.instance;
    }
    const routerResource = routerMetadata.getOrCreateOwn(x);
    return (routerResource && routerResource.container) || aureliaDependencyInjection.Container.instance;
};
const getSettings = (x) => {
    return x.settings ? x.settings : getContainer(x.target).get(RouterMetadataSettings);
};
const mergeRouteConfig = (target, source) => {
    if (!source) {
        return;
    }
    const keys = Object.keys(source);
    let i = keys.length;
    while (i--) {
        const key = keys[i];
        switch (key) {
            case "route":
            case "moduleId":
            case "redirect":
            case "navigationStrategy":
            case "viewPorts":
            case "nav":
            case "href":
            case "generationUsesHref":
            case "title":
            case "navModel":
            case "caseSensitive":
            case "activationStrategy":
            case "layoutView":
            case "layoutViewModel":
            case "layoutModel":
            case "name":
                target[key] = source[key];
                break;
            case "routeName":
                target.name = source.routeName;
                break;
            case "settings":
                if (!target.settings) {
                    target.settings = {};
                }
                Object.assign(target.settings, source.settings);
                break;
            default: // no default
        }
    }
};
const buildRouteConfigOverrides = (instruction) => {
    const result = {};
    const settings = getSettings(instruction);
    mergeRouteConfig(result, settings.routeConfigOverrides);
    result.moduleId = instruction.moduleId;
    if (!result.settings) {
        result.settings = {};
    }
    return result;
};
function hyphenate(value) {
    return (value.charAt(0).toLowerCase() + value.slice(1)).replace(/([A-Z])/g, (char) => `-${char.toLowerCase()}`);
}
function toTitle(value) {
    return value.replace(/([A-Z])/g, (char) => ` ${char}`).trimLeft();
}
const buildCompleteChildRouteConfigCollection = (instruction, $module) => {
    let $constructor = $module && $module.$defaultExport && $module.$defaultExport.$constructor;
    if (!$constructor) {
        $constructor = getRegisteredConstructor(instruction.target);
    }
    const collection = buildChildRouteConfigCollection($constructor);
    return splitRouteConfig(collection);
};
const buildChildRouteConfigCollection = ($constructor) => {
    const results = [];
    const functionDeclaration = getConfigureRouterFunctionDeclaration($constructor);
    if (functionDeclaration) {
        let i = functionDeclaration.body.body.length;
        while (i--) {
            const statement = functionDeclaration.body.body[i];
            if (statement.type === "ExpressionStatement" &&
                statement.expression.type === "CallExpression" &&
                statement.expression.callee.type === "MemberExpression" &&
                statement.expression.callee.property.type === "Identifier" &&
                statement.expression.callee.property.name === "map") {
                const configCollection = getRouteConfigsFromMapCallExpression(statement.expression);
                let j = configCollection.length;
                while (j--) {
                    const config = configCollection[j];
                    if (Array.isArray(config.route)) {
                        let k = config.route.length;
                        while (k--) {
                            const multiConfig = {};
                            mergeRouteConfig(multiConfig, config);
                            multiConfig.route = config.route[k];
                            results.push(multiConfig);
                        }
                    }
                    else {
                        results.push(config);
                    }
                }
            }
        }
    }
    return results;
};
const getRegisteredConstructor = (target) => {
    const resource = routerMetadata.getOrCreateOwn(target);
    if (!resource) {
        throw new Error();
    }
    if (resource.$module && resource.$module.$defaultExport) {
        return resource.$module.$defaultExport.$constructor;
    }
    else if (resource.moduleId) {
        const registry = getContainer(target).get(Registry);
        const $module = registry.getModule(resource.moduleId);
        if ($module && $module.$defaultExport) {
            return $module.$defaultExport.$constructor;
        }
    }
    throw new Error();
};
const getRouteConfigsFromMapCallExpression = (callExpression) => {
    const results = [];
    let i = callExpression.arguments.length;
    while (i--) {
        const arg = callExpression.arguments[i];
        switch (arg.type) {
            case "ArrayExpression": {
                for (const el of arg.elements) {
                    if (el && el.type === "ObjectExpression") {
                        results.push(analyzeObjectExpression(el));
                    }
                }
                break;
            }
            case "ObjectExpression": {
                results.push(analyzeObjectExpression(arg));
                break;
            }
            default:
        }
    }
    return results;
};
const analyzeObjectExpression = (expression) => {
    const objectResult = {};
    let i = expression.properties.length;
    while (i--) {
        const prop = expression.properties[i];
        if (prop.type === "Property" && prop.key.type === "Identifier" && prop.value !== null) {
            switch (prop.value.type) {
                case "Literal":
                    objectResult[prop.key.name] = prop.value.value;
                    break;
                case "ArrayExpression":
                    objectResult[prop.key.name] = [];
                    let j = prop.value.elements.length;
                    while (j--) {
                        const el = prop.value.elements[j];
                        if (el && el.type === "Literal") {
                            objectResult[prop.key.name].push(el.value);
                        }
                    }
                    break;
                case "ObjectExpression": {
                    objectResult[prop.key.name] = analyzeObjectExpression(prop.value);
                }
                default:
            }
        }
    }
    return objectResult;
};
const getConfigureRouterFunctionDeclaration = ($constructor) => {
    let configureRouterMethod = $constructor.$export.$prototype.$properties.find(p => p.key === RouterResource.originalConfigureRouterSymbol);
    if (!configureRouterMethod) {
        configureRouterMethod = $constructor.$export.$prototype.$properties.find(p => p.key === "configureRouter");
    }
    if (configureRouterMethod) {
        let body = configureRouterMethod.descriptor.value.toString();
        // ensure we have a pattern "function functionName()" for the parser
        if (/^function *\(/.test(body)) {
            // regular named functions become "function()" when calling .toString() on the value
            body = body.replace(/^function/, `function ${typeof configureRouterMethod.key !== "symbol" ? configureRouterMethod.key : "configureRouter"}`);
        }
        else if (!/^function/.test(body)) {
            // symbol named functions become "functionName()" when calling .toString() on the value
            body = `function ${body}`;
        }
        const program = parseScript(body);
        let i = program.body.length;
        while (i--) {
            const statement = program.body[i];
            if (statement.type === "FunctionDeclaration") {
                return statement;
            }
        }
    }
    return null;
};

const noTransform = (configs) => configs;
const noFilter = () => true;
// tslint:disable-next-line:no-empty
const noAction = (..._) => { };
const defaults = {
    nav: true
};
const overrides = {};
/**
 * All available aurelia-router-metadata settings
 */
class RouterMetadataSettings {
    constructor() {
        this.routeConfigDefaults = defaults;
        this.routeConfigOverrides = overrides;
        this.transformRouteConfigs = noTransform;
        this.filterChildRoutes = noFilter;
        this.enableEagerLoading = true;
        this.enableStaticAnalysis = true;
        this.routerConfiguration = new aureliaRouter.RouterConfiguration();
        this.onBeforeLoadChildRoutes = noAction;
        this.onBeforeConfigMap = noAction;
        this.assignRouterToViewModel = false;
        this.onAfterMergeRouterConfiguration = noAction;
    }
}
/**
 * Class used to configure behavior of [[RouterResource]]
 */
class RouterMetadataConfiguration {
    /**
     * Gets the global configuration instance. This will be automatically resolved from
     * [[Container.instance]] and assigned when first accessed.
     */
    static get INSTANCE() {
        if (this.instance === undefined) {
            this.instance = aureliaDependencyInjection.Container.instance.get(RouterMetadataConfiguration);
        }
        return this.instance;
    }
    /**
     * Sets the global configuration instance. Should be configured before setRoot()
     * for changes to propagate.
     */
    static set INSTANCE(instance) {
        this.instance = instance;
    }
    /**
     * @param container Optionally pass in a container to use for resolving the dependencies
     * that this class resolves. Will default to Container.instance if null.
     */
    constructor(container) {
        this.container = container || aureliaDependencyInjection.Container.instance;
    }
    /**
     * Makes this configuration instance globally reachable through RouterMetadataConfiguration.INSTANCE
     */
    makeGlobal() {
        RouterMetadataConfiguration.INSTANCE = this;
        return this;
    }
    /**
     * Gets the RouteConfigFactory that is registered with DI, or defaults to
     * [[DefaultRouteConfigFactory]] if its not registered.
     * @param container Optionally pass in a container to use for resolving this dependency.
     * Can be a ChildContainer to scope certain overrides for certain viewModels.
     */
    getConfigFactory(container) {
        const c = container || this.container;
        if (!c.hasResolver(RouteConfigFactory)) {
            c.registerSingleton(RouteConfigFactory, DefaultRouteConfigFactory);
        }
        return c.get(RouteConfigFactory);
    }
    /**
     * Gets the RouterMetadataSettings that is registered with DI, or creates
     * a default one with noop functions if its not registered.
     * @param container Optionally pass in a container to use for resolving this dependency.
     * Can be a ChildContainer to scope certain overrides for certain viewModels.
     */
    getSettings(container) {
        const c = container || this.container;
        return c.get(RouterMetadataSettings);
    }
    /**
     * Gets the ResourceLoader that is registered with DI
     * @param container Optionally pass in a container to use for resolving this dependency.
     * Can be a ChildContainer to scope certain overrides for certain viewModels.
     */
    getResourceLoader(container) {
        const c = container || this.container;
        return c.get(ResourceLoader);
    }
    getRegistry(container) {
        const c = container || this.container;
        return c.get(Registry);
    }
}

const logger = aureliaLogging.getLogger("router-metadata");
/**
 * Identifies a class as a resource that can be navigated to (has routes) and/or
 * configures a router to navigate to other routes (maps routes)
 */
class RouterResource {
    constructor(target, moduleId) {
        this.$module = null;
        this.target = target;
        this.moduleId = moduleId;
        this.isRouteConfig = false;
        this.isConfigureRouter = false;
        this.routeConfigModuleIds = [];
        this.enableEagerLoading = false;
        this.enableStaticAnalysis = false;
        this.createRouteConfigInstruction = null;
        this.ownRoutes = [];
        this.childRoutes = [];
        this.filterChildRoutes = null;
        this.areChildRoutesLoaded = false;
        this.areOwnRoutesLoaded = false;
        this.isConfiguringRouter = false;
        this.isRouterConfigured = false;
        this.parents = new Set();
        this.router = null;
    }
    /**
     * The first (primary) parent of this route
     */
    get parent() {
        return this.parents.keys().next().value || null;
    }
    /**
     * Only applicable when `isConfigureRouter`
     *
     * A convenience property which returns `router.container`, or `null` if the router is not set
     */
    get container() {
        return this.router ? this.router.container : null;
    }
    /**
     * Only applicable when `isConfigureRouter`
     *
     * A convenience property which returns `router.container.viewModel`, or `null` if the router is not set
     * This is an instance of the target class
     */
    get instance() {
        return this.container ? this.container.viewModel : null;
    }
    /**
     * Creates a `@routeConfig` based on the provided instruction.
     *
     * This method is called by the `@routeConfig()` decorator, and can be used instead of the @routeConfig() decorator
     * to achieve the same effect.
     * @param instruction Instruction containing the parameters passed to the `@routeConfig` decorator
     */
    static ROUTE_CONFIG(instruction) {
        const resource = routerMetadata.getOrCreateOwn(instruction.target);
        resource.initialize(instruction);
        return resource;
    }
    /**
     * Creates a `@configureRouter` based on the provided instruction.
     *
     * This method is called by the `@configureRouter()` decorator, and can be used instead of the @configureRouter() decorator
     * to achieve the same effect.
     * @param instruction Instruction containing the parameters passed to the `@configureRouter` decorator
     */
    static CONFIGURE_ROUTER(instruction) {
        const resource = routerMetadata.getOrCreateOwn(instruction.target);
        resource.initialize(instruction);
        return resource;
    }
    /**
     * Initializes this resource based on the provided instruction.
     *
     * If there is a `routeConfigModuleIds` property present on the instruction,
     * or the target has a `configureRouter()` method, it will be initialized as `configureRouter`, otherwise as `routeConfig`
     * @param instruction Instruction containing the parameters passed to the `@configureRouter` decorator
     */
    initialize(instruction) {
        if (!instruction) {
            if (this.isRouteConfig && this.isConfigureRouter) {
                return; // already configured
            }
            // We're not being called from a decorator, so just apply defaults as if we're a @routeConfig
            // tslint:disable-next-line:no-parameter-reassignment
            instruction = this.ensureCreateRouteConfigInstruction();
        }
        const settings = this.getSettings(instruction);
        const target = instruction.target;
        if (isConfigureRouterInstruction(instruction)) {
            if (this.isConfigureRouter) {
                const moduleIds = instruction.routeConfigModuleIds;
                if (moduleIds && moduleIds.length) {
                    for (const moduleId of moduleIds) {
                        if (this.routeConfigModuleIds.indexOf(moduleId) === -1) {
                            this.routeConfigModuleIds.push(moduleId);
                        }
                    }
                }
                return; // already configured
            }
            logger.debug(`initializing @configureRouter for ${target.name}`);
            this.isConfigureRouter = true;
            const configureInstruction = instruction;
            this.routeConfigModuleIds = ensureArray$1(configureInstruction.routeConfigModuleIds);
            this.filterChildRoutes = settings.filterChildRoutes;
            this.enableEagerLoading = settings.enableEagerLoading;
            this.enableStaticAnalysis = settings.enableStaticAnalysis;
            assignOrProxyPrototypeProperty(target.prototype, "configureRouter", RouterResource.originalConfigureRouterSymbol, configureRouter);
        }
        else {
            if (this.isRouteConfig) {
                return; // already configured
            }
            logger.debug(`initializing @routeConfig for ${target.name}`);
            this.isRouteConfig = true;
            const configInstruction = instruction;
            this.createRouteConfigInstruction = Object.assign({}, configInstruction, { settings });
        }
    }
    /**
     * Ensures that the module for this resources is loaded and registered so that its routing information can be queried.
     */
    load() {
        return __awaiter(this, void 0, void 0, function* () {
            const registry = this.getRegistry();
            const loader = this.getResourceLoader();
            if (!this.moduleId) {
                this.moduleId = registry.registerModuleViaConstructor(this.target).moduleId;
            }
            yield loader.loadRouterResource(this.moduleId);
        });
    }
    loadOwnRoutes() {
        return __awaiter(this, void 0, void 0, function* () {
            if (this.areOwnRoutesLoaded) {
                return this.ownRoutes;
            }
            // If we're in this method then it can never be the root, so it's always safe to apply @routeConfig initialization
            if (!this.isRouteConfig) {
                this.isRouteConfig = true;
                this.initialize();
            }
            const instruction = this.ensureCreateRouteConfigInstruction();
            const configs = yield this.getConfigFactory().createRouteConfigs(instruction);
            for (const config of configs) {
                config.settings.routerResource = this;
                this.ownRoutes.push(config);
            }
            this.areOwnRoutesLoaded = true;
            return this.ownRoutes;
        });
    }
    /**
     * Retrieves the `RouteConfig` objects which were generated by all referenced moduleIds
     * and assigns them to `childRoutes`
     *
     * Will also call this method on child resources if `enableEagerLoading` is set to true.
     *
     * Will simply return the previously fetched `childRoutes` on subsequent calls.
     *
     * This method is called by `configureRouter()`.
     *
     * @param router (Optional) The router that was passed to the target instance's `configureRouter()`
     */
    loadChildRoutes(router) {
        return __awaiter(this, void 0, void 0, function* () {
            this.router = router !== undefined ? router : null;
            if (this.areChildRoutesLoaded) {
                return this.childRoutes;
            }
            logger.debug(`loading childRoutes for ${this.target.name}`);
            const loader = this.getResourceLoader();
            let extractedChildRoutes;
            if (this.enableStaticAnalysis) {
                extractedChildRoutes = yield this.getConfigFactory().createChildRouteConfigs({ target: this.target });
                for (const extracted of extractedChildRoutes) {
                    if (extracted.moduleId) {
                        if (this.routeConfigModuleIds.indexOf(extracted.moduleId) === -1) {
                            this.routeConfigModuleIds.push(extracted.moduleId);
                        }
                        yield loader.loadRouterResource(extracted.moduleId);
                    }
                }
            }
            for (const moduleId of this.routeConfigModuleIds) {
                const resource = yield loader.loadRouterResource(moduleId);
                const childRoutes = yield resource.loadOwnRoutes();
                resource.parents.add(this);
                if (resource.isConfigureRouter && this.enableEagerLoading) {
                    yield resource.loadChildRoutes();
                }
                const childRoutesToProcess = [];
                if (this.enableStaticAnalysis) {
                    const couples = alignRouteConfigs(childRoutes, extractedChildRoutes);
                    for (const couple of couples) {
                        if (couple.left) {
                            const childRoute = couple.left;
                            if (couple.right) {
                                Object.assign(childRoute, Object.assign({}, couple.right, { settings: Object.assign({}, childRoute.settings, couple.right.settings) }));
                            }
                            childRoutesToProcess.push(childRoute);
                        }
                    }
                }
                else {
                    childRoutesToProcess.push(...childRoutes);
                }
                for (const childRoute of childRoutesToProcess) {
                    if (!this.filterChildRoutes || (yield this.filterChildRoutes(childRoute, childRoutes, this))) {
                        if (this.ownRoutes.length > 0) {
                            childRoute.settings.parentRoute = this.ownRoutes[0];
                        }
                        this.childRoutes.push(childRoute);
                    }
                }
            }
            if (this.isRouteConfig) {
                const ownRoutes = yield this.loadOwnRoutes();
                for (const ownRoute of ownRoutes) {
                    ownRoute.settings.childRoutes = this.childRoutes;
                }
            }
            this.areChildRoutesLoaded = true;
            return this.childRoutes;
        });
    }
    /**
     * Calls `loadChildRoutes()` to fetch the referenced modulesIds' `RouteConfig` objects, and maps them to the router.
     *
     * This method will be assigned to `target.prototype.configureRouter`, such that the routes will be configured
     * even if there is no `configureRouter()` method present.
     *
     * If `target.prototype.configureRouter` already exists, a reference to that original method will be kept
     * and called at the end of this `configureRouter()` method.
     */
    configureRouter(config, router, ...args) {
        return __awaiter(this, void 0, void 0, function* () {
            yield this.load();
            const viewModel = router.container.viewModel;
            const settings = this.getSettings();
            if (typeof settings.onBeforeLoadChildRoutes === "function") {
                yield settings.onBeforeLoadChildRoutes(viewModel, config, router, this, ...args);
            }
            this.isConfiguringRouter = true;
            const routes = yield this.loadChildRoutes();
            assignPaths(routes);
            if (typeof settings.onBeforeConfigMap === "function") {
                yield settings.onBeforeConfigMap(viewModel, config, router, this, routes, ...args);
            }
            config.map(routes);
            this.router = router;
            if (router instanceof aureliaRouter.AppRouter || router.isRoot) {
                const assign = settings.assignRouterToViewModel;
                if (assign === true) {
                    viewModel.router = router;
                }
                else if (Object.prototype.toString.call(assign) === "[object String]") {
                    viewModel[assign] = router;
                }
                else if (typeof assign === "function") {
                    yield assign(viewModel, config, router, this, routes, ...args);
                }
                const settingsConfig = this.getSettings().routerConfiguration || {};
                mergeRouterConfiguration(config, settingsConfig);
                if (typeof settings.onAfterMergeRouterConfiguration === "function") {
                    yield settings.onAfterMergeRouterConfiguration(viewModel, config, router, this, routes, ...args);
                }
            }
            this.isRouterConfigured = true;
            this.isConfiguringRouter = false;
            const originalConfigureRouter = this.target.prototype[RouterResource.originalConfigureRouterSymbol];
            if (originalConfigureRouter !== undefined) {
                if (this.enableStaticAnalysis) {
                    Object.defineProperty(config, RouterResource.routerResourceSymbol, {
                        enumerable: false,
                        configurable: true,
                        writable: true,
                        value: this
                    });
                    Object.defineProperty(config, RouterResource.originalMapSymbol, {
                        enumerable: false,
                        configurable: true,
                        writable: true,
                        value: config.map
                    });
                    Object.defineProperty(config, "map", {
                        enumerable: true,
                        configurable: true,
                        writable: true,
                        value: map.bind(config)
                    });
                }
                return originalConfigureRouter.call(viewModel, config, router);
            }
        });
    }
    ensureCreateRouteConfigInstruction() {
        const instruction = this.createRouteConfigInstruction || (this.createRouteConfigInstruction = {});
        instruction.target = instruction.target || this.target;
        instruction.moduleId = instruction.moduleId || this.moduleId;
        instruction.settings = instruction.settings || this.getSettings(instruction);
        return instruction;
    }
    getSettings(instruction) {
        const settings = RouterMetadataConfiguration.INSTANCE.getSettings(this.container);
        if (instruction) {
            Object.assign(settings, instruction.settings || {});
        }
        return settings;
    }
    getConfigFactory() {
        return RouterMetadataConfiguration.INSTANCE.getConfigFactory(this.container);
    }
    getResourceLoader() {
        return RouterMetadataConfiguration.INSTANCE.getResourceLoader(this.container);
    }
    getRegistry() {
        return RouterMetadataConfiguration.INSTANCE.getRegistry(this.container);
    }
}
RouterResource.originalConfigureRouterSymbol = Symbol("configureRouter");
RouterResource.originalMapSymbol = Symbol("map");
RouterResource.viewModelSymbol = Symbol("viewModel");
RouterResource.routerResourceSymbol = Symbol("routerResource");
function isConfigureRouterInstruction(instruction) {
    return (!!instruction.routeConfigModuleIds ||
        Object.prototype.hasOwnProperty.call(instruction.target.prototype, "configureRouter"));
}
function ensureArray$1(value) {
    if (value === undefined) {
        return [];
    }
    return Array.isArray(value) ? value : [value];
}
function assignPaths(routes) {
    for (const route of routes.filter((r) => !r.settings.path)) {
        const parentPath = route.settings.parentRoute ? route.settings.parentRoute.settings.path : "";
        const pathProperty = route.settings.pathProperty || "route";
        const path = route[pathProperty];
        route.settings.path = `${parentPath}/${path}`.replace(/\/\//g, "/").replace(/^\//, "");
        assignPaths(route.settings.childRoutes || []);
    }
}
function assignOrProxyPrototypeProperty(proto, name, refSymbol, value) {
    if (name in proto) {
        let protoOrBase = proto;
        while (!protoOrBase.hasOwnProperty(name)) {
            protoOrBase = Object.getPrototypeOf(protoOrBase);
        }
        const original = protoOrBase[name];
        Object.defineProperty(proto, refSymbol, { enumerable: false, configurable: true, writable: true, value: original });
    }
    proto[name] = value;
}
// tslint:disable:no-invalid-this
function configureRouter(config, router, ...args) {
    return __awaiter(this, void 0, void 0, function* () {
        const target = Object.getPrototypeOf(this).constructor;
        const resource = routerMetadata.getOwn(target);
        yield resource.configureRouter(config, router, ...args);
    });
}
// tslint:enable:no-invalid-this
function map(originalConfigs) {
    Object.defineProperty(this, "map", {
        enumerable: false,
        configurable: true,
        writable: true,
        value: this[RouterResource.originalMapSymbol].bind(this)
    });
    delete this[RouterResource.originalMapSymbol];
    const resource = this[RouterResource.routerResourceSymbol];
    delete this[RouterResource.routerResourceSymbol];
    const splittedOriginalConfigs = splitRouteConfig(ensureArray$1(originalConfigs));
    const couples = alignRouteConfigs(resource.childRoutes, splittedOriginalConfigs);
    const remainingConfigs = [];
    for (const couple of couples) {
        if (couple.left && couple.right) {
            Object.assign(couple.left, Object.assign({}, couple.right, { settings: Object.assign({}, couple.left.settings, couple.right.settings) }));
        }
        else if (couple.right) {
            remainingConfigs.push(couple.right);
        }
    }
    // tslint:disable-next-line:no-parameter-reassignment
    originalConfigs = remainingConfigs;
    if (originalConfigs.length > 0) {
        this.map(originalConfigs);
    }
    return this;
}
function mergeRouterConfiguration(target, source) {
    target.instructions = (target.instructions || []).concat(source.instructions || []);
    target.options = Object.assign({}, (target.options || {}), (source.options || {}));
    target.pipelineSteps = (target.pipelineSteps || []).concat(source.pipelineSteps || []);
    target.title = source.title;
    target.unknownRouteConfig = source.unknownRouteConfig;
    target.viewPortDefaults = Object.assign({}, (target.viewPortDefaults || {}), (source.viewPortDefaults || {}));
    return target;
}
function alignRouteConfigs(leftList, rightList) {
    // we're essentially doing an OUTER JOIN here
    const couples = leftList.map(left => {
        const couple = {
            left
        };
        let rightMatches = rightList.filter(r => r.moduleId === left.moduleId);
        if (rightMatches.length > 1) {
            rightMatches = rightMatches.filter(r => r.route === left.route);
            if (rightMatches.length > 1) {
                rightMatches = rightMatches.filter(r => r.name === left.name);
                if (rightMatches.length > 1) {
                    rightMatches = rightMatches.filter(r => r.href === left.href);
                }
            }
        }
        if (rightMatches.length > 1) {
            // really shouldn't be possible
            throw new Error(`Probable duplicate routes found: ${JSON.stringify(rightMatches)}`);
        }
        if (rightMatches.length === 1) {
            couple.right = rightMatches[0];
        }
        return couple;
    });
    for (const right of rightList) {
        if (!couples.some(c => c.right === right)) {
            couples.push({ right });
        }
    }
    return couples;
}

const key = "__routerMetadata__";
const resourceKey = "resource";
const routerMetadata = {
    getOwn(target) {
        const metadata = getMetadataObject(target);
        return metadata[resourceKey];
    },
    define(resource, target) {
        const metadata = getMetadataObject(target);
        Object.defineProperty(metadata, resourceKey, {
            enumerable: false,
            configurable: false,
            writable: true,
            value: resource
        });
    },
    getOrCreateOwn(target, moduleId) {
        const metadata = getMetadataObject(target);
        let result = metadata[resourceKey];
        if (result === undefined) {
            result = metadata[resourceKey] = new RouterResource(target instanceof Function ? target : target.constructor, moduleId);
        }
        return result;
    }
};
function getMetadataObject(target) {
    const proto = target instanceof Function ? target.prototype : target;
    if (!Object.prototype.hasOwnProperty.call(proto, key)) {
        Object.defineProperty(proto, key, {
            enumerable: false,
            configurable: false,
            writable: false,
            value: Object.create(null)
        });
    }
    return proto[key];
}

class ResourceLoader {
    constructor(loader, registry) {
        this.loader = loader;
        this.registry = registry;
    }
    loadRouterResource(moduleId) {
        return __awaiter(this, void 0, void 0, function* () {
            const $module = yield this.loadModule(moduleId);
            if (!$module.$defaultExport) {
                throw new Error(`Unable to resolve RouterResource for ${$module.moduleId}.
            Module appears to have no exported classes.`);
            }
            const resource = routerMetadata.getOrCreateOwn($module.$defaultExport.$constructor.raw, $module.moduleId);
            // The decorators don't have access to their own module in aurelia-cli projects,
            // so we set the moduleId now (only used by @routeConfig resources)
            resource.moduleId = $module.moduleId;
            resource.$module = $module;
            return resource;
        });
    }
    loadModule(normalizedId) {
        return __awaiter(this, void 0, void 0, function* () {
            let $module = this.registry.getModule(normalizedId);
            if ($module === undefined) {
                const moduleInstance = yield this.loader.loadModule(normalizedId);
                $module = this.registry.registerModule(moduleInstance, normalizedId);
            }
            return $module;
        });
    }
}

/**
 * Decorator: Indicates that the decorated class should define a `RouteConfig` for itself
 * @param routesOrInstruction One or more RouteConfig objects whose properties will override the convention defaults,
 * or an instruction object containing this decorators' parameters as properties
 * @param overrideSettings A settings object to override the global RouterMetadataSettings for this resource
 */
function routeConfig(routesOrInstruction, overrideSettings) {
    return (target) => {
        let instruction;
        if (Object.prototype.toString.call(routesOrInstruction) === "[object Object]" &&
            routesOrInstruction.target) {
            instruction = routesOrInstruction;
        }
        else {
            instruction = {
                target,
                routes: routesOrInstruction,
                settings: overrideSettings
            };
        }
        RouterResource.ROUTE_CONFIG(instruction);
    };
}
/**
 * Decorator: Indicates that the decorated class should map RouteConfigs defined by the referenced moduleIds.
 * @param routeConfigModuleIdsOrInstruction A single or array of `PLATFORM.moduleName("")`,
 * or an instruction object containing this decorators' parameters as properties
 * @param overrideSettings A settings object to override the global RouterMetadataSettings for this resource
 */
function configureRouter$1(routeConfigModuleIdsOrInstruction, overrideSettings) {
    return (target) => {
        let instruction;
        if (Object.prototype.toString.call(routeConfigModuleIdsOrInstruction) === "[object Object]" &&
            routeConfigModuleIdsOrInstruction.target) {
            instruction = routeConfigModuleIdsOrInstruction;
        }
        else {
            instruction = {
                target,
                routeConfigModuleIds: routeConfigModuleIdsOrInstruction,
                settings: overrideSettings
            };
        }
        RouterResource.CONFIGURE_ROUTER(instruction);
    };
}

// tslint:disable:no-invalid-this
function configure(fxconfig, configureSettings) {
    const settings = new RouterMetadataSettings();
    if (typeof configureSettings === "function") {
        configureSettings(settings);
    }
    const container = fxconfig.container;
    const config = new RouterMetadataConfiguration(container).makeGlobal();
    container.registerInstance(RouterMetadataSettings, settings);
    container.registerInstance(RouterMetadataConfiguration, config);
    const loader = container.get(aureliaLoader.Loader);
    const registry = new Registry();
    const resourceLoader = new ResourceLoader(loader, registry);
    container.registerInstance(Registry, registry);
    container.registerInstance(ResourceLoader, resourceLoader);
    Object.defineProperty(aureliaDependencyInjection.Container.prototype, RouterResource.viewModelSymbol, {
        enumerable: false,
        configurable: true,
        writable: true
    });
    Object.defineProperty(aureliaDependencyInjection.Container.prototype, "viewModel", {
        enumerable: true,
        configurable: true,
        set: function (value) {
            routerMetadata.getOrCreateOwn(value.constructor).initialize();
            this[RouterResource.viewModelSymbol] = value;
        },
        get: function () {
            return this[RouterResource.viewModelSymbol];
        }
    });
}

exports.configure = configure;
exports.routeConfig = routeConfig;
exports.configureRouter = configureRouter$1;
exports.$Application = $Application;
exports.$Module = $Module;
exports.$Export = $Export;
exports.$Constructor = $Constructor;
exports.$Prototype = $Prototype;
exports.$Property = $Property;
exports.Registry = Registry;
exports.ResourceLoader = ResourceLoader;
exports.RouteConfigFactory = RouteConfigFactory;
exports.DefaultRouteConfigFactory = DefaultRouteConfigFactory;
exports.RouterMetadataSettings = RouterMetadataSettings;
exports.RouterMetadataConfiguration = RouterMetadataConfiguration;
exports.routerMetadata = routerMetadata;
exports.RouterResource = RouterResource;