'use strict';

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

const beforeExpr = true; const startsExpr = true; const isLoop = true; const isAssign = true; const prefix = true; const postfix = true; class TokenType {

constructor(label, conf = {}) {
  this.label = label;
  this.keyword = conf.keyword;
  this.beforeExpr = !!conf.beforeExpr;
  this.startsExpr = !!conf.startsExpr;
  this.rightAssociative = !!conf.rightAssociative;
  this.isLoop = !!conf.isLoop;
  this.isAssign = !!conf.isAssign;
  this.prefix = !!conf.prefix;
  this.postfix = !!conf.postfix;
  this.binop = conf.binop != null ? conf.binop : null;
  this.updateContext = null;
}

} const keywords = new Map();

function createKeyword(name, options = {}) {

options.keyword = name;
const token = new TokenType(name, options);
keywords.set(name, token);
return token;

}

function createBinop(name, binop) {

return new TokenType(name, {
  beforeExpr,
  binop
});

}

const types = {

num: new TokenType("num", {
  startsExpr
}),
bigint: new TokenType("bigint", {
  startsExpr
}),
regexp: new TokenType("regexp", {
  startsExpr
}),
string: new TokenType("string", {
  startsExpr
}),
name: new TokenType("name", {
  startsExpr
}),
eof: new TokenType("eof"),
bracketL: new TokenType("[", {
  beforeExpr,
  startsExpr
}),
bracketR: new TokenType("]"),
braceL: new TokenType("{", {
  beforeExpr,
  startsExpr
}),
braceBarL: new TokenType("{|", {
  beforeExpr,
  startsExpr
}),
braceR: new TokenType("}"),
braceBarR: new TokenType("|}"),
parenL: new TokenType("(", {
  beforeExpr,
  startsExpr
}),
parenR: new TokenType(")"),
comma: new TokenType(",", {
  beforeExpr
}),
semi: new TokenType(";", {
  beforeExpr
}),
colon: new TokenType(":", {
  beforeExpr
}),
doubleColon: new TokenType("::", {
  beforeExpr
}),
dot: new TokenType("."),
question: new TokenType("?", {
  beforeExpr
}),
questionDot: new TokenType("?."),
arrow: new TokenType("=>", {
  beforeExpr
}),
template: new TokenType("template"),
ellipsis: new TokenType("...", {
  beforeExpr
}),
backQuote: new TokenType("`", {
  startsExpr
}),
dollarBraceL: new TokenType("${", {
  beforeExpr,
  startsExpr
}),
at: new TokenType("@"),
hash: new TokenType("#", {
  startsExpr
}),
interpreterDirective: new TokenType("#!..."),
eq: new TokenType("=", {
  beforeExpr,
  isAssign
}),
assign: new TokenType("_=", {
  beforeExpr,
  isAssign
}),
incDec: new TokenType("++/--", {
  prefix,
  postfix,
  startsExpr
}),
bang: new TokenType("!", {
  beforeExpr,
  prefix,
  startsExpr
}),
tilde: new TokenType("~", {
  beforeExpr,
  prefix,
  startsExpr
}),
pipeline: createBinop("|>", 0),
nullishCoalescing: createBinop("??", 1),
logicalOR: createBinop("||", 2),
logicalAND: createBinop("&&", 3),
bitwiseOR: createBinop("|", 4),
bitwiseXOR: createBinop("^", 5),
bitwiseAND: createBinop("&", 6),
equality: createBinop("==/!=/===/!==", 7),
relational: createBinop("</>/<=/>=", 8),
bitShift: createBinop("<</>>/>>>", 9),
plusMin: new TokenType("+/-", {
  beforeExpr,
  binop: 10,
  prefix,
  startsExpr
}),
modulo: new TokenType("%", {
  beforeExpr,
  binop: 11,
  startsExpr
}),
star: createBinop("*", 11),
slash: createBinop("/", 11),
exponent: new TokenType("**", {
  beforeExpr,
  binop: 12,
  rightAssociative: true
}),
_break: createKeyword("break"),
_case: createKeyword("case", {
  beforeExpr
}),
_catch: createKeyword("catch"),
_continue: createKeyword("continue"),
_debugger: createKeyword("debugger"),
_default: createKeyword("default", {
  beforeExpr
}),
_do: createKeyword("do", {
  isLoop,
  beforeExpr
}),
_else: createKeyword("else", {
  beforeExpr
}),
_finally: createKeyword("finally"),
_for: createKeyword("for", {
  isLoop
}),
_function: createKeyword("function", {
  startsExpr
}),
_if: createKeyword("if"),
_return: createKeyword("return", {
  beforeExpr
}),
_switch: createKeyword("switch"),
_throw: createKeyword("throw", {
  beforeExpr,
  prefix,
  startsExpr
}),
_try: createKeyword("try"),
_var: createKeyword("var"),
_const: createKeyword("const"),
_while: createKeyword("while", {
  isLoop
}),
_with: createKeyword("with"),
_new: createKeyword("new", {
  beforeExpr,
  startsExpr
}),
_this: createKeyword("this", {
  startsExpr
}),
_super: createKeyword("super", {
  startsExpr
}),
_class: createKeyword("class", {
  startsExpr
}),
_extends: createKeyword("extends", {
  beforeExpr
}),
_export: createKeyword("export"),
_import: createKeyword("import", {
  startsExpr
}),
_null: createKeyword("null", {
  startsExpr
}),
_true: createKeyword("true", {
  startsExpr
}),
_false: createKeyword("false", {
  startsExpr
}),
_in: createKeyword("in", {
  beforeExpr,
  binop: 8
}),
_instanceof: createKeyword("instanceof", {
  beforeExpr,
  binop: 8
}),
_typeof: createKeyword("typeof", {
  beforeExpr,
  prefix,
  startsExpr
}),
_void: createKeyword("void", {
  beforeExpr,
  prefix,
  startsExpr
}),
_delete: createKeyword("delete", {
  beforeExpr,
  prefix,
  startsExpr
})

};

const SCOPE_OTHER = 0b0000000000,

SCOPE_PROGRAM = 0b0000000001,
SCOPE_FUNCTION = 0b0000000010,
SCOPE_ASYNC = 0b0000000100,
SCOPE_GENERATOR = 0b0000001000,
SCOPE_ARROW = 0b0000010000,
SCOPE_SIMPLE_CATCH = 0b0000100000,
SCOPE_SUPER = 0b0001000000,
SCOPE_DIRECT_SUPER = 0b0010000000,
SCOPE_CLASS = 0b0100000000,
SCOPE_TS_MODULE = 0b1000000000,
SCOPE_VAR = SCOPE_PROGRAM | SCOPE_FUNCTION | SCOPE_TS_MODULE;

function functionFlags(isAsync, isGenerator) {

return SCOPE_FUNCTION | (isAsync ? SCOPE_ASYNC : 0) | (isGenerator ? SCOPE_GENERATOR : 0);

} const BIND_KIND_VALUE = 0b00000000001,

BIND_KIND_TYPE = 0b00000000010,
BIND_SCOPE_VAR = 0b00000000100,
BIND_SCOPE_LEXICAL = 0b00000001000,
BIND_SCOPE_FUNCTION = 0b00000010000,
BIND_FLAGS_NONE = 0b00001000000,
BIND_FLAGS_CLASS = 0b00010000000,
BIND_FLAGS_TS_ENUM = 0b00100000000,
BIND_FLAGS_TS_CONST_ENUM = 0b01000000000,
BIND_FLAGS_TS_EXPORT_ONLY = 0b10000000000;

const BIND_CLASS = BIND_KIND_VALUE | BIND_KIND_TYPE | BIND_SCOPE_LEXICAL | BIND_FLAGS_CLASS,

BIND_LEXICAL = BIND_KIND_VALUE | 0 | BIND_SCOPE_LEXICAL | 0,
BIND_VAR = BIND_KIND_VALUE | 0 | BIND_SCOPE_VAR | 0,
BIND_FUNCTION = BIND_KIND_VALUE | 0 | BIND_SCOPE_FUNCTION | 0,
BIND_TS_INTERFACE = 0 | BIND_KIND_TYPE | 0 | BIND_FLAGS_CLASS,
BIND_TS_TYPE = 0 | BIND_KIND_TYPE | 0 | 0,
BIND_TS_ENUM = BIND_KIND_VALUE | BIND_KIND_TYPE | BIND_SCOPE_LEXICAL | BIND_FLAGS_TS_ENUM,
BIND_TS_AMBIENT = 0 | 0 | 0 | BIND_FLAGS_TS_EXPORT_ONLY,
BIND_NONE = 0 | 0 | 0 | BIND_FLAGS_NONE,
BIND_OUTSIDE = BIND_KIND_VALUE | 0 | 0 | BIND_FLAGS_NONE,
BIND_TS_CONST_ENUM = BIND_TS_ENUM | BIND_FLAGS_TS_CONST_ENUM,
BIND_TS_NAMESPACE = 0 | 0 | 0 | BIND_FLAGS_TS_EXPORT_ONLY;

function isSimpleProperty(node) {

return node != null && node.type === "Property" && node.kind === "init" && node.method === false;

}

var estree = (superClass => class extends superClass {

estreeParseRegExpLiteral({
  pattern,
  flags
}) {
  let regex = null;

  try {
    regex = new RegExp(pattern, flags);
  } catch (e) {}

  const node = this.estreeParseLiteral(regex);
  node.regex = {
    pattern,
    flags
  };
  return node;
}

estreeParseLiteral(value) {
  return this.parseLiteral(value, "Literal");
}

directiveToStmt(directive) {
  const directiveLiteral = directive.value;
  const stmt = this.startNodeAt(directive.start, directive.loc.start);
  const expression = this.startNodeAt(directiveLiteral.start, directiveLiteral.loc.start);
  expression.value = directiveLiteral.value;
  expression.raw = directiveLiteral.extra.raw;
  stmt.expression = this.finishNodeAt(expression, "Literal", directiveLiteral.end, directiveLiteral.loc.end);
  stmt.directive = directiveLiteral.extra.raw.slice(1, -1);
  return this.finishNodeAt(stmt, "ExpressionStatement", directive.end, directive.loc.end);
}

initFunction(node, isAsync) {
  super.initFunction(node, isAsync);
  node.expression = false;
}

checkDeclaration(node) {
  if (isSimpleProperty(node)) {
    this.checkDeclaration(node.value);
  } else {
    super.checkDeclaration(node);
  }
}

checkGetterSetterParams(method) {
  const prop = method;
  const paramCount = prop.kind === "get" ? 0 : 1;
  const start = prop.start;

  if (prop.value.params.length !== paramCount) {
    if (prop.kind === "get") {
      this.raise(start, "getter must not have any formal parameters");
    } else {
      this.raise(start, "setter must have exactly one formal parameter");
    }
  }

  if (prop.kind === "set" && prop.value.params[0].type === "RestElement") {
    this.raise(start, "setter function argument must not be a rest parameter");
  }
}

checkLVal(expr, bindingType = BIND_NONE, checkClashes, contextDescription) {
  switch (expr.type) {
    case "ObjectPattern":
      expr.properties.forEach(prop => {
        this.checkLVal(prop.type === "Property" ? prop.value : prop, bindingType, checkClashes, "object destructuring pattern");
      });
      break;

    default:
      super.checkLVal(expr, bindingType, checkClashes, contextDescription);
  }
}

checkPropClash(prop, propHash) {
  if (prop.type === "SpreadElement" || prop.computed || prop.method || prop.shorthand) {
    return;
  }

  const key = prop.key;
  const name = key.type === "Identifier" ? key.name : String(key.value);

  if (name === "__proto__" && prop.kind === "init") {
    if (propHash.proto) {
      this.raise(key.start, "Redefinition of __proto__ property");
    }

    propHash.proto = true;
  }
}

isStrictBody(node) {
  const isBlockStatement = node.body.type === "BlockStatement";

  if (isBlockStatement && node.body.body.length > 0) {
    for (let _i = 0, _node$body$body = node.body.body; _i < _node$body$body.length; _i++) {
      const directive = _node$body$body[_i];

      if (directive.type === "ExpressionStatement" && directive.expression.type === "Literal") {
        if (directive.expression.value === "use strict") return true;
      } else {
        break;
      }
    }
  }

  return false;
}

isValidDirective(stmt) {
  return stmt.type === "ExpressionStatement" && stmt.expression.type === "Literal" && typeof stmt.expression.value === "string" && (!stmt.expression.extra || !stmt.expression.extra.parenthesized);
}

stmtToDirective(stmt) {
  const directive = super.stmtToDirective(stmt);
  const value = stmt.expression.value;
  directive.value.value = value;
  return directive;
}

parseBlockBody(node, allowDirectives, topLevel, end) {
  super.parseBlockBody(node, allowDirectives, topLevel, end);
  const directiveStatements = node.directives.map(d => this.directiveToStmt(d));
  node.body = directiveStatements.concat(node.body);
  delete node.directives;
}

pushClassMethod(classBody, method, isGenerator, isAsync, isConstructor, allowsDirectSuper) {
  this.parseMethod(method, isGenerator, isAsync, isConstructor, allowsDirectSuper, "ClassMethod", true);

  if (method.typeParameters) {
    method.value.typeParameters = method.typeParameters;
    delete method.typeParameters;
  }

  classBody.body.push(method);
}

parseExprAtom(refShorthandDefaultPos) {
  switch (this.state.type) {
    case types.regexp:
      return this.estreeParseRegExpLiteral(this.state.value);

    case types.num:
    case types.string:
      return this.estreeParseLiteral(this.state.value);

    case types._null:
      return this.estreeParseLiteral(null);

    case types._true:
      return this.estreeParseLiteral(true);

    case types._false:
      return this.estreeParseLiteral(false);

    default:
      return super.parseExprAtom(refShorthandDefaultPos);
  }
}

parseLiteral(value, type, startPos, startLoc) {
  const node = super.parseLiteral(value, type, startPos, startLoc);
  node.raw = node.extra.raw;
  delete node.extra;
  return node;
}

parseFunctionBody(node, allowExpression, isMethod = false) {
  super.parseFunctionBody(node, allowExpression, isMethod);
  node.expression = node.body.type !== "BlockStatement";
}

parseMethod(node, isGenerator, isAsync, isConstructor, allowDirectSuper, type, inClassScope = false) {
  let funcNode = this.startNode();
  funcNode.kind = node.kind;
  funcNode = super.parseMethod(funcNode, isGenerator, isAsync, isConstructor, allowDirectSuper, type, inClassScope);
  funcNode.type = "FunctionExpression";
  delete funcNode.kind;
  node.value = funcNode;
  type = type === "ClassMethod" ? "MethodDefinition" : type;
  return this.finishNode(node, type);
}

parseObjectMethod(prop, isGenerator, isAsync, isPattern, containsEsc) {
  const node = super.parseObjectMethod(prop, isGenerator, isAsync, isPattern, containsEsc);

  if (node) {
    node.type = "Property";
    if (node.kind === "method") node.kind = "init";
    node.shorthand = false;
  }

  return node;
}

parseObjectProperty(prop, startPos, startLoc, isPattern, refShorthandDefaultPos) {
  const node = super.parseObjectProperty(prop, startPos, startLoc, isPattern, refShorthandDefaultPos);

  if (node) {
    node.kind = "init";
    node.type = "Property";
  }

  return node;
}

toAssignable(node, isBinding, contextDescription) {
  if (isSimpleProperty(node)) {
    this.toAssignable(node.value, isBinding, contextDescription);
    return node;
  }

  return super.toAssignable(node, isBinding, contextDescription);
}

toAssignableObjectExpressionProp(prop, isBinding, isLast) {
  if (prop.kind === "get" || prop.kind === "set") {
    this.raise(prop.key.start, "Object pattern can't contain getter or setter");
  } else if (prop.method) {
    this.raise(prop.key.start, "Object pattern can't contain methods");
  } else {
    super.toAssignableObjectExpressionProp(prop, isBinding, isLast);
  }
}

});

const lineBreak = /rn?|/; const lineBreakG = new RegExp(lineBreak.source, “g”); function isNewLine(code) {

switch (code) {
  case 10:
  case 13:
  case 8232:
  case 8233:
    return true;

  default:
    return false;
}

} const skipWhiteSpace = /(?:s|//.*|/**?*/)*/g; function isWhitespace(code) {

switch (code) {
  case 0x0009:
  case 0x000b:
  case 0x000c:
  case 32:
  case 160:
  case 5760:
  case 0x2000:
  case 0x2001:
  case 0x2002:
  case 0x2003:
  case 0x2004:
  case 0x2005:
  case 0x2006:
  case 0x2007:
  case 0x2008:
  case 0x2009:
  case 0x200a:
  case 0x202f:
  case 0x205f:
  case 0x3000:
  case 0xfeff:
    return true;

  default:
    return false;
}

}

class TokContext {

constructor(token, isExpr, preserveSpace, override) {
  this.token = token;
  this.isExpr = !!isExpr;
  this.preserveSpace = !!preserveSpace;
  this.override = override;
}

} const types$1 = {

braceStatement: new TokContext("{", false),
braceExpression: new TokContext("{", true),
templateQuasi: new TokContext("${", false),
parenStatement: new TokContext("(", false),
parenExpression: new TokContext("(", true),
template: new TokContext("`", true, true, p => p.readTmplToken()),
functionExpression: new TokContext("function", true),
functionStatement: new TokContext("function", false)

};

types.parenR.updateContext = types.braceR.updateContext = function () {

if (this.state.context.length === 1) {
  this.state.exprAllowed = true;
  return;
}

let out = this.state.context.pop();

if (out === types$1.braceStatement && this.curContext().token === "function") {
  out = this.state.context.pop();
}

this.state.exprAllowed = !out.isExpr;

};

types.name.updateContext = function (prevType) {

let allowed = false;

if (prevType !== types.dot) {
  if (this.state.value === "of" && !this.state.exprAllowed || this.state.value === "yield" && this.scope.inGenerator) {
    allowed = true;
  }
}

this.state.exprAllowed = allowed;

if (this.state.isIterator) {
  this.state.isIterator = false;
}

};

types.braceL.updateContext = function (prevType) {

this.state.context.push(this.braceIsBlock(prevType) ? types$1.braceStatement : types$1.braceExpression);
this.state.exprAllowed = true;

};

types.dollarBraceL.updateContext = function () {

this.state.context.push(types$1.templateQuasi);
this.state.exprAllowed = true;

};

types.parenL.updateContext = function (prevType) {

const statementParens = prevType === types._if || prevType === types._for || prevType === types._with || prevType === types._while;
this.state.context.push(statementParens ? types$1.parenStatement : types$1.parenExpression);
this.state.exprAllowed = true;

};

types.incDec.updateContext = function () {};

types._function.updateContext = types._class.updateContext = function (prevType) {

if (prevType.beforeExpr && prevType !== types.semi && prevType !== types._else && !(prevType === types._return && lineBreak.test(this.input.slice(this.state.lastTokEnd, this.state.start))) && !((prevType === types.colon || prevType === types.braceL) && this.curContext() === types$1.b_stat)) {
  this.state.context.push(types$1.functionExpression);
} else {
  this.state.context.push(types$1.functionStatement);
}

this.state.exprAllowed = false;

};

types.backQuote.updateContext = function () {

if (this.curContext() === types$1.template) {
  this.state.context.pop();
} else {
  this.state.context.push(types$1.template);
}

this.state.exprAllowed = false;

};

const reservedWords = {

strict: ["implements", "interface", "let", "package", "private", "protected", "public", "static", "yield"],
strictBind: ["eval", "arguments"]

}; const reservedWordsStrictSet = new Set(reservedWords.strict); const reservedWordsStrictBindSet = new Set(reservedWords.strict.concat(reservedWords.strictBind)); const isReservedWord = (word, inModule) => {

return inModule && word === "await" || word === "enum";

}; function isStrictReservedWord(word, inModule) {

return isReservedWord(word, inModule) || reservedWordsStrictSet.has(word);

} function isStrictBindReservedWord(word, inModule) {

return isReservedWord(word, inModule) || reservedWordsStrictBindSet.has(word);

} function isKeyword(word) {

return keywords.has(word);

} const keywordRelationalOperator = /^in(stanceof)?$/; let nonASCIIidentifierStartChars = “xaaxb5xbaxc0-xd6xd8-xf6xf8-u02c1u02c6-u02d1u02e0-u02e4u02ecu02eeu0370-u0374u0376u0377u037a-u037du037fu0386u0388-u038au038cu038e-u03a1u03a3-u03f5u03f7-u0481u048a-u052fu0531-u0556u0559u0560-u0588u05d0-u05eau05ef-u05f2u0620-u064au066eu066fu0671-u06d3u06d5u06e5u06e6u06eeu06efu06fa-u06fcu06ffu0710u0712-u072fu074d-u07a5u07b1u07ca-u07eau07f4u07f5u07fau0800-u0815u081au0824u0828u0840-u0858u0860-u086au08a0-u08b4u08b6-u08bdu0904-u0939u093du0950u0958-u0961u0971-u0980u0985-u098cu098fu0990u0993-u09a8u09aa-u09b0u09b2u09b6-u09b9u09bdu09ceu09dcu09ddu09df-u09e1u09f0u09f1u09fcu0a05-u0a0au0a0fu0a10u0a13-u0a28u0a2a-u0a30u0a32u0a33u0a35u0a36u0a38u0a39u0a59-u0a5cu0a5eu0a72-u0a74u0a85-u0a8du0a8f-u0a91u0a93-u0aa8u0aaa-u0ab0u0ab2u0ab3u0ab5-u0ab9u0abdu0ad0u0ae0u0ae1u0af9u0b05-u0b0cu0b0fu0b10u0b13-u0b28u0b2a-u0b30u0b32u0b33u0b35-u0b39u0b3du0b5cu0b5du0b5f-u0b61u0b71u0b83u0b85-u0b8au0b8e-u0b90u0b92-u0b95u0b99u0b9au0b9cu0b9eu0b9fu0ba3u0ba4u0ba8-u0baau0bae-u0bb9u0bd0u0c05-u0c0cu0c0e-u0c10u0c12-u0c28u0c2a-u0c39u0c3du0c58-u0c5au0c60u0c61u0c80u0c85-u0c8cu0c8e-u0c90u0c92-u0ca8u0caa-u0cb3u0cb5-u0cb9u0cbdu0cdeu0ce0u0ce1u0cf1u0cf2u0d05-u0d0cu0d0e-u0d10u0d12-u0d3au0d3du0d4eu0d54-u0d56u0d5f-u0d61u0d7a-u0d7fu0d85-u0d96u0d9a-u0db1u0db3-u0dbbu0dbdu0dc0-u0dc6u0e01-u0e30u0e32u0e33u0e40-u0e46u0e81u0e82u0e84u0e86-u0e8au0e8c-u0ea3u0ea5u0ea7-u0eb0u0eb2u0eb3u0ebdu0ec0-u0ec4u0ec6u0edc-u0edfu0f00u0f40-u0f47u0f49-u0f6cu0f88-u0f8cu1000-u102au103fu1050-u1055u105a-u105du1061u1065u1066u106e-u1070u1075-u1081u108eu10a0-u10c5u10c7u10cdu10d0-u10fau10fc-u1248u124a-u124du1250-u1256u1258u125a-u125du1260-u1288u128a-u128du1290-u12b0u12b2-u12b5u12b8-u12beu12c0u12c2-u12c5u12c8-u12d6u12d8-u1310u1312-u1315u1318-u135au1380-u138fu13a0-u13f5u13f8-u13fdu1401-u166cu166f-u167fu1681-u169au16a0-u16eau16ee-u16f8u1700-u170cu170e-u1711u1720-u1731u1740-u1751u1760-u176cu176e-u1770u1780-u17b3u17d7u17dcu1820-u1878u1880-u18a8u18aau18b0-u18f5u1900-u191eu1950-u196du1970-u1974u1980-u19abu19b0-u19c9u1a00-u1a16u1a20-u1a54u1aa7u1b05-u1b33u1b45-u1b4bu1b83-u1ba0u1baeu1bafu1bba-u1be5u1c00-u1c23u1c4d-u1c4fu1c5a-u1c7du1c80-u1c88u1c90-u1cbau1cbd-u1cbfu1ce9-u1cecu1cee-u1cf3u1cf5u1cf6u1cfau1d00-u1dbfu1e00-u1f15u1f18-u1f1du1f20-u1f45u1f48-u1f4du1f50-u1f57u1f59u1f5bu1f5du1f5f-u1f7du1f80-u1fb4u1fb6-u1fbcu1fbeu1fc2-u1fc4u1fc6-u1fccu1fd0-u1fd3u1fd6-u1fdbu1fe0-u1fecu1ff2-u1ff4u1ff6-u1ffcu2071u207fu2090-u209cu2102u2107u210a-u2113u2115u2118-u211du2124u2126u2128u212a-u2139u213c-u213fu2145-u2149u214eu2160-u2188u2c00-u2c2eu2c30-u2c5eu2c60-u2ce4u2ceb-u2ceeu2cf2u2cf3u2d00-u2d25u2d27u2d2du2d30-u2d67u2d6fu2d80-u2d96u2da0-u2da6u2da8-u2daeu2db0-u2db6u2db8-u2dbeu2dc0-u2dc6u2dc8-u2dceu2dd0-u2dd6u2dd8-u2ddeu3005-u3007u3021-u3029u3031-u3035u3038-u303cu3041-u3096u309b-u309fu30a1-u30fau30fc-u30ffu3105-u312fu3131-u318eu31a0-u31bau31f0-u31ffu3400-u4db5u4e00-u9fefua000-ua48cua4d0-ua4fdua500-ua60cua610-ua61fua62aua62bua640-ua66eua67f-ua69dua6a0-ua6efua717-ua71fua722-ua788ua78b-ua7bfua7c2-ua7c6ua7f7-ua801ua803-ua805ua807-ua80aua80c-ua822ua840-ua873ua882-ua8b3ua8f2-ua8f7ua8fbua8fdua8feua90a-ua925ua930-ua946ua960-ua97cua984-ua9b2ua9cfua9e0-ua9e4ua9e6-ua9efua9fa-ua9feuaa00-uaa28uaa40-uaa42uaa44-uaa4buaa60-uaa76uaa7auaa7e-uaaafuaab1uaab5uaab6uaab9-uaabduaac0uaac2uaadb-uaadduaae0-uaaeauaaf2-uaaf4uab01-uab06uab09-uab0euab11-uab16uab20-uab26uab28-uab2euab30-uab5auab5c-uab67uab70-uabe2uac00-ud7a3ud7b0-ud7c6ud7cb-ud7fbuf900-ufa6dufa70-ufad9ufb00-ufb06ufb13-ufb17ufb1dufb1f-ufb28ufb2a-ufb36ufb38-ufb3cufb3eufb40ufb41ufb43ufb44ufb46-ufbb1ufbd3-ufd3dufd50-ufd8fufd92-ufdc7ufdf0-ufdfbufe70-ufe74ufe76-ufefcuff21-uff3auff41-uff5auff66-uffbeuffc2-uffc7uffca-uffcfuffd2-uffd7uffda-uffdc”; let nonASCIIidentifierChars = “u200cu200dxb7u0300-u036fu0387u0483-u0487u0591-u05bdu05bfu05c1u05c2u05c4u05c5u05c7u0610-u061au064b-u0669u0670u06d6-u06dcu06df-u06e4u06e7u06e8u06ea-u06edu06f0-u06f9u0711u0730-u074au07a6-u07b0u07c0-u07c9u07eb-u07f3u07fdu0816-u0819u081b-u0823u0825-u0827u0829-u082du0859-u085bu08d3-u08e1u08e3-u0903u093a-u093cu093e-u094fu0951-u0957u0962u0963u0966-u096fu0981-u0983u09bcu09be-u09c4u09c7u09c8u09cb-u09cdu09d7u09e2u09e3u09e6-u09efu09feu0a01-u0a03u0a3cu0a3e-u0a42u0a47u0a48u0a4b-u0a4du0a51u0a66-u0a71u0a75u0a81-u0a83u0abcu0abe-u0ac5u0ac7-u0ac9u0acb-u0acdu0ae2u0ae3u0ae6-u0aefu0afa-u0affu0b01-u0b03u0b3cu0b3e-u0b44u0b47u0b48u0b4b-u0b4du0b56u0b57u0b62u0b63u0b66-u0b6fu0b82u0bbe-u0bc2u0bc6-u0bc8u0bca-u0bcdu0bd7u0be6-u0befu0c00-u0c04u0c3e-u0c44u0c46-u0c48u0c4a-u0c4du0c55u0c56u0c62u0c63u0c66-u0c6fu0c81-u0c83u0cbcu0cbe-u0cc4u0cc6-u0cc8u0cca-u0ccdu0cd5u0cd6u0ce2u0ce3u0ce6-u0cefu0d00-u0d03u0d3bu0d3cu0d3e-u0d44u0d46-u0d48u0d4a-u0d4du0d57u0d62u0d63u0d66-u0d6fu0d82u0d83u0dcau0dcf-u0dd4u0dd6u0dd8-u0ddfu0de6-u0defu0df2u0df3u0e31u0e34-u0e3au0e47-u0e4eu0e50-u0e59u0eb1u0eb4-u0ebcu0ec8-u0ecdu0ed0-u0ed9u0f18u0f19u0f20-u0f29u0f35u0f37u0f39u0f3eu0f3fu0f71-u0f84u0f86u0f87u0f8d-u0f97u0f99-u0fbcu0fc6u102b-u103eu1040-u1049u1056-u1059u105e-u1060u1062-u1064u1067-u106du1071-u1074u1082-u108du108f-u109du135d-u135fu1369-u1371u1712-u1714u1732-u1734u1752u1753u1772u1773u17b4-u17d3u17ddu17e0-u17e9u180b-u180du1810-u1819u18a9u1920-u192bu1930-u193bu1946-u194fu19d0-u19dau1a17-u1a1bu1a55-u1a5eu1a60-u1a7cu1a7f-u1a89u1a90-u1a99u1ab0-u1abdu1b00-u1b04u1b34-u1b44u1b50-u1b59u1b6b-u1b73u1b80-u1b82u1ba1-u1badu1bb0-u1bb9u1be6-u1bf3u1c24-u1c37u1c40-u1c49u1c50-u1c59u1cd0-u1cd2u1cd4-u1ce8u1cedu1cf4u1cf7-u1cf9u1dc0-u1df9u1dfb-u1dffu203fu2040u2054u20d0-u20dcu20e1u20e5-u20f0u2cef-u2cf1u2d7fu2de0-u2dffu302a-u302fu3099u309aua620-ua629ua66fua674-ua67dua69eua69fua6f0ua6f1ua802ua806ua80bua823-ua827ua880ua881ua8b4-ua8c5ua8d0-ua8d9ua8e0-ua8f1ua8ff-ua909ua926-ua92dua947-ua953ua980-ua983ua9b3-ua9c0ua9d0-ua9d9ua9e5ua9f0-ua9f9uaa29-uaa36uaa43uaa4cuaa4duaa50-uaa59uaa7b-uaa7duaab0uaab2-uaab4uaab7uaab8uaabeuaabfuaac1uaaeb-uaaefuaaf5uaaf6uabe3-uabeauabecuabeduabf0-uabf9ufb1eufe00-ufe0fufe20-ufe2fufe33ufe34ufe4d-ufe4fuff10-uff19uff3f”; const nonASCIIidentifierStart = new RegExp(“[” + nonASCIIidentifierStartChars + “]”); const nonASCIIidentifier = new RegExp(“[” + nonASCIIidentifierStartChars + nonASCIIidentifierChars + “]”); nonASCIIidentifierStartChars = nonASCIIidentifierChars = null; const astralIdentifierStartCodes = [0, 11, 2, 25, 2, 18, 2, 1, 2, 14, 3, 13, 35, 122, 70, 52, 268, 28, 4, 48, 48, 31, 14, 29, 6, 37, 11, 29, 3, 35, 5, 7, 2, 4, 43, 157, 19, 35, 5, 35, 5, 39, 9, 51, 157, 310, 10, 21, 11, 7, 153, 5, 3, 0, 2, 43, 2, 1, 4, 0, 3, 22, 11, 22, 10, 30, 66, 18, 2, 1, 11, 21, 11, 25, 71, 55, 7, 1, 65, 0, 16, 3, 2, 2, 2, 28, 43, 28, 4, 28, 36, 7, 2, 27, 28, 53, 11, 21, 11, 18, 14, 17, 111, 72, 56, 50, 14, 50, 14, 35, 477, 28, 11, 0, 9, 21, 155, 22, 13, 52, 76, 44, 33, 24, 27, 35, 30, 0, 12, 34, 4, 0, 13, 47, 15, 3, 22, 0, 2, 0, 36, 17, 2, 24, 85, 6, 2, 0, 2, 3, 2, 14, 2, 9, 8, 46, 39, 7, 3, 1, 3, 21, 2, 6, 2, 1, 2, 4, 4, 0, 19, 0, 13, 4, 159, 52, 19, 3, 21, 0, 33, 47, 21, 1, 2, 0, 185, 46, 42, 3, 37, 47, 21, 0, 60, 42, 14, 0, 72, 26, 230, 43, 117, 63, 32, 0, 161, 7, 3, 38, 17, 0, 2, 0, 29, 0, 11, 39, 8, 0, 22, 0, 12, 45, 20, 0, 35, 56, 264, 8, 2, 36, 18, 0, 50, 29, 113, 6, 2, 1, 2, 37, 22, 0, 26, 5, 2, 1, 2, 31, 15, 0, 328, 18, 270, 921, 103, 110, 18, 195, 2749, 1070, 4050, 582, 8634, 568, 8, 30, 114, 29, 19, 47, 17, 3, 32, 20, 6, 18, 689, 63, 129, 74, 6, 0, 67, 12, 65, 1, 2, 0, 29, 6135, 9, 754, 9486, 286, 50, 2, 18, 3, 9, 395, 2309, 106, 6, 12, 4, 8, 8, 9, 5991, 84, 2, 70, 2, 1, 3, 0, 3, 1, 3, 3, 2, 11, 2, 0, 2, 6, 2, 64, 2, 3, 3, 7, 2, 6, 2, 27, 2, 3, 2, 4, 2, 0, 4, 6, 2, 339, 3, 24, 2, 24, 2, 30, 2, 24, 2, 30, 2, 24, 2, 30, 2, 24, 2, 30, 2, 24, 2, 7, 2357, 44, 11, 6, 17, 0, 370, 43, 1301, 196, 60, 67, 8, 0, 1205, 3, 2, 26, 2, 1, 2, 0, 3, 0, 2, 9, 2, 3, 2, 0, 2, 0, 7, 0, 5, 0, 2, 0, 2, 0, 2, 2, 2, 1, 2, 0, 3, 0, 2, 0, 2, 0, 2, 0, 2, 0, 2, 1, 2, 0, 3, 3, 2, 6, 2, 3, 2, 3, 2, 0, 2, 9, 2, 16, 6, 2, 2, 4, 2, 16, 4421, 42710, 42, 4148, 12, 221, 3, 5761, 15, 7472, 3104, 541]; const astralIdentifierCodes = [509, 0, 227, 0, 150, 4, 294, 9, 1368, 2, 2, 1, 6, 3, 41, 2, 5, 0, 166, 1, 574, 3, 9, 9, 525, 10, 176, 2, 54, 14, 32, 9, 16, 3, 46, 10, 54, 9, 7, 2, 37, 13, 2, 9, 6, 1, 45, 0, 13, 2, 49, 13, 9, 3, 4, 9, 83, 11, 7, 0, 161, 11, 6, 9, 7, 3, 56, 1, 2, 6, 3, 1, 3, 2, 10, 0, 11, 1, 3, 6, 4, 4, 193, 17, 10, 9, 5, 0, 82, 19, 13, 9, 214, 6, 3, 8, 28, 1, 83, 16, 16, 9, 82, 12, 9, 9, 84, 14, 5, 9, 243, 14, 166, 9, 232, 6, 3, 6, 4, 0, 29, 9, 41, 6, 2, 3, 9, 0, 10, 10, 47, 15, 406, 7, 2, 7, 17, 9, 57, 21, 2, 13, 123, 5, 4, 0, 2, 1, 2, 6, 2, 0, 9, 9, 49, 4, 2, 1, 2, 4, 9, 9, 330, 3, 19306, 9, 135, 4, 60, 6, 26, 9, 1014, 0, 2, 54, 8, 3, 19723, 1, 5319, 4, 4, 5, 9, 7, 3, 6, 31, 3, 149, 2, 1418, 49, 513, 54, 5, 49, 9, 0, 15, 0, 23, 4, 2, 14, 1361, 6, 2, 16, 3, 6, 2, 1, 2, 4, 262, 6, 10, 9, 419, 13, 1495, 6, 110, 6, 6, 9, 792487, 239];

function isInAstralSet(code, set) {

let pos = 0x10000;

for (let i = 0, length = set.length; i < length; i += 2) {
  pos += set[i];
  if (pos > code) return false;
  pos += set[i + 1];
  if (pos >= code) return true;
}

return false;

}

function isIdentifierStart(code) {

if (code < 65) return code === 36;
if (code <= 90) return true;
if (code < 97) return code === 95;
if (code <= 122) return true;

if (code <= 0xffff) {
  return code >= 0xaa && nonASCIIidentifierStart.test(String.fromCharCode(code));
}

return isInAstralSet(code, astralIdentifierStartCodes);

} function isIteratorStart(current, next) {

return current === 64 && next === 64;

} function isIdentifierChar(code) {

if (code < 48) return code === 36;
if (code < 58) return true;
if (code < 65) return false;
if (code <= 90) return true;
if (code < 97) return code === 95;
if (code <= 122) return true;

if (code <= 0xffff) {
  return code >= 0xaa && nonASCIIidentifier.test(String.fromCharCode(code));
}

return isInAstralSet(code, astralIdentifierStartCodes) || isInAstralSet(code, astralIdentifierCodes);

}

const reservedTypes = [“any”, “bool”, “boolean”, “empty”, “false”, “mixed”, “null”, “number”, “static”, “string”, “true”, “typeof”, “void”, “interface”, “extends”, “_”];

function isEsModuleType(bodyElement) {

return bodyElement.type === "DeclareExportAllDeclaration" || bodyElement.type === "DeclareExportDeclaration" && (!bodyElement.declaration || bodyElement.declaration.type !== "TypeAlias" && bodyElement.declaration.type !== "InterfaceDeclaration");

}

function hasTypeImportKind(node) {

return node.importKind === "type" || node.importKind === "typeof";

}

function isMaybeDefaultImport(state) {

return (state.type === types.name || !!state.type.keyword) && state.value !== "from";

}

const exportSuggestions = {

const: "declare export var",
let: "declare export var",
type: "export type",
interface: "export interface"

};

function partition(list, test) {

const list1 = [];
const list2 = [];

for (let i = 0; i < list.length; i++) {
  (test(list[i], i, list) ? list1 : list2).push(list[i]);
}

return [list1, list2];

}

const FLOW_PRAGMA_REGEX = /*?s*@((?:no)?flow)b/; var flow = (superClass => class extends superClass {

constructor(options, input) {
  super(options, input);
  this.flowPragma = undefined;
}

shouldParseTypes() {
  return this.getPluginOption("flow", "all") || this.flowPragma === "flow";
}

finishToken(type, val) {
  if (type !== types.string && type !== types.semi && type !== types.interpreterDirective) {
    if (this.flowPragma === undefined) {
      this.flowPragma = null;
    }
  }

  return super.finishToken(type, val);
}

addComment(comment) {
  if (this.flowPragma === undefined) {
    const matches = FLOW_PRAGMA_REGEX.exec(comment.value);

    if (!matches) ; else if (matches[1] === "flow") {
      this.flowPragma = "flow";
    } else if (matches[1] === "noflow") {
      this.flowPragma = "noflow";
    } else {
      throw new Error("Unexpected flow pragma");
    }
  }

  return super.addComment(comment);
}

flowParseTypeInitialiser(tok) {
  const oldInType = this.state.inType;
  this.state.inType = true;
  this.expect(tok || types.colon);
  const type = this.flowParseType();
  this.state.inType = oldInType;
  return type;
}

flowParsePredicate() {
  const node = this.startNode();
  const moduloLoc = this.state.startLoc;
  const moduloPos = this.state.start;
  this.expect(types.modulo);
  const checksLoc = this.state.startLoc;
  this.expectContextual("checks");

  if (moduloLoc.line !== checksLoc.line || moduloLoc.column !== checksLoc.column - 1) {
    this.raise(moduloPos, "Spaces between ´%´ and ´checks´ are not allowed here.");
  }

  if (this.eat(types.parenL)) {
    node.value = this.parseExpression();
    this.expect(types.parenR);
    return this.finishNode(node, "DeclaredPredicate");
  } else {
    return this.finishNode(node, "InferredPredicate");
  }
}

flowParseTypeAndPredicateInitialiser() {
  const oldInType = this.state.inType;
  this.state.inType = true;
  this.expect(types.colon);
  let type = null;
  let predicate = null;

  if (this.match(types.modulo)) {
    this.state.inType = oldInType;
    predicate = this.flowParsePredicate();
  } else {
    type = this.flowParseType();
    this.state.inType = oldInType;

    if (this.match(types.modulo)) {
      predicate = this.flowParsePredicate();
    }
  }

  return [type, predicate];
}

flowParseDeclareClass(node) {
  this.next();
  this.flowParseInterfaceish(node, true);
  return this.finishNode(node, "DeclareClass");
}

flowParseDeclareFunction(node) {
  this.next();
  const id = node.id = this.parseIdentifier();
  const typeNode = this.startNode();
  const typeContainer = this.startNode();

  if (this.isRelational("<")) {
    typeNode.typeParameters = this.flowParseTypeParameterDeclaration();
  } else {
    typeNode.typeParameters = null;
  }

  this.expect(types.parenL);
  const tmp = this.flowParseFunctionTypeParams();
  typeNode.params = tmp.params;
  typeNode.rest = tmp.rest;
  this.expect(types.parenR);
  [typeNode.returnType, node.predicate] = this.flowParseTypeAndPredicateInitialiser();
  typeContainer.typeAnnotation = this.finishNode(typeNode, "FunctionTypeAnnotation");
  id.typeAnnotation = this.finishNode(typeContainer, "TypeAnnotation");
  this.resetEndLocation(id);
  this.semicolon();
  return this.finishNode(node, "DeclareFunction");
}

flowParseDeclare(node, insideModule) {
  if (this.match(types._class)) {
    return this.flowParseDeclareClass(node);
  } else if (this.match(types._function)) {
    return this.flowParseDeclareFunction(node);
  } else if (this.match(types._var)) {
    return this.flowParseDeclareVariable(node);
  } else if (this.eatContextual("module")) {
    if (this.match(types.dot)) {
      return this.flowParseDeclareModuleExports(node);
    } else {
      if (insideModule) {
        this.unexpected(this.state.lastTokStart, "`declare module` cannot be used inside another `declare module`");
      }

      return this.flowParseDeclareModule(node);
    }
  } else if (this.isContextual("type")) {
    return this.flowParseDeclareTypeAlias(node);
  } else if (this.isContextual("opaque")) {
    return this.flowParseDeclareOpaqueType(node);
  } else if (this.isContextual("interface")) {
    return this.flowParseDeclareInterface(node);
  } else if (this.match(types._export)) {
    return this.flowParseDeclareExportDeclaration(node, insideModule);
  } else {
    throw this.unexpected();
  }
}

flowParseDeclareVariable(node) {
  this.next();
  node.id = this.flowParseTypeAnnotatableIdentifier(true);
  this.scope.declareName(node.id.name, BIND_VAR, node.id.start);
  this.semicolon();
  return this.finishNode(node, "DeclareVariable");
}

flowParseDeclareModule(node) {
  this.scope.enter(SCOPE_OTHER);

  if (this.match(types.string)) {
    node.id = this.parseExprAtom();
  } else {
    node.id = this.parseIdentifier();
  }

  const bodyNode = node.body = this.startNode();
  const body = bodyNode.body = [];
  this.expect(types.braceL);

  while (!this.match(types.braceR)) {
    let bodyNode = this.startNode();

    if (this.match(types._import)) {
      this.next();

      if (!this.isContextual("type") && !this.match(types._typeof)) {
        this.unexpected(this.state.lastTokStart, "Imports within a `declare module` body must always be `import type` or `import typeof`");
      }

      this.parseImport(bodyNode);
    } else {
      this.expectContextual("declare", "Only declares and type imports are allowed inside declare module");
      bodyNode = this.flowParseDeclare(bodyNode, true);
    }

    body.push(bodyNode);
  }

  this.scope.exit();
  this.expect(types.braceR);
  this.finishNode(bodyNode, "BlockStatement");
  let kind = null;
  let hasModuleExport = false;
  const errorMessage = "Found both `declare module.exports` and `declare export` in the same module. " + "Modules can only have 1 since they are either an ES module or they are a CommonJS module";
  body.forEach(bodyElement => {
    if (isEsModuleType(bodyElement)) {
      if (kind === "CommonJS") {
        this.unexpected(bodyElement.start, errorMessage);
      }

      kind = "ES";
    } else if (bodyElement.type === "DeclareModuleExports") {
      if (hasModuleExport) {
        this.unexpected(bodyElement.start, "Duplicate `declare module.exports` statement");
      }

      if (kind === "ES") this.unexpected(bodyElement.start, errorMessage);
      kind = "CommonJS";
      hasModuleExport = true;
    }
  });
  node.kind = kind || "CommonJS";
  return this.finishNode(node, "DeclareModule");
}

flowParseDeclareExportDeclaration(node, insideModule) {
  this.expect(types._export);

  if (this.eat(types._default)) {
    if (this.match(types._function) || this.match(types._class)) {
      node.declaration = this.flowParseDeclare(this.startNode());
    } else {
      node.declaration = this.flowParseType();
      this.semicolon();
    }

    node.default = true;
    return this.finishNode(node, "DeclareExportDeclaration");
  } else {
    if (this.match(types._const) || this.isLet() || (this.isContextual("type") || this.isContextual("interface")) && !insideModule) {
      const label = this.state.value;
      const suggestion = exportSuggestions[label];
      this.unexpected(this.state.start, `\`declare export ${label}\` is not supported. Use \`${suggestion}\` instead`);
    }

    if (this.match(types._var) || this.match(types._function) || this.match(types._class) || this.isContextual("opaque")) {
      node.declaration = this.flowParseDeclare(this.startNode());
      node.default = false;
      return this.finishNode(node, "DeclareExportDeclaration");
    } else if (this.match(types.star) || this.match(types.braceL) || this.isContextual("interface") || this.isContextual("type") || this.isContextual("opaque")) {
      node = this.parseExport(node);

      if (node.type === "ExportNamedDeclaration") {
        node.type = "ExportDeclaration";
        node.default = false;
        delete node.exportKind;
      }

      node.type = "Declare" + node.type;
      return node;
    }
  }

  throw this.unexpected();
}

flowParseDeclareModuleExports(node) {
  this.next();
  this.expectContextual("exports");
  node.typeAnnotation = this.flowParseTypeAnnotation();
  this.semicolon();
  return this.finishNode(node, "DeclareModuleExports");
}

flowParseDeclareTypeAlias(node) {
  this.next();
  this.flowParseTypeAlias(node);
  node.type = "DeclareTypeAlias";
  return node;
}

flowParseDeclareOpaqueType(node) {
  this.next();
  this.flowParseOpaqueType(node, true);
  node.type = "DeclareOpaqueType";
  return node;
}

flowParseDeclareInterface(node) {
  this.next();
  this.flowParseInterfaceish(node);
  return this.finishNode(node, "DeclareInterface");
}

flowParseInterfaceish(node, isClass = false) {
  node.id = this.flowParseRestrictedIdentifier(!isClass);
  this.scope.declareName(node.id.name, isClass ? BIND_FUNCTION : BIND_LEXICAL, node.id.start);

  if (this.isRelational("<")) {
    node.typeParameters = this.flowParseTypeParameterDeclaration();
  } else {
    node.typeParameters = null;
  }

  node.extends = [];
  node.implements = [];
  node.mixins = [];

  if (this.eat(types._extends)) {
    do {
      node.extends.push(this.flowParseInterfaceExtends());
    } while (!isClass && this.eat(types.comma));
  }

  if (this.isContextual("mixins")) {
    this.next();

    do {
      node.mixins.push(this.flowParseInterfaceExtends());
    } while (this.eat(types.comma));
  }

  if (this.isContextual("implements")) {
    this.next();

    do {
      node.implements.push(this.flowParseInterfaceExtends());
    } while (this.eat(types.comma));
  }

  node.body = this.flowParseObjectType({
    allowStatic: isClass,
    allowExact: false,
    allowSpread: false,
    allowProto: isClass,
    allowInexact: false
  });
}

flowParseInterfaceExtends() {
  const node = this.startNode();
  node.id = this.flowParseQualifiedTypeIdentifier();

  if (this.isRelational("<")) {
    node.typeParameters = this.flowParseTypeParameterInstantiation();
  } else {
    node.typeParameters = null;
  }

  return this.finishNode(node, "InterfaceExtends");
}

flowParseInterface(node) {
  this.flowParseInterfaceish(node);
  return this.finishNode(node, "InterfaceDeclaration");
}

checkNotUnderscore(word) {
  if (word === "_") {
    throw this.unexpected(null, "`_` is only allowed as a type argument to call or new");
  }
}

checkReservedType(word, startLoc) {
  if (reservedTypes.indexOf(word) > -1) {
    this.raise(startLoc, `Cannot overwrite reserved type ${word}`);
  }
}

flowParseRestrictedIdentifier(liberal) {
  this.checkReservedType(this.state.value, this.state.start);
  return this.parseIdentifier(liberal);
}

flowParseTypeAlias(node) {
  node.id = this.flowParseRestrictedIdentifier();
  this.scope.declareName(node.id.name, BIND_LEXICAL, node.id.start);

  if (this.isRelational("<")) {
    node.typeParameters = this.flowParseTypeParameterDeclaration();
  } else {
    node.typeParameters = null;
  }

  node.right = this.flowParseTypeInitialiser(types.eq);
  this.semicolon();
  return this.finishNode(node, "TypeAlias");
}

flowParseOpaqueType(node, declare) {
  this.expectContextual("type");
  node.id = this.flowParseRestrictedIdentifier(true);
  this.scope.declareName(node.id.name, BIND_LEXICAL, node.id.start);

  if (this.isRelational("<")) {
    node.typeParameters = this.flowParseTypeParameterDeclaration();
  } else {
    node.typeParameters = null;
  }

  node.supertype = null;

  if (this.match(types.colon)) {
    node.supertype = this.flowParseTypeInitialiser(types.colon);
  }

  node.impltype = null;

  if (!declare) {
    node.impltype = this.flowParseTypeInitialiser(types.eq);
  }

  this.semicolon();
  return this.finishNode(node, "OpaqueType");
}

flowParseTypeParameter(requireDefault = false) {
  const nodeStart = this.state.start;
  const node = this.startNode();
  const variance = this.flowParseVariance();
  const ident = this.flowParseTypeAnnotatableIdentifier();
  node.name = ident.name;
  node.variance = variance;
  node.bound = ident.typeAnnotation;

  if (this.match(types.eq)) {
    this.eat(types.eq);
    node.default = this.flowParseType();
  } else {
    if (requireDefault) {
      this.unexpected(nodeStart, "Type parameter declaration needs a default, since a preceding type parameter declaration has a default.");
    }
  }

  return this.finishNode(node, "TypeParameter");
}

flowParseTypeParameterDeclaration() {
  const oldInType = this.state.inType;
  const node = this.startNode();
  node.params = [];
  this.state.inType = true;

  if (this.isRelational("<") || this.match(types.jsxTagStart)) {
    this.next();
  } else {
    this.unexpected();
  }

  let defaultRequired = false;

  do {
    const typeParameter = this.flowParseTypeParameter(defaultRequired);
    node.params.push(typeParameter);

    if (typeParameter.default) {
      defaultRequired = true;
    }

    if (!this.isRelational(">")) {
      this.expect(types.comma);
    }
  } while (!this.isRelational(">"));

  this.expectRelational(">");
  this.state.inType = oldInType;
  return this.finishNode(node, "TypeParameterDeclaration");
}

flowParseTypeParameterInstantiation() {
  const node = this.startNode();
  const oldInType = this.state.inType;
  node.params = [];
  this.state.inType = true;
  this.expectRelational("<");
  const oldNoAnonFunctionType = this.state.noAnonFunctionType;
  this.state.noAnonFunctionType = false;

  while (!this.isRelational(">")) {
    node.params.push(this.flowParseType());

    if (!this.isRelational(">")) {
      this.expect(types.comma);
    }
  }

  this.state.noAnonFunctionType = oldNoAnonFunctionType;
  this.expectRelational(">");
  this.state.inType = oldInType;
  return this.finishNode(node, "TypeParameterInstantiation");
}

flowParseTypeParameterInstantiationCallOrNew() {
  const node = this.startNode();
  const oldInType = this.state.inType;
  node.params = [];
  this.state.inType = true;
  this.expectRelational("<");

  while (!this.isRelational(">")) {
    node.params.push(this.flowParseTypeOrImplicitInstantiation());

    if (!this.isRelational(">")) {
      this.expect(types.comma);
    }
  }

  this.expectRelational(">");
  this.state.inType = oldInType;
  return this.finishNode(node, "TypeParameterInstantiation");
}

flowParseInterfaceType() {
  const node = this.startNode();
  this.expectContextual("interface");
  node.extends = [];

  if (this.eat(types._extends)) {
    do {
      node.extends.push(this.flowParseInterfaceExtends());
    } while (this.eat(types.comma));
  }

  node.body = this.flowParseObjectType({
    allowStatic: false,
    allowExact: false,
    allowSpread: false,
    allowProto: false,
    allowInexact: false
  });
  return this.finishNode(node, "InterfaceTypeAnnotation");
}

flowParseObjectPropertyKey() {
  return this.match(types.num) || this.match(types.string) ? this.parseExprAtom() : this.parseIdentifier(true);
}

flowParseObjectTypeIndexer(node, isStatic, variance) {
  node.static = isStatic;

  if (this.lookahead().type === types.colon) {
    node.id = this.flowParseObjectPropertyKey();
    node.key = this.flowParseTypeInitialiser();
  } else {
    node.id = null;
    node.key = this.flowParseType();
  }

  this.expect(types.bracketR);
  node.value = this.flowParseTypeInitialiser();
  node.variance = variance;
  return this.finishNode(node, "ObjectTypeIndexer");
}

flowParseObjectTypeInternalSlot(node, isStatic) {
  node.static = isStatic;
  node.id = this.flowParseObjectPropertyKey();
  this.expect(types.bracketR);
  this.expect(types.bracketR);

  if (this.isRelational("<") || this.match(types.parenL)) {
    node.method = true;
    node.optional = false;
    node.value = this.flowParseObjectTypeMethodish(this.startNodeAt(node.start, node.loc.start));
  } else {
    node.method = false;

    if (this.eat(types.question)) {
      node.optional = true;
    }

    node.value = this.flowParseTypeInitialiser();
  }

  return this.finishNode(node, "ObjectTypeInternalSlot");
}

flowParseObjectTypeMethodish(node) {
  node.params = [];
  node.rest = null;
  node.typeParameters = null;

  if (this.isRelational("<")) {
    node.typeParameters = this.flowParseTypeParameterDeclaration();
  }

  this.expect(types.parenL);

  while (!this.match(types.parenR) && !this.match(types.ellipsis)) {
    node.params.push(this.flowParseFunctionTypeParam());

    if (!this.match(types.parenR)) {
      this.expect(types.comma);
    }
  }

  if (this.eat(types.ellipsis)) {
    node.rest = this.flowParseFunctionTypeParam();
  }

  this.expect(types.parenR);
  node.returnType = this.flowParseTypeInitialiser();
  return this.finishNode(node, "FunctionTypeAnnotation");
}

flowParseObjectTypeCallProperty(node, isStatic) {
  const valueNode = this.startNode();
  node.static = isStatic;
  node.value = this.flowParseObjectTypeMethodish(valueNode);
  return this.finishNode(node, "ObjectTypeCallProperty");
}

flowParseObjectType({
  allowStatic,
  allowExact,
  allowSpread,
  allowProto,
  allowInexact
}) {
  const oldInType = this.state.inType;
  this.state.inType = true;
  const nodeStart = this.startNode();
  nodeStart.callProperties = [];
  nodeStart.properties = [];
  nodeStart.indexers = [];
  nodeStart.internalSlots = [];
  let endDelim;
  let exact;
  let inexact = false;

  if (allowExact && this.match(types.braceBarL)) {
    this.expect(types.braceBarL);
    endDelim = types.braceBarR;
    exact = true;
  } else {
    this.expect(types.braceL);
    endDelim = types.braceR;
    exact = false;
  }

  nodeStart.exact = exact;

  while (!this.match(endDelim)) {
    let isStatic = false;
    let protoStart = null;
    const node = this.startNode();

    if (allowProto && this.isContextual("proto")) {
      const lookahead = this.lookahead();

      if (lookahead.type !== types.colon && lookahead.type !== types.question) {
        this.next();
        protoStart = this.state.start;
        allowStatic = false;
      }
    }

    if (allowStatic && this.isContextual("static")) {
      const lookahead = this.lookahead();

      if (lookahead.type !== types.colon && lookahead.type !== types.question) {
        this.next();
        isStatic = true;
      }
    }

    const variance = this.flowParseVariance();

    if (this.eat(types.bracketL)) {
      if (protoStart != null) {
        this.unexpected(protoStart);
      }

      if (this.eat(types.bracketL)) {
        if (variance) {
          this.unexpected(variance.start);
        }

        nodeStart.internalSlots.push(this.flowParseObjectTypeInternalSlot(node, isStatic));
      } else {
        nodeStart.indexers.push(this.flowParseObjectTypeIndexer(node, isStatic, variance));
      }
    } else if (this.match(types.parenL) || this.isRelational("<")) {
      if (protoStart != null) {
        this.unexpected(protoStart);
      }

      if (variance) {
        this.unexpected(variance.start);
      }

      nodeStart.callProperties.push(this.flowParseObjectTypeCallProperty(node, isStatic));
    } else {
      let kind = "init";

      if (this.isContextual("get") || this.isContextual("set")) {
        const lookahead = this.lookahead();

        if (lookahead.type === types.name || lookahead.type === types.string || lookahead.type === types.num) {
          kind = this.state.value;
          this.next();
        }
      }

      const propOrInexact = this.flowParseObjectTypeProperty(node, isStatic, protoStart, variance, kind, allowSpread, allowInexact);

      if (propOrInexact === null) {
        inexact = true;
      } else {
        nodeStart.properties.push(propOrInexact);
      }
    }

    this.flowObjectTypeSemicolon();
  }

  this.expect(endDelim);

  if (allowSpread) {
    nodeStart.inexact = inexact;
  }

  const out = this.finishNode(nodeStart, "ObjectTypeAnnotation");
  this.state.inType = oldInType;
  return out;
}

flowParseObjectTypeProperty(node, isStatic, protoStart, variance, kind, allowSpread, allowInexact) {
  if (this.match(types.ellipsis)) {
    if (!allowSpread) {
      this.unexpected(null, "Spread operator cannot appear in class or interface definitions");
    }

    if (protoStart != null) {
      this.unexpected(protoStart);
    }

    if (variance) {
      this.unexpected(variance.start, "Spread properties cannot have variance");
    }

    this.expect(types.ellipsis);
    const isInexactToken = this.eat(types.comma) || this.eat(types.semi);

    if (this.match(types.braceR)) {
      if (allowInexact) return null;
      this.unexpected(null, "Explicit inexact syntax is only allowed inside inexact objects");
    }

    if (this.match(types.braceBarR)) {
      this.unexpected(null, "Explicit inexact syntax cannot appear inside an explicit exact object type");
    }

    if (isInexactToken) {
      this.unexpected(null, "Explicit inexact syntax must appear at the end of an inexact object");
    }

    node.argument = this.flowParseType();
    return this.finishNode(node, "ObjectTypeSpreadProperty");
  } else {
    node.key = this.flowParseObjectPropertyKey();
    node.static = isStatic;
    node.proto = protoStart != null;
    node.kind = kind;
    let optional = false;

    if (this.isRelational("<") || this.match(types.parenL)) {
      node.method = true;

      if (protoStart != null) {
        this.unexpected(protoStart);
      }

      if (variance) {
        this.unexpected(variance.start);
      }

      node.value = this.flowParseObjectTypeMethodish(this.startNodeAt(node.start, node.loc.start));

      if (kind === "get" || kind === "set") {
        this.flowCheckGetterSetterParams(node);
      }
    } else {
      if (kind !== "init") this.unexpected();
      node.method = false;

      if (this.eat(types.question)) {
        optional = true;
      }

      node.value = this.flowParseTypeInitialiser();
      node.variance = variance;
    }

    node.optional = optional;
    return this.finishNode(node, "ObjectTypeProperty");
  }
}

flowCheckGetterSetterParams(property) {
  const paramCount = property.kind === "get" ? 0 : 1;
  const start = property.start;
  const length = property.value.params.length + (property.value.rest ? 1 : 0);

  if (length !== paramCount) {
    if (property.kind === "get") {
      this.raise(start, "getter must not have any formal parameters");
    } else {
      this.raise(start, "setter must have exactly one formal parameter");
    }
  }

  if (property.kind === "set" && property.value.rest) {
    this.raise(start, "setter function argument must not be a rest parameter");
  }
}

flowObjectTypeSemicolon() {
  if (!this.eat(types.semi) && !this.eat(types.comma) && !this.match(types.braceR) && !this.match(types.braceBarR)) {
    this.unexpected();
  }
}

flowParseQualifiedTypeIdentifier(startPos, startLoc, id) {
  startPos = startPos || this.state.start;
  startLoc = startLoc || this.state.startLoc;
  let node = id || this.parseIdentifier();

  while (this.eat(types.dot)) {
    const node2 = this.startNodeAt(startPos, startLoc);
    node2.qualification = node;
    node2.id = this.parseIdentifier();
    node = this.finishNode(node2, "QualifiedTypeIdentifier");
  }

  return node;
}

flowParseGenericType(startPos, startLoc, id) {
  const node = this.startNodeAt(startPos, startLoc);
  node.typeParameters = null;
  node.id = this.flowParseQualifiedTypeIdentifier(startPos, startLoc, id);

  if (this.isRelational("<")) {
    node.typeParameters = this.flowParseTypeParameterInstantiation();
  }

  return this.finishNode(node, "GenericTypeAnnotation");
}

flowParseTypeofType() {
  const node = this.startNode();
  this.expect(types._typeof);
  node.argument = this.flowParsePrimaryType();
  return this.finishNode(node, "TypeofTypeAnnotation");
}

flowParseTupleType() {
  const node = this.startNode();
  node.types = [];
  this.expect(types.bracketL);

  while (this.state.pos < this.length && !this.match(types.bracketR)) {
    node.types.push(this.flowParseType());
    if (this.match(types.bracketR)) break;
    this.expect(types.comma);
  }

  this.expect(types.bracketR);
  return this.finishNode(node, "TupleTypeAnnotation");
}

flowParseFunctionTypeParam() {
  let name = null;
  let optional = false;
  let typeAnnotation = null;
  const node = this.startNode();
  const lh = this.lookahead();

  if (lh.type === types.colon || lh.type === types.question) {
    name = this.parseIdentifier();

    if (this.eat(types.question)) {
      optional = true;
    }

    typeAnnotation = this.flowParseTypeInitialiser();
  } else {
    typeAnnotation = this.flowParseType();
  }

  node.name = name;
  node.optional = optional;
  node.typeAnnotation = typeAnnotation;
  return this.finishNode(node, "FunctionTypeParam");
}

reinterpretTypeAsFunctionTypeParam(type) {
  const node = this.startNodeAt(type.start, type.loc.start);
  node.name = null;
  node.optional = false;
  node.typeAnnotation = type;
  return this.finishNode(node, "FunctionTypeParam");
}

flowParseFunctionTypeParams(params = []) {
  let rest = null;

  while (!this.match(types.parenR) && !this.match(types.ellipsis)) {
    params.push(this.flowParseFunctionTypeParam());

    if (!this.match(types.parenR)) {
      this.expect(types.comma);
    }
  }

  if (this.eat(types.ellipsis)) {
    rest = this.flowParseFunctionTypeParam();
  }

  return {
    params,
    rest
  };
}

flowIdentToTypeAnnotation(startPos, startLoc, node, id) {
  switch (id.name) {
    case "any":
      return this.finishNode(node, "AnyTypeAnnotation");

    case "bool":
    case "boolean":
      return this.finishNode(node, "BooleanTypeAnnotation");

    case "mixed":
      return this.finishNode(node, "MixedTypeAnnotation");

    case "empty":
      return this.finishNode(node, "EmptyTypeAnnotation");

    case "number":
      return this.finishNode(node, "NumberTypeAnnotation");

    case "string":
      return this.finishNode(node, "StringTypeAnnotation");

    default:
      this.checkNotUnderscore(id.name);
      return this.flowParseGenericType(startPos, startLoc, id);
  }
}

flowParsePrimaryType() {
  const startPos = this.state.start;
  const startLoc = this.state.startLoc;
  const node = this.startNode();
  let tmp;
  let type;
  let isGroupedType = false;
  const oldNoAnonFunctionType = this.state.noAnonFunctionType;

  switch (this.state.type) {
    case types.name:
      if (this.isContextual("interface")) {
        return this.flowParseInterfaceType();
      }

      return this.flowIdentToTypeAnnotation(startPos, startLoc, node, this.parseIdentifier());

    case types.braceL:
      return this.flowParseObjectType({
        allowStatic: false,
        allowExact: false,
        allowSpread: true,
        allowProto: false,
        allowInexact: true
      });

    case types.braceBarL:
      return this.flowParseObjectType({
        allowStatic: false,
        allowExact: true,
        allowSpread: true,
        allowProto: false,
        allowInexact: false
      });

    case types.bracketL:
      this.state.noAnonFunctionType = false;
      type = this.flowParseTupleType();
      this.state.noAnonFunctionType = oldNoAnonFunctionType;
      return type;

    case types.relational:
      if (this.state.value === "<") {
        node.typeParameters = this.flowParseTypeParameterDeclaration();
        this.expect(types.parenL);
        tmp = this.flowParseFunctionTypeParams();
        node.params = tmp.params;
        node.rest = tmp.rest;
        this.expect(types.parenR);
        this.expect(types.arrow);
        node.returnType = this.flowParseType();
        return this.finishNode(node, "FunctionTypeAnnotation");
      }

      break;

    case types.parenL:
      this.next();

      if (!this.match(types.parenR) && !this.match(types.ellipsis)) {
        if (this.match(types.name)) {
          const token = this.lookahead().type;
          isGroupedType = token !== types.question && token !== types.colon;
        } else {
          isGroupedType = true;
        }
      }

      if (isGroupedType) {
        this.state.noAnonFunctionType = false;
        type = this.flowParseType();
        this.state.noAnonFunctionType = oldNoAnonFunctionType;

        if (this.state.noAnonFunctionType || !(this.match(types.comma) || this.match(types.parenR) && this.lookahead().type === types.arrow)) {
          this.expect(types.parenR);
          return type;
        } else {
          this.eat(types.comma);
        }
      }

      if (type) {
        tmp = this.flowParseFunctionTypeParams([this.reinterpretTypeAsFunctionTypeParam(type)]);
      } else {
        tmp = this.flowParseFunctionTypeParams();
      }

      node.params = tmp.params;
      node.rest = tmp.rest;
      this.expect(types.parenR);
      this.expect(types.arrow);
      node.returnType = this.flowParseType();
      node.typeParameters = null;
      return this.finishNode(node, "FunctionTypeAnnotation");

    case types.string:
      return this.parseLiteral(this.state.value, "StringLiteralTypeAnnotation");

    case types._true:
    case types._false:
      node.value = this.match(types._true);
      this.next();
      return this.finishNode(node, "BooleanLiteralTypeAnnotation");

    case types.plusMin:
      if (this.state.value === "-") {
        this.next();

        if (this.match(types.num)) {
          return this.parseLiteral(-this.state.value, "NumberLiteralTypeAnnotation", node.start, node.loc.start);
        }

        if (this.match(types.bigint)) {
          return this.parseLiteral(-this.state.value, "BigIntLiteralTypeAnnotation", node.start, node.loc.start);
        }

        this.unexpected(null, `Unexpected token, expected "number" or "bigint"`);
      }

      this.unexpected();

    case types.num:
      return this.parseLiteral(this.state.value, "NumberLiteralTypeAnnotation");

    case types.bigint:
      return this.parseLiteral(this.state.value, "BigIntLiteralTypeAnnotation");

    case types._void:
      this.next();
      return this.finishNode(node, "VoidTypeAnnotation");

    case types._null:
      this.next();
      return this.finishNode(node, "NullLiteralTypeAnnotation");

    case types._this:
      this.next();
      return this.finishNode(node, "ThisTypeAnnotation");

    case types.star:
      this.next();
      return this.finishNode(node, "ExistsTypeAnnotation");

    default:
      if (this.state.type.keyword === "typeof") {
        return this.flowParseTypeofType();
      } else if (this.state.type.keyword) {
        const label = this.state.type.label;
        this.next();
        return super.createIdentifier(node, label);
      }

  }

  throw this.unexpected();
}

flowParsePostfixType() {
  const startPos = this.state.start,
        startLoc = this.state.startLoc;
  let type = this.flowParsePrimaryType();

  while (this.match(types.bracketL) && !this.canInsertSemicolon()) {
    const node = this.startNodeAt(startPos, startLoc);
    node.elementType = type;
    this.expect(types.bracketL);
    this.expect(types.bracketR);
    type = this.finishNode(node, "ArrayTypeAnnotation");
  }

  return type;
}

flowParsePrefixType() {
  const node = this.startNode();

  if (this.eat(types.question)) {
    node.typeAnnotation = this.flowParsePrefixType();
    return this.finishNode(node, "NullableTypeAnnotation");
  } else {
    return this.flowParsePostfixType();
  }
}

flowParseAnonFunctionWithoutParens() {
  const param = this.flowParsePrefixType();

  if (!this.state.noAnonFunctionType && this.eat(types.arrow)) {
    const node = this.startNodeAt(param.start, param.loc.start);
    node.params = [this.reinterpretTypeAsFunctionTypeParam(param)];
    node.rest = null;
    node.returnType = this.flowParseType();
    node.typeParameters = null;
    return this.finishNode(node, "FunctionTypeAnnotation");
  }

  return param;
}

flowParseIntersectionType() {
  const node = this.startNode();
  this.eat(types.bitwiseAND);
  const type = this.flowParseAnonFunctionWithoutParens();
  node.types = [type];

  while (this.eat(types.bitwiseAND)) {
    node.types.push(this.flowParseAnonFunctionWithoutParens());
  }

  return node.types.length === 1 ? type : this.finishNode(node, "IntersectionTypeAnnotation");
}

flowParseUnionType() {
  const node = this.startNode();
  this.eat(types.bitwiseOR);
  const type = this.flowParseIntersectionType();
  node.types = [type];

  while (this.eat(types.bitwiseOR)) {
    node.types.push(this.flowParseIntersectionType());
  }

  return node.types.length === 1 ? type : this.finishNode(node, "UnionTypeAnnotation");
}

flowParseType() {
  const oldInType = this.state.inType;
  this.state.inType = true;
  const type = this.flowParseUnionType();
  this.state.inType = oldInType;
  this.state.exprAllowed = this.state.exprAllowed || this.state.noAnonFunctionType;
  return type;
}

flowParseTypeOrImplicitInstantiation() {
  if (this.state.type === types.name && this.state.value === "_") {
    const startPos = this.state.start;
    const startLoc = this.state.startLoc;
    const node = this.parseIdentifier();
    return this.flowParseGenericType(startPos, startLoc, node);
  } else {
    return this.flowParseType();
  }
}

flowParseTypeAnnotation() {
  const node = this.startNode();
  node.typeAnnotation = this.flowParseTypeInitialiser();
  return this.finishNode(node, "TypeAnnotation");
}

flowParseTypeAnnotatableIdentifier(allowPrimitiveOverride) {
  const ident = allowPrimitiveOverride ? this.parseIdentifier() : this.flowParseRestrictedIdentifier();

  if (this.match(types.colon)) {
    ident.typeAnnotation = this.flowParseTypeAnnotation();
    this.resetEndLocation(ident);
  }

  return ident;
}

typeCastToParameter(node) {
  node.expression.typeAnnotation = node.typeAnnotation;
  this.resetEndLocation(node.expression, node.typeAnnotation.end, node.typeAnnotation.loc.end);
  return node.expression;
}

flowParseVariance() {
  let variance = null;

  if (this.match(types.plusMin)) {
    variance = this.startNode();

    if (this.state.value === "+") {
      variance.kind = "plus";
    } else {
      variance.kind = "minus";
    }

    this.next();
    this.finishNode(variance, "Variance");
  }

  return variance;
}

parseFunctionBody(node, allowExpressionBody, isMethod = false) {
  if (allowExpressionBody) {
    return this.forwardNoArrowParamsConversionAt(node, () => super.parseFunctionBody(node, true, isMethod));
  }

  return super.parseFunctionBody(node, false, isMethod);
}

parseFunctionBodyAndFinish(node, type, isMethod = false) {
  if (this.match(types.colon)) {
    const typeNode = this.startNode();
    [typeNode.typeAnnotation, node.predicate] = this.flowParseTypeAndPredicateInitialiser();
    node.returnType = typeNode.typeAnnotation ? this.finishNode(typeNode, "TypeAnnotation") : null;
  }

  super.parseFunctionBodyAndFinish(node, type, isMethod);
}

parseStatement(context, topLevel) {
  if (this.state.strict && this.match(types.name) && this.state.value === "interface") {
    const node = this.startNode();
    this.next();
    return this.flowParseInterface(node);
  } else {
    const stmt = super.parseStatement(context, topLevel);

    if (this.flowPragma === undefined && !this.isValidDirective(stmt)) {
      this.flowPragma = null;
    }

    return stmt;
  }
}

parseExpressionStatement(node, expr) {
  if (expr.type === "Identifier") {
    if (expr.name === "declare") {
      if (this.match(types._class) || this.match(types.name) || this.match(types._function) || this.match(types._var) || this.match(types._export)) {
        return this.flowParseDeclare(node);
      }
    } else if (this.match(types.name)) {
      if (expr.name === "interface") {
        return this.flowParseInterface(node);
      } else if (expr.name === "type") {
        return this.flowParseTypeAlias(node);
      } else if (expr.name === "opaque") {
        return this.flowParseOpaqueType(node, false);
      }
    }
  }

  return super.parseExpressionStatement(node, expr);
}

shouldParseExportDeclaration() {
  return this.isContextual("type") || this.isContextual("interface") || this.isContextual("opaque") || super.shouldParseExportDeclaration();
}

isExportDefaultSpecifier() {
  if (this.match(types.name) && (this.state.value === "type" || this.state.value === "interface" || this.state.value === "opaque")) {
    return false;
  }

  return super.isExportDefaultSpecifier();
}

parseConditional(expr, noIn, startPos, startLoc, refNeedsArrowPos) {
  if (!this.match(types.question)) return expr;

  if (refNeedsArrowPos) {
    const state = this.state.clone();

    try {
      return super.parseConditional(expr, noIn, startPos, startLoc);
    } catch (err) {
      if (err instanceof SyntaxError) {
        this.state = state;
        refNeedsArrowPos.start = err.pos || this.state.start;
        return expr;
      } else {
        throw err;
      }
    }
  }

  this.expect(types.question);
  const state = this.state.clone();
  const originalNoArrowAt = this.state.noArrowAt;
  const node = this.startNodeAt(startPos, startLoc);
  let {
    consequent,
    failed
  } = this.tryParseConditionalConsequent();
  let [valid, invalid] = this.getArrowLikeExpressions(consequent);

  if (failed || invalid.length > 0) {
    const noArrowAt = [...originalNoArrowAt];

    if (invalid.length > 0) {
      this.state = state;
      this.state.noArrowAt = noArrowAt;

      for (let i = 0; i < invalid.length; i++) {
        noArrowAt.push(invalid[i].start);
      }

      ({
        consequent,
        failed
      } = this.tryParseConditionalConsequent());
      [valid, invalid] = this.getArrowLikeExpressions(consequent);
    }

    if (failed && valid.length > 1) {
      this.raise(state.start, "Ambiguous expression: wrap the arrow functions in parentheses to disambiguate.");
    }

    if (failed && valid.length === 1) {
      this.state = state;
      this.state.noArrowAt = noArrowAt.concat(valid[0].start);
      ({
        consequent,
        failed
      } = this.tryParseConditionalConsequent());
    }

    this.getArrowLikeExpressions(consequent, true);
  }

  this.state.noArrowAt = originalNoArrowAt;
  this.expect(types.colon);
  node.test = expr;
  node.consequent = consequent;
  node.alternate = this.forwardNoArrowParamsConversionAt(node, () => this.parseMaybeAssign(noIn, undefined, undefined, undefined));
  return this.finishNode(node, "ConditionalExpression");
}

tryParseConditionalConsequent() {
  this.state.noArrowParamsConversionAt.push(this.state.start);
  const consequent = this.parseMaybeAssign();
  const failed = !this.match(types.colon);
  this.state.noArrowParamsConversionAt.pop();
  return {
    consequent,
    failed
  };
}

getArrowLikeExpressions(node, disallowInvalid) {
  const stack = [node];
  const arrows = [];

  while (stack.length !== 0) {
    const node = stack.pop();

    if (node.type === "ArrowFunctionExpression") {
      if (node.typeParameters || !node.returnType) {
        var _node$extra;

        this.toAssignableList(node.params, true, "arrow function parameters", (_node$extra = node.extra) === null || _node$extra === void 0 ? void 0 : _node$extra.trailingComma);
        this.scope.enter(functionFlags(false, false) | SCOPE_ARROW);
        super.checkParams(node, false, true);
        this.scope.exit();
      } else {
        arrows.push(node);
      }

      stack.push(node.body);
    } else if (node.type === "ConditionalExpression") {
      stack.push(node.consequent);
      stack.push(node.alternate);
    }
  }

  if (disallowInvalid) {
    for (let i = 0; i < arrows.length; i++) {
      var _node$extra2;

      this.toAssignableList(node.params, true, "arrow function parameters", (_node$extra2 = node.extra) === null || _node$extra2 === void 0 ? void 0 : _node$extra2.trailingComma);
    }

    return [arrows, []];
  }

  return partition(arrows, node => {
    try {
      var _node$extra3;

      this.toAssignableList(node.params, true, "arrow function parameters", (_node$extra3 = node.extra) === null || _node$extra3 === void 0 ? void 0 : _node$extra3.trailingComma);
      return true;
    } catch (err) {
      return false;
    }
  });
}

forwardNoArrowParamsConversionAt(node, parse) {
  let result;

  if (this.state.noArrowParamsConversionAt.indexOf(node.start) !== -1) {
    this.state.noArrowParamsConversionAt.push(this.state.start);
    result = parse();
    this.state.noArrowParamsConversionAt.pop();
  } else {
    result = parse();
  }

  return result;
}

parseParenItem(node, startPos, startLoc) {
  node = super.parseParenItem(node, startPos, startLoc);

  if (this.eat(types.question)) {
    node.optional = true;
    this.resetEndLocation(node);
  }

  if (this.match(types.colon)) {
    const typeCastNode = this.startNodeAt(startPos, startLoc);
    typeCastNode.expression = node;
    typeCastNode.typeAnnotation = this.flowParseTypeAnnotation();
    return this.finishNode(typeCastNode, "TypeCastExpression");
  }

  return node;
}

assertModuleNodeAllowed(node) {
  if (node.type === "ImportDeclaration" && (node.importKind === "type" || node.importKind === "typeof") || node.type === "ExportNamedDeclaration" && node.exportKind === "type" || node.type === "ExportAllDeclaration" && node.exportKind === "type") {
    return;
  }

  super.assertModuleNodeAllowed(node);
}

parseExport(node) {
  const decl = super.parseExport(node);

  if (decl.type === "ExportNamedDeclaration" || decl.type === "ExportAllDeclaration") {
    decl.exportKind = decl.exportKind || "value";
  }

  return decl;
}

parseExportDeclaration(node) {
  if (this.isContextual("type")) {
    node.exportKind = "type";
    const declarationNode = this.startNode();
    this.next();

    if (this.match(types.braceL)) {
      node.specifiers = this.parseExportSpecifiers();
      this.parseExportFrom(node);
      return null;
    } else {
      return this.flowParseTypeAlias(declarationNode);
    }
  } else if (this.isContextual("opaque")) {
    node.exportKind = "type";
    const declarationNode = this.startNode();
    this.next();
    return this.flowParseOpaqueType(declarationNode, false);
  } else if (this.isContextual("interface")) {
    node.exportKind = "type";
    const declarationNode = this.startNode();
    this.next();
    return this.flowParseInterface(declarationNode);
  } else {
    return super.parseExportDeclaration(node);
  }
}

eatExportStar(node) {
  if (super.eatExportStar(...arguments)) return true;

  if (this.isContextual("type") && this.lookahead().type === types.star) {
    node.exportKind = "type";
    this.next();
    this.next();
    return true;
  }

  return false;
}

maybeParseExportNamespaceSpecifier(node) {
  const pos = this.state.start;
  const hasNamespace = super.maybeParseExportNamespaceSpecifier(node);

  if (hasNamespace && node.exportKind === "type") {
    this.unexpected(pos);
  }

  return hasNamespace;
}

parseClassId(node, isStatement, optionalId) {
  super.parseClassId(node, isStatement, optionalId);

  if (this.isRelational("<")) {
    node.typeParameters = this.flowParseTypeParameterDeclaration();
  }
}

getTokenFromCode(code) {
  const next = this.input.charCodeAt(this.state.pos + 1);

  if (code === 123 && next === 124) {
    return this.finishOp(types.braceBarL, 2);
  } else if (this.state.inType && (code === 62 || code === 60)) {
    return this.finishOp(types.relational, 1);
  } else if (isIteratorStart(code, next)) {
    this.state.isIterator = true;
    return super.readWord();
  } else {
    return super.getTokenFromCode(code);
  }
}

toAssignable(node, isBinding, contextDescription) {
  if (node.type === "TypeCastExpression") {
    return super.toAssignable(this.typeCastToParameter(node), isBinding, contextDescription);
  } else {
    return super.toAssignable(node, isBinding, contextDescription);
  }
}

toAssignableList(exprList, isBinding, contextDescription, trailingCommaPos) {
  for (let i = 0; i < exprList.length; i++) {
    const expr = exprList[i];

    if (expr && expr.type === "TypeCastExpression") {
      exprList[i] = this.typeCastToParameter(expr);
    }
  }

  return super.toAssignableList(exprList, isBinding, contextDescription, trailingCommaPos);
}

toReferencedList(exprList, isParenthesizedExpr) {
  for (let i = 0; i < exprList.length; i++) {
    const expr = exprList[i];

    if (expr && expr.type === "TypeCastExpression" && (!expr.extra || !expr.extra.parenthesized) && (exprList.length > 1 || !isParenthesizedExpr)) {
      this.raise(expr.typeAnnotation.start, "The type cast expression is expected to be wrapped with parenthesis");
    }
  }

  return exprList;
}

checkLVal(expr, bindingType = BIND_NONE, checkClashes, contextDescription) {
  if (expr.type !== "TypeCastExpression") {
    return super.checkLVal(expr, bindingType, checkClashes, contextDescription);
  }
}

parseClassProperty(node) {
  if (this.match(types.colon)) {
    node.typeAnnotation = this.flowParseTypeAnnotation();
  }

  return super.parseClassProperty(node);
}

parseClassPrivateProperty(node) {
  if (this.match(types.colon)) {
    node.typeAnnotation = this.flowParseTypeAnnotation();
  }

  return super.parseClassPrivateProperty(node);
}

isClassMethod() {
  return this.isRelational("<") || super.isClassMethod();
}

isClassProperty() {
  return this.match(types.colon) || super.isClassProperty();
}

isNonstaticConstructor(method) {
  return !this.match(types.colon) && super.isNonstaticConstructor(method);
}

pushClassMethod(classBody, method, isGenerator, isAsync, isConstructor, allowsDirectSuper) {
  if (method.variance) {
    this.unexpected(method.variance.start);
  }

  delete method.variance;

  if (this.isRelational("<")) {
    method.typeParameters = this.flowParseTypeParameterDeclaration();
  }

  super.pushClassMethod(classBody, method, isGenerator, isAsync, isConstructor, allowsDirectSuper);
}

pushClassPrivateMethod(classBody, method, isGenerator, isAsync) {
  if (method.variance) {
    this.unexpected(method.variance.start);
  }

  delete method.variance;

  if (this.isRelational("<")) {
    method.typeParameters = this.flowParseTypeParameterDeclaration();
  }

  super.pushClassPrivateMethod(classBody, method, isGenerator, isAsync);
}

parseClassSuper(node) {
  super.parseClassSuper(node);

  if (node.superClass && this.isRelational("<")) {
    node.superTypeParameters = this.flowParseTypeParameterInstantiation();
  }

  if (this.isContextual("implements")) {
    this.next();
    const implemented = node.implements = [];

    do {
      const node = this.startNode();
      node.id = this.flowParseRestrictedIdentifier(true);

      if (this.isRelational("<")) {
        node.typeParameters = this.flowParseTypeParameterInstantiation();
      } else {
        node.typeParameters = null;
      }

      implemented.push(this.finishNode(node, "ClassImplements"));
    } while (this.eat(types.comma));
  }
}

parsePropertyName(node) {
  const variance = this.flowParseVariance();
  const key = super.parsePropertyName(node);
  node.variance = variance;
  return key;
}

parseObjPropValue(prop, startPos, startLoc, isGenerator, isAsync, isPattern, refShorthandDefaultPos, containsEsc) {
  if (prop.variance) {
    this.unexpected(prop.variance.start);
  }

  delete prop.variance;
  let typeParameters;

  if (this.isRelational("<")) {
    typeParameters = this.flowParseTypeParameterDeclaration();
    if (!this.match(types.parenL)) this.unexpected();
  }

  super.parseObjPropValue(prop, startPos, startLoc, isGenerator, isAsync, isPattern, refShorthandDefaultPos, containsEsc);

  if (typeParameters) {
    (prop.value || prop).typeParameters = typeParameters;
  }
}

parseAssignableListItemTypes(param) {
  if (this.eat(types.question)) {
    if (param.type !== "Identifier") {
      throw this.raise(param.start, "A binding pattern parameter cannot be optional in an implementation signature.");
    }

    param.optional = true;
  }

  if (this.match(types.colon)) {
    param.typeAnnotation = this.flowParseTypeAnnotation();
  }

  this.resetEndLocation(param);
  return param;
}

parseMaybeDefault(startPos, startLoc, left) {
  const node = super.parseMaybeDefault(startPos, startLoc, left);

  if (node.type === "AssignmentPattern" && node.typeAnnotation && node.right.start < node.typeAnnotation.start) {
    this.raise(node.typeAnnotation.start, "Type annotations must come before default assignments, " + "e.g. instead of `age = 25: number` use `age: number = 25`");
  }

  return node;
}

shouldParseDefaultImport(node) {
  if (!hasTypeImportKind(node)) {
    return super.shouldParseDefaultImport(node);
  }

  return isMaybeDefaultImport(this.state);
}

parseImportSpecifierLocal(node, specifier, type, contextDescription) {
  specifier.local = hasTypeImportKind(node) ? this.flowParseRestrictedIdentifier(true) : this.parseIdentifier();
  this.checkLVal(specifier.local, BIND_LEXICAL, undefined, contextDescription);
  node.specifiers.push(this.finishNode(specifier, type));
}

maybeParseDefaultImportSpecifier(node) {
  node.importKind = "value";
  let kind = null;

  if (this.match(types._typeof)) {
    kind = "typeof";
  } else if (this.isContextual("type")) {
    kind = "type";
  }

  if (kind) {
    const lh = this.lookahead();

    if (kind === "type" && lh.type === types.star) {
      this.unexpected(lh.start);
    }

    if (isMaybeDefaultImport(lh) || lh.type === types.braceL || lh.type === types.star) {
      this.next();
      node.importKind = kind;
    }
  }

  return super.maybeParseDefaultImportSpecifier(node);
}

parseImportSpecifier(node) {
  const specifier = this.startNode();
  const firstIdentLoc = this.state.start;
  const firstIdent = this.parseIdentifier(true);
  let specifierTypeKind = null;

  if (firstIdent.name === "type") {
    specifierTypeKind = "type";
  } else if (firstIdent.name === "typeof") {
    specifierTypeKind = "typeof";
  }

  let isBinding = false;

  if (this.isContextual("as") && !this.isLookaheadContextual("as")) {
    const as_ident = this.parseIdentifier(true);

    if (specifierTypeKind !== null && !this.match(types.name) && !this.state.type.keyword) {
      specifier.imported = as_ident;
      specifier.importKind = specifierTypeKind;
      specifier.local = as_ident.__clone();
    } else {
      specifier.imported = firstIdent;
      specifier.importKind = null;
      specifier.local = this.parseIdentifier();
    }
  } else if (specifierTypeKind !== null && (this.match(types.name) || this.state.type.keyword)) {
    specifier.imported = this.parseIdentifier(true);
    specifier.importKind = specifierTypeKind;

    if (this.eatContextual("as")) {
      specifier.local = this.parseIdentifier();
    } else {
      isBinding = true;
      specifier.local = specifier.imported.__clone();
    }
  } else {
    isBinding = true;
    specifier.imported = firstIdent;
    specifier.importKind = null;
    specifier.local = specifier.imported.__clone();
  }

  const nodeIsTypeImport = hasTypeImportKind(node);
  const specifierIsTypeImport = hasTypeImportKind(specifier);

  if (nodeIsTypeImport && specifierIsTypeImport) {
    this.raise(firstIdentLoc, "The `type` and `typeof` keywords on named imports can only be used on regular " + "`import` statements. It cannot be used with `import type` or `import typeof` statements");
  }

  if (nodeIsTypeImport || specifierIsTypeImport) {
    this.checkReservedType(specifier.local.name, specifier.local.start);
  }

  if (isBinding && !nodeIsTypeImport && !specifierIsTypeImport) {
    this.checkReservedWord(specifier.local.name, specifier.start, true, true);
  }

  this.checkLVal(specifier.local, BIND_LEXICAL, undefined, "import specifier");
  node.specifiers.push(this.finishNode(specifier, "ImportSpecifier"));
}

parseFunctionParams(node, allowModifiers) {
  const kind = node.kind;

  if (kind !== "get" && kind !== "set" && this.isRelational("<")) {
    node.typeParameters = this.flowParseTypeParameterDeclaration();
  }

  super.parseFunctionParams(node, allowModifiers);
}

parseVarId(decl, kind) {
  super.parseVarId(decl, kind);

  if (this.match(types.colon)) {
    decl.id.typeAnnotation = this.flowParseTypeAnnotation();
    this.resetEndLocation(decl.id);
  }
}

parseAsyncArrowFromCallExpression(node, call) {
  if (this.match(types.colon)) {
    const oldNoAnonFunctionType = this.state.noAnonFunctionType;
    this.state.noAnonFunctionType = true;
    node.returnType = this.flowParseTypeAnnotation();
    this.state.noAnonFunctionType = oldNoAnonFunctionType;
  }

  return super.parseAsyncArrowFromCallExpression(node, call);
}

shouldParseAsyncArrow() {
  return this.match(types.colon) || super.shouldParseAsyncArrow();
}

parseMaybeAssign(noIn, refShorthandDefaultPos, afterLeftParse, refNeedsArrowPos) {
  let jsxError = null;

  if (this.hasPlugin("jsx") && (this.match(types.jsxTagStart) || this.isRelational("<"))) {
    const state = this.state.clone();

    try {
      return super.parseMaybeAssign(noIn, refShorthandDefaultPos, afterLeftParse, refNeedsArrowPos);
    } catch (err) {
      if (err instanceof SyntaxError) {
        this.state = state;
        const cLength = this.state.context.length;

        if (this.state.context[cLength - 1] === types$1.j_oTag) {
          this.state.context.length -= 2;
        }

        jsxError = err;
      } else {
        throw err;
      }
    }
  }

  if (jsxError != null || this.isRelational("<")) {
    let arrowExpression;
    let typeParameters;

    try {
      typeParameters = this.flowParseTypeParameterDeclaration();
      arrowExpression = this.forwardNoArrowParamsConversionAt(typeParameters, () => super.parseMaybeAssign(noIn, refShorthandDefaultPos, afterLeftParse, refNeedsArrowPos));
      arrowExpression.typeParameters = typeParameters;
      this.resetStartLocationFromNode(arrowExpression, typeParameters);
    } catch (err) {
      throw jsxError || err;
    }

    if (arrowExpression.type === "ArrowFunctionExpression") {
      return arrowExpression;
    } else if (jsxError != null) {
      throw jsxError;
    } else {
      this.raise(typeParameters.start, "Expected an arrow function after this type parameter declaration");
    }
  }

  return super.parseMaybeAssign(noIn, refShorthandDefaultPos, afterLeftParse, refNeedsArrowPos);
}

parseArrow(node) {
  if (this.match(types.colon)) {
    const state = this.state.clone();

    try {
      const oldNoAnonFunctionType = this.state.noAnonFunctionType;
      this.state.noAnonFunctionType = true;
      const typeNode = this.startNode();
      [typeNode.typeAnnotation, node.predicate] = this.flowParseTypeAndPredicateInitialiser();
      this.state.noAnonFunctionType = oldNoAnonFunctionType;
      if (this.canInsertSemicolon()) this.unexpected();
      if (!this.match(types.arrow)) this.unexpected();
      node.returnType = typeNode.typeAnnotation ? this.finishNode(typeNode, "TypeAnnotation") : null;
    } catch (err) {
      if (err instanceof SyntaxError) {
        this.state = state;
      } else {
        throw err;
      }
    }
  }

  return super.parseArrow(node);
}

shouldParseArrow() {
  return this.match(types.colon) || super.shouldParseArrow();
}

setArrowFunctionParameters(node, params) {
  if (this.state.noArrowParamsConversionAt.indexOf(node.start) !== -1) {
    node.params = params;
  } else {
    super.setArrowFunctionParameters(node, params);
  }
}

checkParams(node, allowDuplicates, isArrowFunction) {
  if (isArrowFunction && this.state.noArrowParamsConversionAt.indexOf(node.start) !== -1) {
    return;
  }

  return super.checkParams(node, allowDuplicates, isArrowFunction);
}

parseParenAndDistinguishExpression(canBeArrow) {
  return super.parseParenAndDistinguishExpression(canBeArrow && this.state.noArrowAt.indexOf(this.state.start) === -1);
}

parseSubscripts(base, startPos, startLoc, noCalls) {
  if (base.type === "Identifier" && base.name === "async" && this.state.noArrowAt.indexOf(startPos) !== -1) {
    this.next();
    const node = this.startNodeAt(startPos, startLoc);
    node.callee = base;
    node.arguments = this.parseCallExpressionArguments(types.parenR, false);
    base = this.finishNode(node, "CallExpression");
  } else if (base.type === "Identifier" && base.name === "async" && this.isRelational("<")) {
    const state = this.state.clone();
    let error;

    try {
      const node = this.parseAsyncArrowWithTypeParameters(startPos, startLoc);
      if (node) return node;
    } catch (e) {
      error = e;
    }

    this.state = state;

    try {
      return super.parseSubscripts(base, startPos, startLoc, noCalls);
    } catch (e) {
      throw error || e;
    }
  }

  return super.parseSubscripts(base, startPos, startLoc, noCalls);
}

parseSubscript(base, startPos, startLoc, noCalls, subscriptState) {
  if (this.match(types.questionDot) && this.isLookaheadRelational("<")) {
    this.expectPlugin("optionalChaining");
    subscriptState.optionalChainMember = true;

    if (noCalls) {
      subscriptState.stop = true;
      return base;
    }

    this.next();
    const node = this.startNodeAt(startPos, startLoc);
    node.callee = base;
    node.typeArguments = this.flowParseTypeParameterInstantiation();
    this.expect(types.parenL);
    node.arguments = this.parseCallExpressionArguments(types.parenR, false);
    node.optional = true;
    return this.finishNode(node, "OptionalCallExpression");
  } else if (!noCalls && this.shouldParseTypes() && this.isRelational("<")) {
    const node = this.startNodeAt(startPos, startLoc);
    node.callee = base;
    const state = this.state.clone();

    try {
      node.typeArguments = this.flowParseTypeParameterInstantiationCallOrNew();
      this.expect(types.parenL);
      node.arguments = this.parseCallExpressionArguments(types.parenR, false);

      if (subscriptState.optionalChainMember) {
        node.optional = false;
        return this.finishNode(node, "OptionalCallExpression");
      }

      return this.finishNode(node, "CallExpression");
    } catch (e) {
      if (e instanceof SyntaxError) {
        this.state = state;
      } else {
        throw e;
      }
    }
  }

  return super.parseSubscript(base, startPos, startLoc, noCalls, subscriptState);
}

parseNewArguments(node) {
  let targs = null;

  if (this.shouldParseTypes() && this.isRelational("<")) {
    const state = this.state.clone();

    try {
      targs = this.flowParseTypeParameterInstantiationCallOrNew();
    } catch (e) {
      if (e instanceof SyntaxError) {
        this.state = state;
      } else {
        throw e;
      }
    }
  }

  node.typeArguments = targs;
  super.parseNewArguments(node);
}

parseAsyncArrowWithTypeParameters(startPos, startLoc) {
  const node = this.startNodeAt(startPos, startLoc);
  this.parseFunctionParams(node);
  if (!this.parseArrow(node)) return;
  return this.parseArrowExpression(node, undefined, true);
}

readToken_mult_modulo(code) {
  const next = this.input.charCodeAt(this.state.pos + 1);

  if (code === 42 && next === 47 && this.state.hasFlowComment) {
    this.state.hasFlowComment = false;
    this.state.pos += 2;
    this.nextToken();
    return;
  }

  super.readToken_mult_modulo(code);
}

readToken_pipe_amp(code) {
  const next = this.input.charCodeAt(this.state.pos + 1);

  if (code === 124 && next === 125) {
    this.finishOp(types.braceBarR, 2);
    return;
  }

  super.readToken_pipe_amp(code);
}

parseTopLevel(file, program) {
  const fileNode = super.parseTopLevel(file, program);

  if (this.state.hasFlowComment) {
    this.unexpected(null, "Unterminated flow-comment");
  }

  return fileNode;
}

skipBlockComment() {
  if (this.hasPlugin("flowComments") && this.skipFlowComment()) {
    if (this.state.hasFlowComment) {
      this.unexpected(null, "Cannot have a flow comment inside another flow comment");
    }

    this.hasFlowCommentCompletion();
    this.state.pos += this.skipFlowComment();
    this.state.hasFlowComment = true;
    return;
  }

  if (this.state.hasFlowComment) {
    const end = this.input.indexOf("*-/", this.state.pos += 2);
    if (end === -1) this.raise(this.state.pos - 2, "Unterminated comment");
    this.state.pos = end + 3;
    return;
  }

  super.skipBlockComment();
}

skipFlowComment() {
  const {
    pos
  } = this.state;
  let shiftToFirstNonWhiteSpace = 2;

  while ([32, 9].includes(this.input.charCodeAt(pos + shiftToFirstNonWhiteSpace))) {
    shiftToFirstNonWhiteSpace++;
  }

  const ch2 = this.input.charCodeAt(shiftToFirstNonWhiteSpace + pos);
  const ch3 = this.input.charCodeAt(shiftToFirstNonWhiteSpace + pos + 1);

  if (ch2 === 58 && ch3 === 58) {
    return shiftToFirstNonWhiteSpace + 2;
  }

  if (this.input.slice(shiftToFirstNonWhiteSpace + pos, shiftToFirstNonWhiteSpace + pos + 12) === "flow-include") {
    return shiftToFirstNonWhiteSpace + 12;
  }

  if (ch2 === 58 && ch3 !== 58) {
    return shiftToFirstNonWhiteSpace;
  }

  return false;
}

hasFlowCommentCompletion() {
  const end = this.input.indexOf("*/", this.state.pos);

  if (end === -1) {
    this.raise(this.state.pos, "Unterminated comment");
  }
}

});

const entities = {

quot: "\u0022",
amp: "&",
apos: "\u0027",
lt: "<",
gt: ">",
nbsp: "\u00A0",
iexcl: "\u00A1",
cent: "\u00A2",
pound: "\u00A3",
curren: "\u00A4",
yen: "\u00A5",
brvbar: "\u00A6",
sect: "\u00A7",
uml: "\u00A8",
copy: "\u00A9",
ordf: "\u00AA",
laquo: "\u00AB",
not: "\u00AC",
shy: "\u00AD",
reg: "\u00AE",
macr: "\u00AF",
deg: "\u00B0",
plusmn: "\u00B1",
sup2: "\u00B2",
sup3: "\u00B3",
acute: "\u00B4",
micro: "\u00B5",
para: "\u00B6",
middot: "\u00B7",
cedil: "\u00B8",
sup1: "\u00B9",
ordm: "\u00BA",
raquo: "\u00BB",
frac14: "\u00BC",
frac12: "\u00BD",
frac34: "\u00BE",
iquest: "\u00BF",
Agrave: "\u00C0",
Aacute: "\u00C1",
Acirc: "\u00C2",
Atilde: "\u00C3",
Auml: "\u00C4",
Aring: "\u00C5",
AElig: "\u00C6",
Ccedil: "\u00C7",
Egrave: "\u00C8",
Eacute: "\u00C9",
Ecirc: "\u00CA",
Euml: "\u00CB",
Igrave: "\u00CC",
Iacute: "\u00CD",
Icirc: "\u00CE",
Iuml: "\u00CF",
ETH: "\u00D0",
Ntilde: "\u00D1",
Ograve: "\u00D2",
Oacute: "\u00D3",
Ocirc: "\u00D4",
Otilde: "\u00D5",
Ouml: "\u00D6",
times: "\u00D7",
Oslash: "\u00D8",
Ugrave: "\u00D9",
Uacute: "\u00DA",
Ucirc: "\u00DB",
Uuml: "\u00DC",
Yacute: "\u00DD",
THORN: "\u00DE",
szlig: "\u00DF",
agrave: "\u00E0",
aacute: "\u00E1",
acirc: "\u00E2",
atilde: "\u00E3",
auml: "\u00E4",
aring: "\u00E5",
aelig: "\u00E6",
ccedil: "\u00E7",
egrave: "\u00E8",
eacute: "\u00E9",
ecirc: "\u00EA",
euml: "\u00EB",
igrave: "\u00EC",
iacute: "\u00ED",
icirc: "\u00EE",
iuml: "\u00EF",
eth: "\u00F0",
ntilde: "\u00F1",
ograve: "\u00F2",
oacute: "\u00F3",
ocirc: "\u00F4",
otilde: "\u00F5",
ouml: "\u00F6",
divide: "\u00F7",
oslash: "\u00F8",
ugrave: "\u00F9",
uacute: "\u00FA",
ucirc: "\u00FB",
uuml: "\u00FC",
yacute: "\u00FD",
thorn: "\u00FE",
yuml: "\u00FF",
OElig: "\u0152",
oelig: "\u0153",
Scaron: "\u0160",
scaron: "\u0161",
Yuml: "\u0178",
fnof: "\u0192",
circ: "\u02C6",
tilde: "\u02DC",
Alpha: "\u0391",
Beta: "\u0392",
Gamma: "\u0393",
Delta: "\u0394",
Epsilon: "\u0395",
Zeta: "\u0396",
Eta: "\u0397",
Theta: "\u0398",
Iota: "\u0399",
Kappa: "\u039A",
Lambda: "\u039B",
Mu: "\u039C",
Nu: "\u039D",
Xi: "\u039E",
Omicron: "\u039F",
Pi: "\u03A0",
Rho: "\u03A1",
Sigma: "\u03A3",
Tau: "\u03A4",
Upsilon: "\u03A5",
Phi: "\u03A6",
Chi: "\u03A7",
Psi: "\u03A8",
Omega: "\u03A9",
alpha: "\u03B1",
beta: "\u03B2",
gamma: "\u03B3",
delta: "\u03B4",
epsilon: "\u03B5",
zeta: "\u03B6",
eta: "\u03B7",
theta: "\u03B8",
iota: "\u03B9",
kappa: "\u03BA",
lambda: "\u03BB",
mu: "\u03BC",
nu: "\u03BD",
xi: "\u03BE",
omicron: "\u03BF",
pi: "\u03C0",
rho: "\u03C1",
sigmaf: "\u03C2",
sigma: "\u03C3",
tau: "\u03C4",
upsilon: "\u03C5",
phi: "\u03C6",
chi: "\u03C7",
psi: "\u03C8",
omega: "\u03C9",
thetasym: "\u03D1",
upsih: "\u03D2",
piv: "\u03D6",
ensp: "\u2002",
emsp: "\u2003",
thinsp: "\u2009",
zwnj: "\u200C",
zwj: "\u200D",
lrm: "\u200E",
rlm: "\u200F",
ndash: "\u2013",
mdash: "\u2014",
lsquo: "\u2018",
rsquo: "\u2019",
sbquo: "\u201A",
ldquo: "\u201C",
rdquo: "\u201D",
bdquo: "\u201E",
dagger: "\u2020",
Dagger: "\u2021",
bull: "\u2022",
hellip: "\u2026",
permil: "\u2030",
prime: "\u2032",
Prime: "\u2033",
lsaquo: "\u2039",
rsaquo: "\u203A",
oline: "\u203E",
frasl: "\u2044",
euro: "\u20AC",
image: "\u2111",
weierp: "\u2118",
real: "\u211C",
trade: "\u2122",
alefsym: "\u2135",
larr: "\u2190",
uarr: "\u2191",
rarr: "\u2192",
darr: "\u2193",
harr: "\u2194",
crarr: "\u21B5",
lArr: "\u21D0",
uArr: "\u21D1",
rArr: "\u21D2",
dArr: "\u21D3",
hArr: "\u21D4",
forall: "\u2200",
part: "\u2202",
exist: "\u2203",
empty: "\u2205",
nabla: "\u2207",
isin: "\u2208",
notin: "\u2209",
ni: "\u220B",
prod: "\u220F",
sum: "\u2211",
minus: "\u2212",
lowast: "\u2217",
radic: "\u221A",
prop: "\u221D",
infin: "\u221E",
ang: "\u2220",
and: "\u2227",
or: "\u2228",
cap: "\u2229",
cup: "\u222A",
int: "\u222B",
there4: "\u2234",
sim: "\u223C",
cong: "\u2245",
asymp: "\u2248",
ne: "\u2260",
equiv: "\u2261",
le: "\u2264",
ge: "\u2265",
sub: "\u2282",
sup: "\u2283",
nsub: "\u2284",
sube: "\u2286",
supe: "\u2287",
oplus: "\u2295",
otimes: "\u2297",
perp: "\u22A5",
sdot: "\u22C5",
lceil: "\u2308",
rceil: "\u2309",
lfloor: "\u230A",
rfloor: "\u230B",
lang: "\u2329",
rang: "\u232A",
loz: "\u25CA",
spades: "\u2660",
clubs: "\u2663",
hearts: "\u2665",
diams: "\u2666"

};

const HEX_NUMBER = /^[da-fA-F]+$/; const DECIMAL_NUMBER = /^d+$/; types$1.j_oTag = new TokContext(“<tag”, false); types$1.j_cTag = new TokContext(“</tag”, false); types$1.j_expr = new TokContext(“<tag>…</tag>”, true, true); types.jsxName = new TokenType(“jsxName”); types.jsxText = new TokenType(“jsxText”, {

beforeExpr: true

}); types.jsxTagStart = new TokenType(“jsxTagStart”, {

startsExpr: true

}); types.jsxTagEnd = new TokenType(“jsxTagEnd”);

types.jsxTagStart.updateContext = function () {

this.state.context.push(types$1.j_expr);
this.state.context.push(types$1.j_oTag);
this.state.exprAllowed = false;

};

types.jsxTagEnd.updateContext = function (prevType) {

const out = this.state.context.pop();

if (out === types$1.j_oTag && prevType === types.slash || out === types$1.j_cTag) {
  this.state.context.pop();
  this.state.exprAllowed = this.curContext() === types$1.j_expr;
} else {
  this.state.exprAllowed = true;
}

};

function isFragment(object) {

return object ? object.type === "JSXOpeningFragment" || object.type === "JSXClosingFragment" : false;

}

function getQualifiedJSXName(object) {

if (object.type === "JSXIdentifier") {
  return object.name;
}

if (object.type === "JSXNamespacedName") {
  return object.namespace.name + ":" + object.name.name;
}

if (object.type === "JSXMemberExpression") {
  return getQualifiedJSXName(object.object) + "." + getQualifiedJSXName(object.property);
}

throw new Error("Node had unexpected type: " + object.type);

}

var jsx = (superClass => class extends superClass {

jsxReadToken() {
  let out = "";
  let chunkStart = this.state.pos;

  for (;;) {
    if (this.state.pos >= this.length) {
      this.raise(this.state.start, "Unterminated JSX contents");
    }

    const ch = this.input.charCodeAt(this.state.pos);

    switch (ch) {
      case 60:
      case 123:
        if (this.state.pos === this.state.start) {
          if (ch === 60 && this.state.exprAllowed) {
            ++this.state.pos;
            return this.finishToken(types.jsxTagStart);
          }

          return super.getTokenFromCode(ch);
        }

        out += this.input.slice(chunkStart, this.state.pos);
        return this.finishToken(types.jsxText, out);

      case 38:
        out += this.input.slice(chunkStart, this.state.pos);
        out += this.jsxReadEntity();
        chunkStart = this.state.pos;
        break;

      default:
        if (isNewLine(ch)) {
          out += this.input.slice(chunkStart, this.state.pos);
          out += this.jsxReadNewLine(true);
          chunkStart = this.state.pos;
        } else {
          ++this.state.pos;
        }

    }
  }
}

jsxReadNewLine(normalizeCRLF) {
  const ch = this.input.charCodeAt(this.state.pos);
  let out;
  ++this.state.pos;

  if (ch === 13 && this.input.charCodeAt(this.state.pos) === 10) {
    ++this.state.pos;
    out = normalizeCRLF ? "\n" : "\r\n";
  } else {
    out = String.fromCharCode(ch);
  }

  ++this.state.curLine;
  this.state.lineStart = this.state.pos;
  return out;
}

jsxReadString(quote) {
  let out = "";
  let chunkStart = ++this.state.pos;

  for (;;) {
    if (this.state.pos >= this.length) {
      this.raise(this.state.start, "Unterminated string constant");
    }

    const ch = this.input.charCodeAt(this.state.pos);
    if (ch === quote) break;

    if (ch === 38) {
      out += this.input.slice(chunkStart, this.state.pos);
      out += this.jsxReadEntity();
      chunkStart = this.state.pos;
    } else if (isNewLine(ch)) {
      out += this.input.slice(chunkStart, this.state.pos);
      out += this.jsxReadNewLine(false);
      chunkStart = this.state.pos;
    } else {
      ++this.state.pos;
    }
  }

  out += this.input.slice(chunkStart, this.state.pos++);
  return this.finishToken(types.string, out);
}

jsxReadEntity() {
  let str = "";
  let count = 0;
  let entity;
  let ch = this.input[this.state.pos];
  const startPos = ++this.state.pos;

  while (this.state.pos < this.length && count++ < 10) {
    ch = this.input[this.state.pos++];

    if (ch === ";") {
      if (str[0] === "#") {
        if (str[1] === "x") {
          str = str.substr(2);

          if (HEX_NUMBER.test(str)) {
            entity = String.fromCodePoint(parseInt(str, 16));
          }
        } else {
          str = str.substr(1);

          if (DECIMAL_NUMBER.test(str)) {
            entity = String.fromCodePoint(parseInt(str, 10));
          }
        }
      } else {
        entity = entities[str];
      }

      break;
    }

    str += ch;
  }

  if (!entity) {
    this.state.pos = startPos;
    return "&";
  }

  return entity;
}

jsxReadWord() {
  let ch;
  const start = this.state.pos;

  do {
    ch = this.input.charCodeAt(++this.state.pos);
  } while (isIdentifierChar(ch) || ch === 45);

  return this.finishToken(types.jsxName, this.input.slice(start, this.state.pos));
}

jsxParseIdentifier() {
  const node = this.startNode();

  if (this.match(types.jsxName)) {
    node.name = this.state.value;
  } else if (this.state.type.keyword) {
    node.name = this.state.type.keyword;
  } else {
    this.unexpected();
  }

  this.next();
  return this.finishNode(node, "JSXIdentifier");
}

jsxParseNamespacedName() {
  const startPos = this.state.start;
  const startLoc = this.state.startLoc;
  const name = this.jsxParseIdentifier();
  if (!this.eat(types.colon)) return name;
  const node = this.startNodeAt(startPos, startLoc);
  node.namespace = name;
  node.name = this.jsxParseIdentifier();
  return this.finishNode(node, "JSXNamespacedName");
}

jsxParseElementName() {
  const startPos = this.state.start;
  const startLoc = this.state.startLoc;
  let node = this.jsxParseNamespacedName();

  if (node.type === "JSXNamespacedName") {
    return node;
  }

  while (this.eat(types.dot)) {
    const newNode = this.startNodeAt(startPos, startLoc);
    newNode.object = node;
    newNode.property = this.jsxParseIdentifier();
    node = this.finishNode(newNode, "JSXMemberExpression");
  }

  return node;
}

jsxParseAttributeValue() {
  let node;

  switch (this.state.type) {
    case types.braceL:
      node = this.startNode();
      this.next();
      node = this.jsxParseExpressionContainer(node);

      if (node.expression.type === "JSXEmptyExpression") {
        throw this.raise(node.start, "JSX attributes must only be assigned a non-empty expression");
      } else {
        return node;
      }

    case types.jsxTagStart:
    case types.string:
      return this.parseExprAtom();

    default:
      throw this.raise(this.state.start, "JSX value should be either an expression or a quoted JSX text");
  }
}

jsxParseEmptyExpression() {
  const node = this.startNodeAt(this.state.lastTokEnd, this.state.lastTokEndLoc);
  return this.finishNodeAt(node, "JSXEmptyExpression", this.state.start, this.state.startLoc);
}

jsxParseSpreadChild(node) {
  this.next();
  node.expression = this.parseExpression();
  this.expect(types.braceR);
  return this.finishNode(node, "JSXSpreadChild");
}

jsxParseExpressionContainer(node) {
  if (this.match(types.braceR)) {
    node.expression = this.jsxParseEmptyExpression();
  } else {
    node.expression = this.parseExpression();
  }

  this.expect(types.braceR);
  return this.finishNode(node, "JSXExpressionContainer");
}

jsxParseAttribute() {
  const node = this.startNode();

  if (this.eat(types.braceL)) {
    this.expect(types.ellipsis);
    node.argument = this.parseMaybeAssign();
    this.expect(types.braceR);
    return this.finishNode(node, "JSXSpreadAttribute");
  }

  node.name = this.jsxParseNamespacedName();
  node.value = this.eat(types.eq) ? this.jsxParseAttributeValue() : null;
  return this.finishNode(node, "JSXAttribute");
}

jsxParseOpeningElementAt(startPos, startLoc) {
  const node = this.startNodeAt(startPos, startLoc);

  if (this.match(types.jsxTagEnd)) {
    this.expect(types.jsxTagEnd);
    return this.finishNode(node, "JSXOpeningFragment");
  }

  node.name = this.jsxParseElementName();
  return this.jsxParseOpeningElementAfterName(node);
}

jsxParseOpeningElementAfterName(node) {
  const attributes = [];

  while (!this.match(types.slash) && !this.match(types.jsxTagEnd)) {
    attributes.push(this.jsxParseAttribute());
  }

  node.attributes = attributes;
  node.selfClosing = this.eat(types.slash);
  this.expect(types.jsxTagEnd);
  return this.finishNode(node, "JSXOpeningElement");
}

jsxParseClosingElementAt(startPos, startLoc) {
  const node = this.startNodeAt(startPos, startLoc);

  if (this.match(types.jsxTagEnd)) {
    this.expect(types.jsxTagEnd);
    return this.finishNode(node, "JSXClosingFragment");
  }

  node.name = this.jsxParseElementName();
  this.expect(types.jsxTagEnd);
  return this.finishNode(node, "JSXClosingElement");
}

jsxParseElementAt(startPos, startLoc) {
  const node = this.startNodeAt(startPos, startLoc);
  const children = [];
  const openingElement = this.jsxParseOpeningElementAt(startPos, startLoc);
  let closingElement = null;

  if (!openingElement.selfClosing) {
    contents: for (;;) {
      switch (this.state.type) {
        case types.jsxTagStart:
          startPos = this.state.start;
          startLoc = this.state.startLoc;
          this.next();

          if (this.eat(types.slash)) {
            closingElement = this.jsxParseClosingElementAt(startPos, startLoc);
            break contents;
          }

          children.push(this.jsxParseElementAt(startPos, startLoc));
          break;

        case types.jsxText:
          children.push(this.parseExprAtom());
          break;

        case types.braceL:
          {
            const node = this.startNode();
            this.next();

            if (this.match(types.ellipsis)) {
              children.push(this.jsxParseSpreadChild(node));
            } else {
              children.push(this.jsxParseExpressionContainer(node));
            }

            break;
          }

        default:
          throw this.unexpected();
      }
    }

    if (isFragment(openingElement) && !isFragment(closingElement)) {
      this.raise(closingElement.start, "Expected corresponding JSX closing tag for <>");
    } else if (!isFragment(openingElement) && isFragment(closingElement)) {
      this.raise(closingElement.start, "Expected corresponding JSX closing tag for <" + getQualifiedJSXName(openingElement.name) + ">");
    } else if (!isFragment(openingElement) && !isFragment(closingElement)) {
      if (getQualifiedJSXName(closingElement.name) !== getQualifiedJSXName(openingElement.name)) {
        this.raise(closingElement.start, "Expected corresponding JSX closing tag for <" + getQualifiedJSXName(openingElement.name) + ">");
      }
    }
  }

  if (isFragment(openingElement)) {
    node.openingFragment = openingElement;
    node.closingFragment = closingElement;
  } else {
    node.openingElement = openingElement;
    node.closingElement = closingElement;
  }

  node.children = children;

  if (this.match(types.relational) && this.state.value === "<") {
    this.raise(this.state.start, "Adjacent JSX elements must be wrapped in an enclosing tag. " + "Did you want a JSX fragment <>...</>?");
  }

  return isFragment(openingElement) ? this.finishNode(node, "JSXFragment") : this.finishNode(node, "JSXElement");
}

jsxParseElement() {
  const startPos = this.state.start;
  const startLoc = this.state.startLoc;
  this.next();
  return this.jsxParseElementAt(startPos, startLoc);
}

parseExprAtom(refShortHandDefaultPos) {
  if (this.match(types.jsxText)) {
    return this.parseLiteral(this.state.value, "JSXText");
  } else if (this.match(types.jsxTagStart)) {
    return this.jsxParseElement();
  } else if (this.isRelational("<") && this.input.charCodeAt(this.state.pos) !== 33) {
    this.finishToken(types.jsxTagStart);
    return this.jsxParseElement();
  } else {
    return super.parseExprAtom(refShortHandDefaultPos);
  }
}

getTokenFromCode(code) {
  if (this.state.inPropertyName) return super.getTokenFromCode(code);
  const context = this.curContext();

  if (context === types$1.j_expr) {
    return this.jsxReadToken();
  }

  if (context === types$1.j_oTag || context === types$1.j_cTag) {
    if (isIdentifierStart(code)) {
      return this.jsxReadWord();
    }

    if (code === 62) {
      ++this.state.pos;
      return this.finishToken(types.jsxTagEnd);
    }

    if ((code === 34 || code === 39) && context === types$1.j_oTag) {
      return this.jsxReadString(code);
    }
  }

  if (code === 60 && this.state.exprAllowed && this.input.charCodeAt(this.state.pos + 1) !== 33) {
    ++this.state.pos;
    return this.finishToken(types.jsxTagStart);
  }

  return super.getTokenFromCode(code);
}

updateContext(prevType) {
  if (this.match(types.braceL)) {
    const curContext = this.curContext();

    if (curContext === types$1.j_oTag) {
      this.state.context.push(types$1.braceExpression);
    } else if (curContext === types$1.j_expr) {
      this.state.context.push(types$1.templateQuasi);
    } else {
      super.updateContext(prevType);
    }

    this.state.exprAllowed = true;
  } else if (this.match(types.slash) && prevType === types.jsxTagStart) {
    this.state.context.length -= 2;
    this.state.context.push(types$1.j_cTag);
    this.state.exprAllowed = false;
  } else {
    return super.updateContext(prevType);
  }
}

});

class Scope {

constructor(flags) {
  this.var = [];
  this.lexical = [];
  this.functions = [];
  this.flags = flags;
}

} class ScopeHandler {

constructor(raise, inModule) {
  this.scopeStack = [];
  this.undefinedExports = new Map();
  this.raise = raise;
  this.inModule = inModule;
}

get inFunction() {
  return (this.currentVarScope().flags & SCOPE_FUNCTION) > 0;
}

get inGenerator() {
  return (this.currentVarScope().flags & SCOPE_GENERATOR) > 0;
}

get inAsync() {
  return (this.currentVarScope().flags & SCOPE_ASYNC) > 0;
}

get allowSuper() {
  return (this.currentThisScope().flags & SCOPE_SUPER) > 0;
}

get allowDirectSuper() {
  return (this.currentThisScope().flags & SCOPE_DIRECT_SUPER) > 0;
}

get inNonArrowFunction() {
  return (this.currentThisScope().flags & SCOPE_FUNCTION) > 0;
}

get treatFunctionsAsVar() {
  return this.treatFunctionsAsVarInScope(this.currentScope());
}

createScope(flags) {
  return new Scope(flags);
}

enter(flags) {
  this.scopeStack.push(this.createScope(flags));
}

exit() {
  this.scopeStack.pop();
}

treatFunctionsAsVarInScope(scope) {
  return !!(scope.flags & SCOPE_FUNCTION || !this.inModule && scope.flags & SCOPE_PROGRAM);
}

declareName(name, bindingType, pos) {
  let scope = this.currentScope();

  if (bindingType & BIND_SCOPE_LEXICAL || bindingType & BIND_SCOPE_FUNCTION) {
    this.checkRedeclarationInScope(scope, name, bindingType, pos);

    if (bindingType & BIND_SCOPE_FUNCTION) {
      scope.functions.push(name);
    } else {
      scope.lexical.push(name);
    }

    if (bindingType & BIND_SCOPE_LEXICAL) {
      this.maybeExportDefined(scope, name);
    }
  } else if (bindingType & BIND_SCOPE_VAR) {
    for (let i = this.scopeStack.length - 1; i >= 0; --i) {
      scope = this.scopeStack[i];
      this.checkRedeclarationInScope(scope, name, bindingType, pos);
      scope.var.push(name);
      this.maybeExportDefined(scope, name);
      if (scope.flags & SCOPE_VAR) break;
    }
  }

  if (this.inModule && scope.flags & SCOPE_PROGRAM) {
    this.undefinedExports.delete(name);
  }
}

maybeExportDefined(scope, name) {
  if (this.inModule && scope.flags & SCOPE_PROGRAM) {
    this.undefinedExports.delete(name);
  }
}

checkRedeclarationInScope(scope, name, bindingType, pos) {
  if (this.isRedeclaredInScope(scope, name, bindingType)) {
    this.raise(pos, `Identifier '${name}' has already been declared`);
  }
}

isRedeclaredInScope(scope, name, bindingType) {
  if (!(bindingType & BIND_KIND_VALUE)) return false;

  if (bindingType & BIND_SCOPE_LEXICAL) {
    return scope.lexical.indexOf(name) > -1 || scope.functions.indexOf(name) > -1 || scope.var.indexOf(name) > -1;
  }

  if (bindingType & BIND_SCOPE_FUNCTION) {
    return scope.lexical.indexOf(name) > -1 || !this.treatFunctionsAsVarInScope(scope) && scope.var.indexOf(name) > -1;
  }

  return scope.lexical.indexOf(name) > -1 && !(scope.flags & SCOPE_SIMPLE_CATCH && scope.lexical[0] === name) || !this.treatFunctionsAsVarInScope(scope) && scope.functions.indexOf(name) > -1;
}

checkLocalExport(id) {
  if (this.scopeStack[0].lexical.indexOf(id.name) === -1 && this.scopeStack[0].var.indexOf(id.name) === -1 && this.scopeStack[0].functions.indexOf(id.name) === -1) {
    this.undefinedExports.set(id.name, id.start);
  }
}

currentScope() {
  return this.scopeStack[this.scopeStack.length - 1];
}

currentVarScope() {
  for (let i = this.scopeStack.length - 1;; i--) {
    const scope = this.scopeStack[i];

    if (scope.flags & SCOPE_VAR) {
      return scope;
    }
  }
}

currentThisScope() {
  for (let i = this.scopeStack.length - 1;; i--) {
    const scope = this.scopeStack[i];

    if ((scope.flags & SCOPE_VAR || scope.flags & SCOPE_CLASS) && !(scope.flags & SCOPE_ARROW)) {
      return scope;
    }
  }
}

}

class TypeScriptScope extends Scope {

constructor(...args) {
  super(...args);
  this.types = [];
  this.enums = [];
  this.constEnums = [];
  this.classes = [];
  this.exportOnlyBindings = [];
}

}

class TypeScriptScopeHandler extends ScopeHandler {

createScope(flags) {
  return new TypeScriptScope(flags);
}

declareName(name, bindingType, pos) {
  const scope = this.currentScope();

  if (bindingType & BIND_FLAGS_TS_EXPORT_ONLY) {
    this.maybeExportDefined(scope, name);
    scope.exportOnlyBindings.push(name);
    return;
  }

  super.declareName(...arguments);

  if (bindingType & BIND_KIND_TYPE) {
    if (!(bindingType & BIND_KIND_VALUE)) {
      this.checkRedeclarationInScope(scope, name, bindingType, pos);
      this.maybeExportDefined(scope, name);
    }

    scope.types.push(name);
  }

  if (bindingType & BIND_FLAGS_TS_ENUM) scope.enums.push(name);
  if (bindingType & BIND_FLAGS_TS_CONST_ENUM) scope.constEnums.push(name);
  if (bindingType & BIND_FLAGS_CLASS) scope.classes.push(name);
}

isRedeclaredInScope(scope, name, bindingType) {
  if (scope.enums.indexOf(name) > -1) {
    if (bindingType & BIND_FLAGS_TS_ENUM) {
      const isConst = !!(bindingType & BIND_FLAGS_TS_CONST_ENUM);
      const wasConst = scope.constEnums.indexOf(name) > -1;
      return isConst !== wasConst;
    }

    return true;
  }

  if (bindingType & BIND_FLAGS_CLASS && scope.classes.indexOf(name) > -1) {
    if (scope.lexical.indexOf(name) > -1) {
      return !!(bindingType & BIND_KIND_VALUE);
    } else {
      return false;
    }
  }

  if (bindingType & BIND_KIND_TYPE && scope.types.indexOf(name) > -1) {
    return true;
  }

  return super.isRedeclaredInScope(...arguments);
}

checkLocalExport(id) {
  if (this.scopeStack[0].types.indexOf(id.name) === -1 && this.scopeStack[0].exportOnlyBindings.indexOf(id.name) === -1) {
    super.checkLocalExport(id);
  }
}

}

function nonNull(x) {

if (x == null) {
  throw new Error(`Unexpected ${x} value.`);
}

return x;

}

function assert(x) {

if (!x) {
  throw new Error("Assert fail");
}

}

function keywordTypeFromName(value) {

switch (value) {
  case "any":
    return "TSAnyKeyword";

  case "boolean":
    return "TSBooleanKeyword";

  case "bigint":
    return "TSBigIntKeyword";

  case "never":
    return "TSNeverKeyword";

  case "number":
    return "TSNumberKeyword";

  case "object":
    return "TSObjectKeyword";

  case "string":
    return "TSStringKeyword";

  case "symbol":
    return "TSSymbolKeyword";

  case "undefined":
    return "TSUndefinedKeyword";

  case "unknown":
    return "TSUnknownKeyword";

  default:
    return undefined;
}

}

var typescript = (superClass => class extends superClass {

getScopeHandler() {
  return TypeScriptScopeHandler;
}

tsIsIdentifier() {
  return this.match(types.name);
}

tsNextTokenCanFollowModifier() {
  this.next();
  return !this.hasPrecedingLineBreak() && !this.match(types.parenL) && !this.match(types.parenR) && !this.match(types.colon) && !this.match(types.eq) && !this.match(types.question) && !this.match(types.bang);
}

tsParseModifier(allowedModifiers) {
  if (!this.match(types.name)) {
    return undefined;
  }

  const modifier = this.state.value;

  if (allowedModifiers.indexOf(modifier) !== -1 && this.tsTryParse(this.tsNextTokenCanFollowModifier.bind(this))) {
    return modifier;
  }

  return undefined;
}

tsIsListTerminator(kind) {
  switch (kind) {
    case "EnumMembers":
    case "TypeMembers":
      return this.match(types.braceR);

    case "HeritageClauseElement":
      return this.match(types.braceL);

    case "TupleElementTypes":
      return this.match(types.bracketR);

    case "TypeParametersOrArguments":
      return this.isRelational(">");
  }

  throw new Error("Unreachable");
}

tsParseList(kind, parseElement) {
  const result = [];

  while (!this.tsIsListTerminator(kind)) {
    result.push(parseElement());
  }

  return result;
}

tsParseDelimitedList(kind, parseElement) {
  return nonNull(this.tsParseDelimitedListWorker(kind, parseElement, true));
}

tsParseDelimitedListWorker(kind, parseElement, expectSuccess) {
  const result = [];

  while (true) {
    if (this.tsIsListTerminator(kind)) {
      break;
    }

    const element = parseElement();

    if (element == null) {
      return undefined;
    }

    result.push(element);

    if (this.eat(types.comma)) {
      continue;
    }

    if (this.tsIsListTerminator(kind)) {
      break;
    }

    if (expectSuccess) {
      this.expect(types.comma);
    }

    return undefined;
  }

  return result;
}

tsParseBracketedList(kind, parseElement, bracket, skipFirstToken) {
  if (!skipFirstToken) {
    if (bracket) {
      this.expect(types.bracketL);
    } else {
      this.expectRelational("<");
    }
  }

  const result = this.tsParseDelimitedList(kind, parseElement);

  if (bracket) {
    this.expect(types.bracketR);
  } else {
    this.expectRelational(">");
  }

  return result;
}

tsParseImportType() {
  const node = this.startNode();
  this.expect(types._import);
  this.expect(types.parenL);

  if (!this.match(types.string)) {
    throw this.unexpected(null, "Argument in a type import must be a string literal");
  }

  node.argument = this.parseExprAtom();
  this.expect(types.parenR);

  if (this.eat(types.dot)) {
    node.qualifier = this.tsParseEntityName(true);
  }

  if (this.isRelational("<")) {
    node.typeParameters = this.tsParseTypeArguments();
  }

  return this.finishNode(node, "TSImportType");
}

tsParseEntityName(allowReservedWords) {
  let entity = this.parseIdentifier();

  while (this.eat(types.dot)) {
    const node = this.startNodeAtNode(entity);
    node.left = entity;
    node.right = this.parseIdentifier(allowReservedWords);
    entity = this.finishNode(node, "TSQualifiedName");
  }

  return entity;
}

tsParseTypeReference() {
  const node = this.startNode();
  node.typeName = this.tsParseEntityName(false);

  if (!this.hasPrecedingLineBreak() && this.isRelational("<")) {
    node.typeParameters = this.tsParseTypeArguments();
  }

  return this.finishNode(node, "TSTypeReference");
}

tsParseThisTypePredicate(lhs) {
  this.next();
  const node = this.startNodeAtNode(lhs);
  node.parameterName = lhs;
  node.typeAnnotation = this.tsParseTypeAnnotation(false);
  return this.finishNode(node, "TSTypePredicate");
}

tsParseThisTypeNode() {
  const node = this.startNode();
  this.next();
  return this.finishNode(node, "TSThisType");
}

tsParseTypeQuery() {
  const node = this.startNode();
  this.expect(types._typeof);

  if (this.match(types._import)) {
    node.exprName = this.tsParseImportType();
  } else {
    node.exprName = this.tsParseEntityName(true);
  }

  return this.finishNode(node, "TSTypeQuery");
}

tsParseTypeParameter() {
  const node = this.startNode();
  node.name = this.parseIdentifierName(node.start);
  node.constraint = this.tsEatThenParseType(types._extends);
  node.default = this.tsEatThenParseType(types.eq);
  return this.finishNode(node, "TSTypeParameter");
}

tsTryParseTypeParameters() {
  if (this.isRelational("<")) {
    return this.tsParseTypeParameters();
  }
}

tsParseTypeParameters() {
  const node = this.startNode();

  if (this.isRelational("<") || this.match(types.jsxTagStart)) {
    this.next();
  } else {
    this.unexpected();
  }

  node.params = this.tsParseBracketedList("TypeParametersOrArguments", this.tsParseTypeParameter.bind(this), false, true);
  return this.finishNode(node, "TSTypeParameterDeclaration");
}

tsTryNextParseConstantContext() {
  if (this.lookahead().type === types._const) {
    this.next();
    return this.tsParseTypeReference();
  }

  return null;
}

tsFillSignature(returnToken, signature) {
  const returnTokenRequired = returnToken === types.arrow;
  signature.typeParameters = this.tsTryParseTypeParameters();
  this.expect(types.parenL);
  signature.parameters = this.tsParseBindingListForSignature();

  if (returnTokenRequired) {
    signature.typeAnnotation = this.tsParseTypeOrTypePredicateAnnotation(returnToken);
  } else if (this.match(returnToken)) {
    signature.typeAnnotation = this.tsParseTypeOrTypePredicateAnnotation(returnToken);
  }
}

tsParseBindingListForSignature() {
  return this.parseBindingList(types.parenR, 41).map(pattern => {
    if (pattern.type !== "Identifier" && pattern.type !== "RestElement" && pattern.type !== "ObjectPattern" && pattern.type !== "ArrayPattern") {
      throw this.unexpected(pattern.start, "Name in a signature must be an Identifier, ObjectPattern or ArrayPattern," + `instead got ${pattern.type}`);
    }

    return pattern;
  });
}

tsParseTypeMemberSemicolon() {
  if (!this.eat(types.comma)) {
    this.semicolon();
  }
}

tsParseSignatureMember(kind, node) {
  this.tsFillSignature(types.colon, node);
  this.tsParseTypeMemberSemicolon();
  return this.finishNode(node, kind);
}

tsIsUnambiguouslyIndexSignature() {
  this.next();
  return this.eat(types.name) && this.match(types.colon);
}

tsTryParseIndexSignature(node) {
  if (!(this.match(types.bracketL) && this.tsLookAhead(this.tsIsUnambiguouslyIndexSignature.bind(this)))) {
    return undefined;
  }

  this.expect(types.bracketL);
  const id = this.parseIdentifier();
  id.typeAnnotation = this.tsParseTypeAnnotation();
  this.resetEndLocation(id);
  this.expect(types.bracketR);
  node.parameters = [id];
  const type = this.tsTryParseTypeAnnotation();
  if (type) node.typeAnnotation = type;
  this.tsParseTypeMemberSemicolon();
  return this.finishNode(node, "TSIndexSignature");
}

tsParsePropertyOrMethodSignature(node, readonly) {
  if (this.eat(types.question)) node.optional = true;
  const nodeAny = node;

  if (!readonly && (this.match(types.parenL) || this.isRelational("<"))) {
    const method = nodeAny;
    this.tsFillSignature(types.colon, method);
    this.tsParseTypeMemberSemicolon();
    return this.finishNode(method, "TSMethodSignature");
  } else {
    const property = nodeAny;
    if (readonly) property.readonly = true;
    const type = this.tsTryParseTypeAnnotation();
    if (type) property.typeAnnotation = type;
    this.tsParseTypeMemberSemicolon();
    return this.finishNode(property, "TSPropertySignature");
  }
}

tsParseTypeMember() {
  const node = this.startNode();

  if (this.match(types.parenL) || this.isRelational("<")) {
    return this.tsParseSignatureMember("TSCallSignatureDeclaration", node);
  }

  if (this.match(types._new)) {
    const id = this.startNode();
    this.next();

    if (this.match(types.parenL) || this.isRelational("<")) {
      return this.tsParseSignatureMember("TSConstructSignatureDeclaration", node);
    } else {
      node.key = this.createIdentifier(id, "new");
      return this.tsParsePropertyOrMethodSignature(node, false);
    }
  }

  const readonly = !!this.tsParseModifier(["readonly"]);
  const idx = this.tsTryParseIndexSignature(node);

  if (idx) {
    if (readonly) node.readonly = true;
    return idx;
  }

  this.parsePropertyName(node);
  return this.tsParsePropertyOrMethodSignature(node, readonly);
}

tsParseTypeLiteral() {
  const node = this.startNode();
  node.members = this.tsParseObjectTypeMembers();
  return this.finishNode(node, "TSTypeLiteral");
}

tsParseObjectTypeMembers() {
  this.expect(types.braceL);
  const members = this.tsParseList("TypeMembers", this.tsParseTypeMember.bind(this));
  this.expect(types.braceR);
  return members;
}

tsIsStartOfMappedType() {
  this.next();

  if (this.eat(types.plusMin)) {
    return this.isContextual("readonly");
  }

  if (this.isContextual("readonly")) {
    this.next();
  }

  if (!this.match(types.bracketL)) {
    return false;
  }

  this.next();

  if (!this.tsIsIdentifier()) {
    return false;
  }

  this.next();
  return this.match(types._in);
}

tsParseMappedTypeParameter() {
  const node = this.startNode();
  node.name = this.parseIdentifierName(node.start);
  node.constraint = this.tsExpectThenParseType(types._in);
  return this.finishNode(node, "TSTypeParameter");
}

tsParseMappedType() {
  const node = this.startNode();
  this.expect(types.braceL);

  if (this.match(types.plusMin)) {
    node.readonly = this.state.value;
    this.next();
    this.expectContextual("readonly");
  } else if (this.eatContextual("readonly")) {
    node.readonly = true;
  }

  this.expect(types.bracketL);
  node.typeParameter = this.tsParseMappedTypeParameter();
  this.expect(types.bracketR);

  if (this.match(types.plusMin)) {
    node.optional = this.state.value;
    this.next();
    this.expect(types.question);
  } else if (this.eat(types.question)) {
    node.optional = true;
  }

  node.typeAnnotation = this.tsTryParseType();
  this.semicolon();
  this.expect(types.braceR);
  return this.finishNode(node, "TSMappedType");
}

tsParseTupleType() {
  const node = this.startNode();
  node.elementTypes = this.tsParseBracketedList("TupleElementTypes", this.tsParseTupleElementType.bind(this), true, false);
  let seenOptionalElement = false;
  node.elementTypes.forEach(elementNode => {
    if (elementNode.type === "TSOptionalType") {
      seenOptionalElement = true;
    } else if (seenOptionalElement && elementNode.type !== "TSRestType") {
      this.raise(elementNode.start, "A required element cannot follow an optional element.");
    }
  });
  return this.finishNode(node, "TSTupleType");
}

tsParseTupleElementType() {
  if (this.match(types.ellipsis)) {
    const restNode = this.startNode();
    this.next();
    restNode.typeAnnotation = this.tsParseType();
    this.checkCommaAfterRest(93);
    return this.finishNode(restNode, "TSRestType");
  }

  const type = this.tsParseType();

  if (this.eat(types.question)) {
    const optionalTypeNode = this.startNodeAtNode(type);
    optionalTypeNode.typeAnnotation = type;
    return this.finishNode(optionalTypeNode, "TSOptionalType");
  }

  return type;
}

tsParseParenthesizedType() {
  const node = this.startNode();
  this.expect(types.parenL);
  node.typeAnnotation = this.tsParseType();
  this.expect(types.parenR);
  return this.finishNode(node, "TSParenthesizedType");
}

tsParseFunctionOrConstructorType(type) {
  const node = this.startNode();

  if (type === "TSConstructorType") {
    this.expect(types._new);
  }

  this.tsFillSignature(types.arrow, node);
  return this.finishNode(node, type);
}

tsParseLiteralTypeNode() {
  const node = this.startNode();

  node.literal = (() => {
    switch (this.state.type) {
      case types.num:
      case types.string:
      case types._true:
      case types._false:
        return this.parseExprAtom();

      default:
        throw this.unexpected();
    }
  })();

  return this.finishNode(node, "TSLiteralType");
}

tsParseTemplateLiteralType() {
  const node = this.startNode();
  const templateNode = this.parseTemplate(false);

  if (templateNode.expressions.length > 0) {
    throw this.raise(templateNode.expressions[0].start, "Template literal types cannot have any substitution");
  }

  node.literal = templateNode;
  return this.finishNode(node, "TSLiteralType");
}

tsParseNonArrayType() {
  switch (this.state.type) {
    case types.name:
    case types._void:
    case types._null:
      {
        const type = this.match(types._void) ? "TSVoidKeyword" : this.match(types._null) ? "TSNullKeyword" : keywordTypeFromName(this.state.value);

        if (type !== undefined && this.lookaheadCharCode() !== 46) {
          const node = this.startNode();
          this.next();
          return this.finishNode(node, type);
        }

        return this.tsParseTypeReference();
      }

    case types.string:
    case types.num:
    case types._true:
    case types._false:
      return this.tsParseLiteralTypeNode();

    case types.plusMin:
      if (this.state.value === "-") {
        const node = this.startNode();

        if (this.lookahead().type !== types.num) {
          throw this.unexpected();
        }

        node.literal = this.parseMaybeUnary();
        return this.finishNode(node, "TSLiteralType");
      }

      break;

    case types._this:
      {
        const thisKeyword = this.tsParseThisTypeNode();

        if (this.isContextual("is") && !this.hasPrecedingLineBreak()) {
          return this.tsParseThisTypePredicate(thisKeyword);
        } else {
          return thisKeyword;
        }
      }

    case types._typeof:
      return this.tsParseTypeQuery();

    case types._import:
      return this.tsParseImportType();

    case types.braceL:
      return this.tsLookAhead(this.tsIsStartOfMappedType.bind(this)) ? this.tsParseMappedType() : this.tsParseTypeLiteral();

    case types.bracketL:
      return this.tsParseTupleType();

    case types.parenL:
      return this.tsParseParenthesizedType();

    case types.backQuote:
      return this.tsParseTemplateLiteralType();
  }

  throw this.unexpected();
}

tsParseArrayTypeOrHigher() {
  let type = this.tsParseNonArrayType();

  while (!this.hasPrecedingLineBreak() && this.eat(types.bracketL)) {
    if (this.match(types.bracketR)) {
      const node = this.startNodeAtNode(type);
      node.elementType = type;
      this.expect(types.bracketR);
      type = this.finishNode(node, "TSArrayType");
    } else {
      const node = this.startNodeAtNode(type);
      node.objectType = type;
      node.indexType = this.tsParseType();
      this.expect(types.bracketR);
      type = this.finishNode(node, "TSIndexedAccessType");
    }
  }

  return type;
}

tsParseTypeOperator(operator) {
  const node = this.startNode();
  this.expectContextual(operator);
  node.operator = operator;
  node.typeAnnotation = this.tsParseTypeOperatorOrHigher();

  if (operator === "readonly") {
    this.tsCheckTypeAnnotationForReadOnly(node);
  }

  return this.finishNode(node, "TSTypeOperator");
}

tsCheckTypeAnnotationForReadOnly(node) {
  switch (node.typeAnnotation.type) {
    case "TSTupleType":
    case "TSArrayType":
      return;

    default:
      this.raise(node.start, "'readonly' type modifier is only permitted on array and tuple literal types.");
  }
}

tsParseInferType() {
  const node = this.startNode();
  this.expectContextual("infer");
  const typeParameter = this.startNode();
  typeParameter.name = this.parseIdentifierName(typeParameter.start);
  node.typeParameter = this.finishNode(typeParameter, "TSTypeParameter");
  return this.finishNode(node, "TSInferType");
}

tsParseTypeOperatorOrHigher() {
  const operator = ["keyof", "unique", "readonly"].find(kw => this.isContextual(kw));
  return operator ? this.tsParseTypeOperator(operator) : this.isContextual("infer") ? this.tsParseInferType() : this.tsParseArrayTypeOrHigher();
}

tsParseUnionOrIntersectionType(kind, parseConstituentType, operator) {
  this.eat(operator);
  let type = parseConstituentType();

  if (this.match(operator)) {
    const types = [type];

    while (this.eat(operator)) {
      types.push(parseConstituentType());
    }

    const node = this.startNodeAtNode(type);
    node.types = types;
    type = this.finishNode(node, kind);
  }

  return type;
}

tsParseIntersectionTypeOrHigher() {
  return this.tsParseUnionOrIntersectionType("TSIntersectionType", this.tsParseTypeOperatorOrHigher.bind(this), types.bitwiseAND);
}

tsParseUnionTypeOrHigher() {
  return this.tsParseUnionOrIntersectionType("TSUnionType", this.tsParseIntersectionTypeOrHigher.bind(this), types.bitwiseOR);
}

tsIsStartOfFunctionType() {
  if (this.isRelational("<")) {
    return true;
  }

  return this.match(types.parenL) && this.tsLookAhead(this.tsIsUnambiguouslyStartOfFunctionType.bind(this));
}

tsSkipParameterStart() {
  if (this.match(types.name) || this.match(types._this)) {
    this.next();
    return true;
  }

  if (this.match(types.braceL)) {
    let braceStackCounter = 1;
    this.next();

    while (braceStackCounter > 0) {
      if (this.match(types.braceL)) {
        ++braceStackCounter;
      } else if (this.match(types.braceR)) {
        --braceStackCounter;
      }

      this.next();
    }

    return true;
  }

  if (this.match(types.bracketL)) {
    let braceStackCounter = 1;
    this.next();

    while (braceStackCounter > 0) {
      if (this.match(types.bracketL)) {
        ++braceStackCounter;
      } else if (this.match(types.bracketR)) {
        --braceStackCounter;
      }

      this.next();
    }

    return true;
  }

  return false;
}

tsIsUnambiguouslyStartOfFunctionType() {
  this.next();

  if (this.match(types.parenR) || this.match(types.ellipsis)) {
    return true;
  }

  if (this.tsSkipParameterStart()) {
    if (this.match(types.colon) || this.match(types.comma) || this.match(types.question) || this.match(types.eq)) {
      return true;
    }

    if (this.match(types.parenR)) {
      this.next();

      if (this.match(types.arrow)) {
        return true;
      }
    }
  }

  return false;
}

tsParseTypeOrTypePredicateAnnotation(returnToken) {
  return this.tsInType(() => {
    const t = this.startNode();
    this.expect(returnToken);
    const typePredicateVariable = this.tsIsIdentifier() && this.tsTryParse(this.tsParseTypePredicatePrefix.bind(this));

    if (!typePredicateVariable) {
      return this.tsParseTypeAnnotation(false, t);
    }

    const type = this.tsParseTypeAnnotation(false);
    const node = this.startNodeAtNode(typePredicateVariable);
    node.parameterName = typePredicateVariable;
    node.typeAnnotation = type;
    t.typeAnnotation = this.finishNode(node, "TSTypePredicate");
    return this.finishNode(t, "TSTypeAnnotation");
  });
}

tsTryParseTypeOrTypePredicateAnnotation() {
  return this.match(types.colon) ? this.tsParseTypeOrTypePredicateAnnotation(types.colon) : undefined;
}

tsTryParseTypeAnnotation() {
  return this.match(types.colon) ? this.tsParseTypeAnnotation() : undefined;
}

tsTryParseType() {
  return this.tsEatThenParseType(types.colon);
}

tsParseTypePredicatePrefix() {
  const id = this.parseIdentifier();

  if (this.isContextual("is") && !this.hasPrecedingLineBreak()) {
    this.next();
    return id;
  }
}

tsParseTypeAnnotation(eatColon = true, t = this.startNode()) {
  this.tsInType(() => {
    if (eatColon) this.expect(types.colon);
    t.typeAnnotation = this.tsParseType();
  });
  return this.finishNode(t, "TSTypeAnnotation");
}

tsParseType() {
  assert(this.state.inType);
  const type = this.tsParseNonConditionalType();

  if (this.hasPrecedingLineBreak() || !this.eat(types._extends)) {
    return type;
  }

  const node = this.startNodeAtNode(type);
  node.checkType = type;
  node.extendsType = this.tsParseNonConditionalType();
  this.expect(types.question);
  node.trueType = this.tsParseType();
  this.expect(types.colon);
  node.falseType = this.tsParseType();
  return this.finishNode(node, "TSConditionalType");
}

tsParseNonConditionalType() {
  if (this.tsIsStartOfFunctionType()) {
    return this.tsParseFunctionOrConstructorType("TSFunctionType");
  }

  if (this.match(types._new)) {
    return this.tsParseFunctionOrConstructorType("TSConstructorType");
  }

  return this.tsParseUnionTypeOrHigher();
}

tsParseTypeAssertion() {
  const node = this.startNode();

  const _const = this.tsTryNextParseConstantContext();

  node.typeAnnotation = _const || this.tsNextThenParseType();
  this.expectRelational(">");
  node.expression = this.parseMaybeUnary();
  return this.finishNode(node, "TSTypeAssertion");
}

tsParseHeritageClause(descriptor) {
  const originalStart = this.state.start;
  const delimitedList = this.tsParseDelimitedList("HeritageClauseElement", this.tsParseExpressionWithTypeArguments.bind(this));

  if (!delimitedList.length) {
    this.raise(originalStart, `'${descriptor}' list cannot be empty.`);
  }

  return delimitedList;
}

tsParseExpressionWithTypeArguments() {
  const node = this.startNode();
  node.expression = this.tsParseEntityName(false);

  if (this.isRelational("<")) {
    node.typeParameters = this.tsParseTypeArguments();
  }

  return this.finishNode(node, "TSExpressionWithTypeArguments");
}

tsParseInterfaceDeclaration(node) {
  node.id = this.parseIdentifier();
  this.checkLVal(node.id, BIND_TS_INTERFACE, undefined, "typescript interface declaration");
  node.typeParameters = this.tsTryParseTypeParameters();

  if (this.eat(types._extends)) {
    node.extends = this.tsParseHeritageClause("extends");
  }

  const body = this.startNode();
  body.body = this.tsInType(this.tsParseObjectTypeMembers.bind(this));
  node.body = this.finishNode(body, "TSInterfaceBody");
  return this.finishNode(node, "TSInterfaceDeclaration");
}

tsParseTypeAliasDeclaration(node) {
  node.id = this.parseIdentifier();
  this.checkLVal(node.id, BIND_TS_TYPE, undefined, "typescript type alias");
  node.typeParameters = this.tsTryParseTypeParameters();
  node.typeAnnotation = this.tsExpectThenParseType(types.eq);
  this.semicolon();
  return this.finishNode(node, "TSTypeAliasDeclaration");
}

tsInNoContext(cb) {
  const oldContext = this.state.context;
  this.state.context = [oldContext[0]];

  try {
    return cb();
  } finally {
    this.state.context = oldContext;
  }
}

tsInType(cb) {
  const oldInType = this.state.inType;
  this.state.inType = true;

  try {
    return cb();
  } finally {
    this.state.inType = oldInType;
  }
}

tsEatThenParseType(token) {
  return !this.match(token) ? undefined : this.tsNextThenParseType();
}

tsExpectThenParseType(token) {
  return this.tsDoThenParseType(() => this.expect(token));
}

tsNextThenParseType() {
  return this.tsDoThenParseType(() => this.next());
}

tsDoThenParseType(cb) {
  return this.tsInType(() => {
    cb();
    return this.tsParseType();
  });
}

tsParseEnumMember() {
  const node = this.startNode();
  node.id = this.match(types.string) ? this.parseExprAtom() : this.parseIdentifier(true);

  if (this.eat(types.eq)) {
    node.initializer = this.parseMaybeAssign();
  }

  return this.finishNode(node, "TSEnumMember");
}

tsParseEnumDeclaration(node, isConst) {
  if (isConst) node.const = true;
  node.id = this.parseIdentifier();
  this.checkLVal(node.id, isConst ? BIND_TS_CONST_ENUM : BIND_TS_ENUM, undefined, "typescript enum declaration");
  this.expect(types.braceL);
  node.members = this.tsParseDelimitedList("EnumMembers", this.tsParseEnumMember.bind(this));
  this.expect(types.braceR);
  return this.finishNode(node, "TSEnumDeclaration");
}

tsParseModuleBlock() {
  const node = this.startNode();
  this.scope.enter(SCOPE_OTHER);
  this.expect(types.braceL);
  this.parseBlockOrModuleBlockBody(node.body = [], undefined, true, types.braceR);
  this.scope.exit();
  return this.finishNode(node, "TSModuleBlock");
}

tsParseModuleOrNamespaceDeclaration(node, nested = false) {
  node.id = this.parseIdentifier();

  if (!nested) {
    this.checkLVal(node.id, BIND_TS_NAMESPACE, null, "module or namespace declaration");
  }

  if (this.eat(types.dot)) {
    const inner = this.startNode();
    this.tsParseModuleOrNamespaceDeclaration(inner, true);
    node.body = inner;
  } else {
    this.scope.enter(SCOPE_TS_MODULE);
    node.body = this.tsParseModuleBlock();
    this.scope.exit();
  }

  return this.finishNode(node, "TSModuleDeclaration");
}

tsParseAmbientExternalModuleDeclaration(node) {
  if (this.isContextual("global")) {
    node.global = true;
    node.id = this.parseIdentifier();
  } else if (this.match(types.string)) {
    node.id = this.parseExprAtom();
  } else {
    this.unexpected();
  }

  if (this.match(types.braceL)) {
    this.scope.enter(SCOPE_TS_MODULE);
    node.body = this.tsParseModuleBlock();
    this.scope.exit();
  } else {
    this.semicolon();
  }

  return this.finishNode(node, "TSModuleDeclaration");
}

tsParseImportEqualsDeclaration(node, isExport) {
  node.isExport = isExport || false;
  node.id = this.parseIdentifier();
  this.expect(types.eq);
  node.moduleReference = this.tsParseModuleReference();
  this.semicolon();
  return this.finishNode(node, "TSImportEqualsDeclaration");
}

tsIsExternalModuleReference() {
  return this.isContextual("require") && this.lookaheadCharCode() === 40;
}

tsParseModuleReference() {
  return this.tsIsExternalModuleReference() ? this.tsParseExternalModuleReference() : this.tsParseEntityName(false);
}

tsParseExternalModuleReference() {
  const node = this.startNode();
  this.expectContextual("require");
  this.expect(types.parenL);

  if (!this.match(types.string)) {
    throw this.unexpected();
  }

  node.expression = this.parseExprAtom();
  this.expect(types.parenR);
  return this.finishNode(node, "TSExternalModuleReference");
}

tsLookAhead(f) {
  const state = this.state.clone();
  const res = f();
  this.state = state;
  return res;
}

tsTryParseAndCatch(f) {
  const state = this.state.clone();

  try {
    return f();
  } catch (e) {
    if (e instanceof SyntaxError) {
      this.state = state;
      return undefined;
    }

    throw e;
  }
}

tsTryParse(f) {
  const state = this.state.clone();
  const result = f();

  if (result !== undefined && result !== false) {
    return result;
  } else {
    this.state = state;
    return undefined;
  }
}

tsTryParseDeclare(nany) {
  if (this.isLineTerminator()) {
    return;
  }

  let starttype = this.state.type;
  let kind;

  if (this.isContextual("let")) {
    starttype = types._var;
    kind = "let";
  }

  switch (starttype) {
    case types._function:
      return this.parseFunctionStatement(nany, false, true);

    case types._class:
      nany.declare = true;
      return this.parseClass(nany, true, false);

    case types._const:
      if (this.match(types._const) && this.isLookaheadContextual("enum")) {
        this.expect(types._const);
        this.expectContextual("enum");
        return this.tsParseEnumDeclaration(nany, true);
      }

    case types._var:
      kind = kind || this.state.value;
      return this.parseVarStatement(nany, kind);

    case types.name:
      {
        const value = this.state.value;

        if (value === "global") {
          return this.tsParseAmbientExternalModuleDeclaration(nany);
        } else {
          return this.tsParseDeclaration(nany, value, true);
        }
      }
  }
}

tsTryParseExportDeclaration() {
  return this.tsParseDeclaration(this.startNode(), this.state.value, true);
}

tsParseExpressionStatement(node, expr) {
  switch (expr.name) {
    case "declare":
      {
        const declaration = this.tsTryParseDeclare(node);

        if (declaration) {
          declaration.declare = true;
          return declaration;
        }

        break;
      }

    case "global":
      if (this.match(types.braceL)) {
        this.scope.enter(SCOPE_TS_MODULE);
        const mod = node;
        mod.global = true;
        mod.id = expr;
        mod.body = this.tsParseModuleBlock();
        this.scope.exit();
        return this.finishNode(mod, "TSModuleDeclaration");
      }

      break;

    default:
      return this.tsParseDeclaration(node, expr.name, false);
  }
}

tsParseDeclaration(node, value, next) {
  switch (value) {
    case "abstract":
      if (this.tsCheckLineTerminatorAndMatch(types._class, next)) {
        const cls = node;
        cls.abstract = true;

        if (next) {
          this.next();

          if (!this.match(types._class)) {
            this.unexpected(null, types._class);
          }
        }

        return this.parseClass(cls, true, false);
      }

      break;

    case "enum":
      if (next || this.match(types.name)) {
        if (next) this.next();
        return this.tsParseEnumDeclaration(node, false);
      }

      break;

    case "interface":
      if (this.tsCheckLineTerminatorAndMatch(types.name, next)) {
        if (next) this.next();
        return this.tsParseInterfaceDeclaration(node);
      }

      break;

    case "module":
      if (next) this.next();

      if (this.match(types.string)) {
        return this.tsParseAmbientExternalModuleDeclaration(node);
      } else if (this.tsCheckLineTerminatorAndMatch(types.name, next)) {
        return this.tsParseModuleOrNamespaceDeclaration(node);
      }

      break;

    case "namespace":
      if (this.tsCheckLineTerminatorAndMatch(types.name, next)) {
        if (next) this.next();
        return this.tsParseModuleOrNamespaceDeclaration(node);
      }

      break;

    case "type":
      if (this.tsCheckLineTerminatorAndMatch(types.name, next)) {
        if (next) this.next();
        return this.tsParseTypeAliasDeclaration(node);
      }

      break;
  }
}

tsCheckLineTerminatorAndMatch(tokenType, next) {
  return (next || this.match(tokenType)) && !this.isLineTerminator();
}

tsTryParseGenericAsyncArrowFunction(startPos, startLoc) {
  if (!this.isRelational("<")) {
    return undefined;
  }

  const res = this.tsTryParseAndCatch(() => {
    const node = this.startNodeAt(startPos, startLoc);
    node.typeParameters = this.tsParseTypeParameters();
    super.parseFunctionParams(node);
    node.returnType = this.tsTryParseTypeOrTypePredicateAnnotation();
    this.expect(types.arrow);
    return node;
  });

  if (!res) {
    return undefined;
  }

  return this.parseArrowExpression(res, null, true);
}

tsParseTypeArguments() {
  const node = this.startNode();
  node.params = this.tsInType(() => this.tsInNoContext(() => {
    this.expectRelational("<");
    return this.tsParseDelimitedList("TypeParametersOrArguments", this.tsParseType.bind(this));
  }));
  this.state.exprAllowed = false;
  this.expectRelational(">");
  return this.finishNode(node, "TSTypeParameterInstantiation");
}

tsIsDeclarationStart() {
  if (this.match(types.name)) {
    switch (this.state.value) {
      case "abstract":
      case "declare":
      case "enum":
      case "interface":
      case "module":
      case "namespace":
      case "type":
        return true;
    }
  }

  return false;
}

isExportDefaultSpecifier() {
  if (this.tsIsDeclarationStart()) return false;
  return super.isExportDefaultSpecifier();
}

parseAssignableListItem(allowModifiers, decorators) {
  const startPos = this.state.start;
  const startLoc = this.state.startLoc;
  let accessibility;
  let readonly = false;

  if (allowModifiers) {
    accessibility = this.parseAccessModifier();
    readonly = !!this.tsParseModifier(["readonly"]);
  }

  const left = this.parseMaybeDefault();
  this.parseAssignableListItemTypes(left);
  const elt = this.parseMaybeDefault(left.start, left.loc.start, left);

  if (accessibility || readonly) {
    const pp = this.startNodeAt(startPos, startLoc);

    if (decorators.length) {
      pp.decorators = decorators;
    }

    if (accessibility) pp.accessibility = accessibility;
    if (readonly) pp.readonly = readonly;

    if (elt.type !== "Identifier" && elt.type !== "AssignmentPattern") {
      throw this.raise(pp.start, "A parameter property may not be declared using a binding pattern.");
    }

    pp.parameter = elt;
    return this.finishNode(pp, "TSParameterProperty");
  }

  if (decorators.length) {
    left.decorators = decorators;
  }

  return elt;
}

parseFunctionBodyAndFinish(node, type, isMethod = false) {
  if (this.match(types.colon)) {
    node.returnType = this.tsParseTypeOrTypePredicateAnnotation(types.colon);
  }

  const bodilessType = type === "FunctionDeclaration" ? "TSDeclareFunction" : type === "ClassMethod" ? "TSDeclareMethod" : undefined;

  if (bodilessType && !this.match(types.braceL) && this.isLineTerminator()) {
    this.finishNode(node, bodilessType);
    return;
  }

  super.parseFunctionBodyAndFinish(node, type, isMethod);
}

checkFunctionStatementId(node) {
  if (!node.body && node.id) {
    this.checkLVal(node.id, BIND_TS_AMBIENT, null, "function name");
  } else {
    super.checkFunctionStatementId(...arguments);
  }
}

parseSubscript(base, startPos, startLoc, noCalls, state) {
  if (!this.hasPrecedingLineBreak() && this.match(types.bang)) {
    this.state.exprAllowed = false;
    this.next();
    const nonNullExpression = this.startNodeAt(startPos, startLoc);
    nonNullExpression.expression = base;
    return this.finishNode(nonNullExpression, "TSNonNullExpression");
  }

  if (this.isRelational("<")) {
    const result = this.tsTryParseAndCatch(() => {
      if (!noCalls && this.atPossibleAsync(base)) {
        const asyncArrowFn = this.tsTryParseGenericAsyncArrowFunction(startPos, startLoc);

        if (asyncArrowFn) {
          return asyncArrowFn;
        }
      }

      const node = this.startNodeAt(startPos, startLoc);
      node.callee = base;
      const typeArguments = this.tsParseTypeArguments();

      if (typeArguments) {
        if (!noCalls && this.eat(types.parenL)) {
          node.arguments = this.parseCallExpressionArguments(types.parenR, false);
          node.typeParameters = typeArguments;
          return this.finishCallExpression(node);
        } else if (this.match(types.backQuote)) {
          return this.parseTaggedTemplateExpression(startPos, startLoc, base, state, typeArguments);
        }
      }

      this.unexpected();
    });
    if (result) return result;
  }

  return super.parseSubscript(base, startPos, startLoc, noCalls, state);
}

parseNewArguments(node) {
  if (this.isRelational("<")) {
    const typeParameters = this.tsTryParseAndCatch(() => {
      const args = this.tsParseTypeArguments();
      if (!this.match(types.parenL)) this.unexpected();
      return args;
    });

    if (typeParameters) {
      node.typeParameters = typeParameters;
    }
  }

  super.parseNewArguments(node);
}

parseExprOp(left, leftStartPos, leftStartLoc, minPrec, noIn) {
  if (nonNull(types._in.binop) > minPrec && !this.hasPrecedingLineBreak() && this.isContextual("as")) {
    const node = this.startNodeAt(leftStartPos, leftStartLoc);
    node.expression = left;

    const _const = this.tsTryNextParseConstantContext();

    if (_const) {
      node.typeAnnotation = _const;
    } else {
      node.typeAnnotation = this.tsNextThenParseType();
    }

    this.finishNode(node, "TSAsExpression");
    return this.parseExprOp(node, leftStartPos, leftStartLoc, minPrec, noIn);
  }

  return super.parseExprOp(left, leftStartPos, leftStartLoc, minPrec, noIn);
}

checkReservedWord(word, startLoc, checkKeywords, isBinding) {}

checkDuplicateExports() {}

parseImport(node) {
  if (this.match(types.name) && this.lookahead().type === types.eq) {
    return this.tsParseImportEqualsDeclaration(node);
  }

  return super.parseImport(node);
}

parseExport(node) {
  if (this.match(types._import)) {
    this.expect(types._import);
    return this.tsParseImportEqualsDeclaration(node, true);
  } else if (this.eat(types.eq)) {
    const assign = node;
    assign.expression = this.parseExpression();
    this.semicolon();
    return this.finishNode(assign, "TSExportAssignment");
  } else if (this.eatContextual("as")) {
    const decl = node;
    this.expectContextual("namespace");
    decl.id = this.parseIdentifier();
    this.semicolon();
    return this.finishNode(decl, "TSNamespaceExportDeclaration");
  } else {
    return super.parseExport(node);
  }
}

isAbstractClass() {
  return this.isContextual("abstract") && this.lookahead().type === types._class;
}

parseExportDefaultExpression() {
  if (this.isAbstractClass()) {
    const cls = this.startNode();
    this.next();
    this.parseClass(cls, true, true);
    cls.abstract = true;
    return cls;
  }

  if (this.state.value === "interface") {
    const result = this.tsParseDeclaration(this.startNode(), this.state.value, true);
    if (result) return result;
  }

  return super.parseExportDefaultExpression();
}

parseStatementContent(context, topLevel) {
  if (this.state.type === types._const) {
    const ahead = this.lookahead();

    if (ahead.type === types.name && ahead.value === "enum") {
      const node = this.startNode();
      this.expect(types._const);
      this.expectContextual("enum");
      return this.tsParseEnumDeclaration(node, true);
    }
  }

  return super.parseStatementContent(context, topLevel);
}

parseAccessModifier() {
  return this.tsParseModifier(["public", "protected", "private"]);
}

parseClassMember(classBody, member, state, constructorAllowsSuper) {
  const accessibility = this.parseAccessModifier();
  if (accessibility) member.accessibility = accessibility;
  super.parseClassMember(classBody, member, state, constructorAllowsSuper);
}

parseClassMemberWithIsStatic(classBody, member, state, isStatic, constructorAllowsSuper) {
  const methodOrProp = member;
  const prop = member;
  const propOrIdx = member;
  let abstract = false,
      readonly = false;
  const mod = this.tsParseModifier(["abstract", "readonly"]);

  switch (mod) {
    case "readonly":
      readonly = true;
      abstract = !!this.tsParseModifier(["abstract"]);
      break;

    case "abstract":
      abstract = true;
      readonly = !!this.tsParseModifier(["readonly"]);
      break;
  }

  if (abstract) methodOrProp.abstract = true;
  if (readonly) propOrIdx.readonly = true;

  if (!abstract && !isStatic && !methodOrProp.accessibility) {
    const idx = this.tsTryParseIndexSignature(member);

    if (idx) {
      classBody.body.push(idx);
      return;
    }
  }

  if (readonly) {
    methodOrProp.static = isStatic;
    this.parseClassPropertyName(prop);
    this.parsePostMemberNameModifiers(methodOrProp);
    this.pushClassProperty(classBody, prop);
    return;
  }

  super.parseClassMemberWithIsStatic(classBody, member, state, isStatic, constructorAllowsSuper);
}

parsePostMemberNameModifiers(methodOrProp) {
  const optional = this.eat(types.question);
  if (optional) methodOrProp.optional = true;
}

parseExpressionStatement(node, expr) {
  const decl = expr.type === "Identifier" ? this.tsParseExpressionStatement(node, expr) : undefined;
  return decl || super.parseExpressionStatement(node, expr);
}

shouldParseExportDeclaration() {
  if (this.tsIsDeclarationStart()) return true;
  return super.shouldParseExportDeclaration();
}

parseConditional(expr, noIn, startPos, startLoc, refNeedsArrowPos) {
  if (!refNeedsArrowPos || !this.match(types.question)) {
    return super.parseConditional(expr, noIn, startPos, startLoc, refNeedsArrowPos);
  }

  const state = this.state.clone();

  try {
    return super.parseConditional(expr, noIn, startPos, startLoc);
  } catch (err) {
    if (!(err instanceof SyntaxError)) {
      throw err;
    }

    this.state = state;
    refNeedsArrowPos.start = err.pos || this.state.start;
    return expr;
  }
}

parseParenItem(node, startPos, startLoc) {
  node = super.parseParenItem(node, startPos, startLoc);

  if (this.eat(types.question)) {
    node.optional = true;
    this.resetEndLocation(node);
  }

  if (this.match(types.colon)) {
    const typeCastNode = this.startNodeAt(startPos, startLoc);
    typeCastNode.expression = node;
    typeCastNode.typeAnnotation = this.tsParseTypeAnnotation();
    return this.finishNode(typeCastNode, "TSTypeCastExpression");
  }

  return node;
}

parseExportDeclaration(node) {
  const startPos = this.state.start;
  const startLoc = this.state.startLoc;
  const isDeclare = this.eatContextual("declare");
  let declaration;

  if (this.match(types.name)) {
    declaration = this.tsTryParseExportDeclaration();
  }

  if (!declaration) {
    declaration = super.parseExportDeclaration(node);
  }

  if (declaration && isDeclare) {
    this.resetStartLocation(declaration, startPos, startLoc);
    declaration.declare = true;
  }

  return declaration;
}

parseClassId(node, isStatement, optionalId) {
  if ((!isStatement || optionalId) && this.isContextual("implements")) {
    return;
  }

  super.parseClassId(node, isStatement, optionalId, node.declare ? BIND_TS_AMBIENT : BIND_CLASS);
  const typeParameters = this.tsTryParseTypeParameters();
  if (typeParameters) node.typeParameters = typeParameters;
}

parseClassProperty(node) {
  if (!node.optional && this.eat(types.bang)) {
    node.definite = true;
  }

  const type = this.tsTryParseTypeAnnotation();
  if (type) node.typeAnnotation = type;
  return super.parseClassProperty(node);
}

pushClassMethod(classBody, method, isGenerator, isAsync, isConstructor, allowsDirectSuper) {
  const typeParameters = this.tsTryParseTypeParameters();
  if (typeParameters) method.typeParameters = typeParameters;
  super.pushClassMethod(classBody, method, isGenerator, isAsync, isConstructor, allowsDirectSuper);
}

pushClassPrivateMethod(classBody, method, isGenerator, isAsync) {
  const typeParameters = this.tsTryParseTypeParameters();
  if (typeParameters) method.typeParameters = typeParameters;
  super.pushClassPrivateMethod(classBody, method, isGenerator, isAsync);
}

parseClassSuper(node) {
  super.parseClassSuper(node);

  if (node.superClass && this.isRelational("<")) {
    node.superTypeParameters = this.tsParseTypeArguments();
  }

  if (this.eatContextual("implements")) {
    node.implements = this.tsParseHeritageClause("implements");
  }
}

parseObjPropValue(prop, ...args) {
  const typeParameters = this.tsTryParseTypeParameters();
  if (typeParameters) prop.typeParameters = typeParameters;
  super.parseObjPropValue(prop, ...args);
}

parseFunctionParams(node, allowModifiers) {
  const typeParameters = this.tsTryParseTypeParameters();
  if (typeParameters) node.typeParameters = typeParameters;
  super.parseFunctionParams(node, allowModifiers);
}

parseVarId(decl, kind) {
  super.parseVarId(decl, kind);

  if (decl.id.type === "Identifier" && this.eat(types.bang)) {
    decl.definite = true;
  }

  const type = this.tsTryParseTypeAnnotation();

  if (type) {
    decl.id.typeAnnotation = type;
    this.resetEndLocation(decl.id);
  }
}

parseAsyncArrowFromCallExpression(node, call) {
  if (this.match(types.colon)) {
    node.returnType = this.tsParseTypeAnnotation();
  }

  return super.parseAsyncArrowFromCallExpression(node, call);
}

parseMaybeAssign(...args) {
  let jsxError;

  if (this.match(types.jsxTagStart)) {
    const context = this.curContext();
    assert(context === types$1.j_oTag);
    assert(this.state.context[this.state.context.length - 2] === types$1.j_expr);
    const state = this.state.clone();

    try {
      return super.parseMaybeAssign(...args);
    } catch (err) {
      if (!(err instanceof SyntaxError)) {
        throw err;
      }

      this.state = state;
      assert(this.curContext() === types$1.j_oTag);
      this.state.context.pop();
      assert(this.curContext() === types$1.j_expr);
      this.state.context.pop();
      jsxError = err;
    }
  }

  if (jsxError === undefined && !this.isRelational("<")) {
    return super.parseMaybeAssign(...args);
  }

  let arrowExpression;
  let typeParameters;
  const state = this.state.clone();

  try {
    typeParameters = this.tsParseTypeParameters();
    arrowExpression = super.parseMaybeAssign(...args);

    if (arrowExpression.type !== "ArrowFunctionExpression" || arrowExpression.extra && arrowExpression.extra.parenthesized) {
      this.unexpected();
    }
  } catch (err) {
    if (!(err instanceof SyntaxError)) {
      throw err;
    }

    if (jsxError) {
      throw jsxError;
    }

    assert(!this.hasPlugin("jsx"));
    this.state = state;
    return super.parseMaybeAssign(...args);
  }

  if (typeParameters && typeParameters.params.length !== 0) {
    this.resetStartLocationFromNode(arrowExpression, typeParameters);
  }

  arrowExpression.typeParameters = typeParameters;
  return arrowExpression;
}

parseMaybeUnary(refShorthandDefaultPos) {
  if (!this.hasPlugin("jsx") && this.isRelational("<")) {
    return this.tsParseTypeAssertion();
  } else {
    return super.parseMaybeUnary(refShorthandDefaultPos);
  }
}

parseArrow(node) {
  if (this.match(types.colon)) {
    const state = this.state.clone();

    try {
      const returnType = this.tsParseTypeOrTypePredicateAnnotation(types.colon);

      if (this.canInsertSemicolon() || !this.match(types.arrow)) {
        this.state = state;
        return undefined;
      }

      node.returnType = returnType;
    } catch (err) {
      if (err instanceof SyntaxError) {
        this.state = state;
      } else {
        throw err;
      }
    }
  }

  return super.parseArrow(node);
}

parseAssignableListItemTypes(param) {
  if (this.eat(types.question)) {
    if (param.type !== "Identifier") {
      throw this.raise(param.start, "A binding pattern parameter cannot be optional in an implementation signature.");
    }

    param.optional = true;
  }

  const type = this.tsTryParseTypeAnnotation();
  if (type) param.typeAnnotation = type;
  this.resetEndLocation(param);
  return param;
}

toAssignable(node, isBinding, contextDescription) {
  switch (node.type) {
    case "TSTypeCastExpression":
      return super.toAssignable(this.typeCastToParameter(node), isBinding, contextDescription);

    case "TSParameterProperty":
      return super.toAssignable(node, isBinding, contextDescription);

    case "TSAsExpression":
    case "TSNonNullExpression":
    case "TSTypeAssertion":
      node.expression = this.toAssignable(node.expression, isBinding, contextDescription);
      return node;

    default:
      return super.toAssignable(node, isBinding, contextDescription);
  }
}

checkLVal(expr, bindingType = BIND_NONE, checkClashes, contextDescription) {
  switch (expr.type) {
    case "TSTypeCastExpression":
      return;

    case "TSParameterProperty":
      this.checkLVal(expr.parameter, bindingType, checkClashes, "parameter property");
      return;

    case "TSAsExpression":
    case "TSNonNullExpression":
    case "TSTypeAssertion":
      this.checkLVal(expr.expression, bindingType, checkClashes, contextDescription);
      return;

    default:
      super.checkLVal(expr, bindingType, checkClashes, contextDescription);
      return;
  }
}

parseBindingAtom() {
  switch (this.state.type) {
    case types._this:
      return this.parseIdentifier(true);

    default:
      return super.parseBindingAtom();
  }
}

parseMaybeDecoratorArguments(expr) {
  if (this.isRelational("<")) {
    const typeArguments = this.tsParseTypeArguments();

    if (this.match(types.parenL)) {
      const call = super.parseMaybeDecoratorArguments(expr);
      call.typeParameters = typeArguments;
      return call;
    }

    this.unexpected(this.state.start, types.parenL);
  }

  return super.parseMaybeDecoratorArguments(expr);
}

isClassMethod() {
  return this.isRelational("<") || super.isClassMethod();
}

isClassProperty() {
  return this.match(types.bang) || this.match(types.colon) || super.isClassProperty();
}

parseMaybeDefault(...args) {
  const node = super.parseMaybeDefault(...args);

  if (node.type === "AssignmentPattern" && node.typeAnnotation && node.right.start < node.typeAnnotation.start) {
    this.raise(node.typeAnnotation.start, "Type annotations must come before default assignments, " + "e.g. instead of `age = 25: number` use `age: number = 25`");
  }

  return node;
}

getTokenFromCode(code) {
  if (this.state.inType && (code === 62 || code === 60)) {
    return this.finishOp(types.relational, 1);
  } else {
    return super.getTokenFromCode(code);
  }
}

toAssignableList(exprList) {
  for (let i = 0; i < exprList.length; i++) {
    const expr = exprList[i];
    if (!expr) continue;

    switch (expr.type) {
      case "TSTypeCastExpression":
        exprList[i] = this.typeCastToParameter(expr);
        break;

      case "TSAsExpression":
      case "TSTypeAssertion":
        this.raise(expr.start, "Unexpected type cast in parameter position.");
        break;
    }
  }

  return super.toAssignableList(...arguments);
}

typeCastToParameter(node) {
  node.expression.typeAnnotation = node.typeAnnotation;
  this.resetEndLocation(node.expression, node.typeAnnotation.end, node.typeAnnotation.loc.end);
  return node.expression;
}

toReferencedList(exprList, isInParens) {
  for (let i = 0; i < exprList.length; i++) {
    const expr = exprList[i];

    if (expr && expr._exprListItem && expr.type === "TsTypeCastExpression") {
      this.raise(expr.start, "Did not expect a type annotation here.");
    }
  }

  return exprList;
}

shouldParseArrow() {
  return this.match(types.colon) || super.shouldParseArrow();
}

shouldParseAsyncArrow() {
  return this.match(types.colon) || super.shouldParseAsyncArrow();
}

canHaveLeadingDecorator() {
  return super.canHaveLeadingDecorator() || this.isAbstractClass();
}

jsxParseOpeningElementAfterName(node) {
  if (this.isRelational("<")) {
    const typeArguments = this.tsTryParseAndCatch(() => this.tsParseTypeArguments());
    if (typeArguments) node.typeParameters = typeArguments;
  }

  return super.jsxParseOpeningElementAfterName(node);
}

getGetterSetterExpectedParamCount(method) {
  const baseCount = super.getGetterSetterExpectedParamCount(method);
  const firstParam = method.params[0];
  const hasContextParam = firstParam && firstParam.type === "Identifier" && firstParam.name === "this";
  return hasContextParam ? baseCount + 1 : baseCount;
}

});

types.placeholder = new TokenType(“%%”, {

startsExpr: true

}); var placeholders = (superClass => class extends superClass {

parsePlaceholder(expectedNode) {
  if (this.match(types.placeholder)) {
    const node = this.startNode();
    this.next();
    this.assertNoSpace("Unexpected space in placeholder.");
    node.name = super.parseIdentifier(true);
    this.assertNoSpace("Unexpected space in placeholder.");
    this.expect(types.placeholder);
    return this.finishPlaceholder(node, expectedNode);
  }
}

finishPlaceholder(node, expectedNode) {
  const isFinished = !!(node.expectedNode && node.type === "Placeholder");
  node.expectedNode = expectedNode;
  return isFinished ? node : this.finishNode(node, "Placeholder");
}

getTokenFromCode(code) {
  if (code === 37 && this.input.charCodeAt(this.state.pos + 1) === 37) {
    return this.finishOp(types.placeholder, 2);
  }

  return super.getTokenFromCode(...arguments);
}

parseExprAtom() {
  return this.parsePlaceholder("Expression") || super.parseExprAtom(...arguments);
}

parseIdentifier() {
  return this.parsePlaceholder("Identifier") || super.parseIdentifier(...arguments);
}

checkReservedWord(word) {
  if (word !== undefined) super.checkReservedWord(...arguments);
}

parseBindingAtom() {
  return this.parsePlaceholder("Pattern") || super.parseBindingAtom(...arguments);
}

checkLVal(expr) {
  if (expr.type !== "Placeholder") super.checkLVal(...arguments);
}

toAssignable(node) {
  if (node && node.type === "Placeholder" && node.expectedNode === "Expression") {
    node.expectedNode = "Pattern";
    return node;
  }

  return super.toAssignable(...arguments);
}

verifyBreakContinue(node) {
  if (node.label && node.label.type === "Placeholder") return;
  super.verifyBreakContinue(...arguments);
}

parseExpressionStatement(node, expr) {
  if (expr.type !== "Placeholder" || expr.extra && expr.extra.parenthesized) {
    return super.parseExpressionStatement(...arguments);
  }

  if (this.match(types.colon)) {
    const stmt = node;
    stmt.label = this.finishPlaceholder(expr, "Identifier");
    this.next();
    stmt.body = this.parseStatement("label");
    return this.finishNode(stmt, "LabeledStatement");
  }

  this.semicolon();
  node.name = expr.name;
  return this.finishPlaceholder(node, "Statement");
}

parseBlock() {
  return this.parsePlaceholder("BlockStatement") || super.parseBlock(...arguments);
}

parseFunctionId() {
  return this.parsePlaceholder("Identifier") || super.parseFunctionId(...arguments);
}

parseClass(node, isStatement, optionalId) {
  const type = isStatement ? "ClassDeclaration" : "ClassExpression";
  this.next();
  this.takeDecorators(node);
  const placeholder = this.parsePlaceholder("Identifier");

  if (placeholder) {
    if (this.match(types._extends) || this.match(types.placeholder) || this.match(types.braceL)) {
      node.id = placeholder;
    } else if (optionalId || !isStatement) {
      node.id = null;
      node.body = this.finishPlaceholder(placeholder, "ClassBody");
      return this.finishNode(node, type);
    } else {
      this.unexpected(null, "A class name is required");
    }
  } else {
    this.parseClassId(node, isStatement, optionalId);
  }

  this.parseClassSuper(node);
  node.body = this.parsePlaceholder("ClassBody") || this.parseClassBody(!!node.superClass);
  return this.finishNode(node, type);
}

parseExport(node) {
  const placeholder = this.parsePlaceholder("Identifier");
  if (!placeholder) return super.parseExport(...arguments);

  if (!this.isContextual("from") && !this.match(types.comma)) {
    node.specifiers = [];
    node.source = null;
    node.declaration = this.finishPlaceholder(placeholder, "Declaration");
    return this.finishNode(node, "ExportNamedDeclaration");
  }

  this.expectPlugin("exportDefaultFrom");
  const specifier = this.startNode();
  specifier.exported = placeholder;
  node.specifiers = [this.finishNode(specifier, "ExportDefaultSpecifier")];
  return super.parseExport(node);
}

maybeParseExportDefaultSpecifier(node) {
  if (node.specifiers && node.specifiers.length > 0) {
    return true;
  }

  return super.maybeParseExportDefaultSpecifier(...arguments);
}

checkExport(node) {
  const {
    specifiers
  } = node;

  if (specifiers && specifiers.length) {
    node.specifiers = specifiers.filter(node => node.exported.type === "Placeholder");
  }

  super.checkExport(node);
  node.specifiers = specifiers;
}

parseImport(node) {
  const placeholder = this.parsePlaceholder("Identifier");
  if (!placeholder) return super.parseImport(...arguments);
  node.specifiers = [];

  if (!this.isContextual("from") && !this.match(types.comma)) {
    node.source = this.finishPlaceholder(placeholder, "StringLiteral");
    this.semicolon();
    return this.finishNode(node, "ImportDeclaration");
  }

  const specifier = this.startNodeAtNode(placeholder);
  specifier.local = placeholder;
  this.finishNode(specifier, "ImportDefaultSpecifier");
  node.specifiers.push(specifier);

  if (this.eat(types.comma)) {
    const hasStarImport = this.maybeParseStarImportSpecifier(node);
    if (!hasStarImport) this.parseNamedImportSpecifiers(node);
  }

  this.expectContextual("from");
  node.source = this.parseImportSource();
  this.semicolon();
  return this.finishNode(node, "ImportDeclaration");
}

parseImportSource() {
  return this.parsePlaceholder("StringLiteral") || super.parseImportSource(...arguments);
}

});

var v8intrinsic = (superClass => class extends superClass {

parseV8Intrinsic() {
  if (this.match(types.modulo)) {
    const v8IntrinsicStart = this.state.start;
    const node = this.startNode();
    this.eat(types.modulo);

    if (this.match(types.name)) {
      const name = this.parseIdentifierName(this.state.start);
      const identifier = this.createIdentifier(node, name);
      identifier.type = "V8IntrinsicIdentifier";

      if (this.match(types.parenL)) {
        return identifier;
      }
    }

    this.unexpected(v8IntrinsicStart);
  }
}

parseExprAtom() {
  return this.parseV8Intrinsic() || super.parseExprAtom(...arguments);
}

});

function hasPlugin(plugins, name) {

return plugins.some(plugin => {
  if (Array.isArray(plugin)) {
    return plugin[0] === name;
  } else {
    return plugin === name;
  }
});

} function getPluginOption(plugins, name, option) {

const plugin = plugins.find(plugin => {
  if (Array.isArray(plugin)) {
    return plugin[0] === name;
  } else {
    return plugin === name;
  }
});

if (plugin && Array.isArray(plugin)) {
  return plugin[1][option];
}

return null;

} const PIPELINE_PROPOSALS = [“minimal”, “smart”, “fsharp”]; function validatePlugins(plugins) {

if (hasPlugin(plugins, "decorators")) {
  if (hasPlugin(plugins, "decorators-legacy")) {
    throw new Error("Cannot use the decorators and decorators-legacy plugin together");
  }

  const decoratorsBeforeExport = getPluginOption(plugins, "decorators", "decoratorsBeforeExport");

  if (decoratorsBeforeExport == null) {
    throw new Error("The 'decorators' plugin requires a 'decoratorsBeforeExport' option," + " whose value must be a boolean. If you are migrating from" + " Babylon/Babel 6 or want to use the old decorators proposal, you" + " should use the 'decorators-legacy' plugin instead of 'decorators'.");
  } else if (typeof decoratorsBeforeExport !== "boolean") {
    throw new Error("'decoratorsBeforeExport' must be a boolean.");
  }
}

if (hasPlugin(plugins, "flow") && hasPlugin(plugins, "typescript")) {
  throw new Error("Cannot combine flow and typescript plugins.");
}

if (hasPlugin(plugins, "placeholders") && hasPlugin(plugins, "v8intrinsic")) {
  throw new Error("Cannot combine placeholders and v8intrinsic plugins.");
}

if (hasPlugin(plugins, "pipelineOperator") && !PIPELINE_PROPOSALS.includes(getPluginOption(plugins, "pipelineOperator", "proposal"))) {
  throw new Error("'pipelineOperator' requires 'proposal' option whose value should be one of: " + PIPELINE_PROPOSALS.map(p => `'${p}'`).join(", "));
}

} const mixinPlugins = {

estree,
jsx,
flow,
typescript,
v8intrinsic,
placeholders

}; const mixinPluginNames = Object.keys(mixinPlugins);

const defaultOptions = {

sourceType: "script",
sourceFilename: undefined,
startLine: 1,
allowAwaitOutsideFunction: false,
allowReturnOutsideFunction: false,
allowImportExportEverywhere: false,
allowSuperOutsideMethod: false,
allowUndeclaredExports: false,
plugins: [],
strictMode: null,
ranges: false,
tokens: false,
createParenthesizedExpressions: false

}; function getOptions(opts) {

const options = {};

for (let _i = 0, _Object$keys = Object.keys(defaultOptions); _i < _Object$keys.length; _i++) {
  const key = _Object$keys[_i];
  options[key] = opts && opts[key] != null ? opts[key] : defaultOptions[key];
}

return options;

}

class Position {

constructor(line, col) {
  this.line = line;
  this.column = col;
}

} class SourceLocation {

constructor(start, end) {
  this.start = start;
  this.end = end;
}

} function getLineInfo(input, offset) {

let line = 1;
let lineStart = 0;
let match;
lineBreakG.lastIndex = 0;

while ((match = lineBreakG.exec(input)) && match.index < offset) {
  line++;
  lineStart = lineBreakG.lastIndex;
}

return new Position(line, offset - lineStart);

}

class BaseParser {

constructor() {
  this.sawUnambiguousESM = false;
}

hasPlugin(name) {
  return this.plugins.has(name);
}

getPluginOption(plugin, name) {
  if (this.hasPlugin(plugin)) return this.plugins.get(plugin)[name];
}

}

function last(stack) {

return stack[stack.length - 1];

}

class CommentsParser extends BaseParser {

addComment(comment) {
  if (this.filename) comment.loc.filename = this.filename;
  this.state.trailingComments.push(comment);
  this.state.leadingComments.push(comment);
}

adjustCommentsAfterTrailingComma(node, elements, takeAllComments) {
  if (this.state.leadingComments.length === 0) {
    return;
  }

  let lastElement = null;
  let i = elements.length;

  while (lastElement === null && i > 0) {
    lastElement = elements[--i];
  }

  if (lastElement === null) {
    return;
  }

  for (let j = 0; j < this.state.leadingComments.length; j++) {
    if (this.state.leadingComments[j].end < this.state.commentPreviousNode.end) {
      this.state.leadingComments.splice(j, 1);
      j--;
    }
  }

  const newTrailingComments = [];

  for (let i = 0; i < this.state.leadingComments.length; i++) {
    const leadingComment = this.state.leadingComments[i];

    if (leadingComment.end < node.end) {
      newTrailingComments.push(leadingComment);

      if (!takeAllComments) {
        this.state.leadingComments.splice(i, 1);
        i--;
      }
    } else {
      if (node.trailingComments === undefined) {
        node.trailingComments = [];
      }

      node.trailingComments.push(leadingComment);
    }
  }

  if (takeAllComments) this.state.leadingComments = [];

  if (newTrailingComments.length > 0) {
    lastElement.trailingComments = newTrailingComments;
  } else if (lastElement.trailingComments !== undefined) {
    lastElement.trailingComments = [];
  }
}

processComment(node) {
  if (node.type === "Program" && node.body.length > 0) return;
  const stack = this.state.commentStack;
  let firstChild, lastChild, trailingComments, i, j;

  if (this.state.trailingComments.length > 0) {
    if (this.state.trailingComments[0].start >= node.end) {
      trailingComments = this.state.trailingComments;
      this.state.trailingComments = [];
    } else {
      this.state.trailingComments.length = 0;
    }
  } else if (stack.length > 0) {
    const lastInStack = last(stack);

    if (lastInStack.trailingComments && lastInStack.trailingComments[0].start >= node.end) {
      trailingComments = lastInStack.trailingComments;
      delete lastInStack.trailingComments;
    }
  }

  if (stack.length > 0 && last(stack).start >= node.start) {
    firstChild = stack.pop();
  }

  while (stack.length > 0 && last(stack).start >= node.start) {
    lastChild = stack.pop();
  }

  if (!lastChild && firstChild) lastChild = firstChild;

  if (firstChild) {
    switch (node.type) {
      case "ObjectExpression":
        this.adjustCommentsAfterTrailingComma(node, node.properties);
        break;

      case "ObjectPattern":
        this.adjustCommentsAfterTrailingComma(node, node.properties, true);
        break;

      case "CallExpression":
        this.adjustCommentsAfterTrailingComma(node, node.arguments);
        break;

      case "ArrayExpression":
        this.adjustCommentsAfterTrailingComma(node, node.elements);
        break;

      case "ArrayPattern":
        this.adjustCommentsAfterTrailingComma(node, node.elements, true);
        break;
    }
  } else if (this.state.commentPreviousNode && (this.state.commentPreviousNode.type === "ImportSpecifier" && node.type !== "ImportSpecifier" || this.state.commentPreviousNode.type === "ExportSpecifier" && node.type !== "ExportSpecifier")) {
    this.adjustCommentsAfterTrailingComma(node, [this.state.commentPreviousNode], true);
  }

  if (lastChild) {
    if (lastChild.leadingComments) {
      if (lastChild !== node && lastChild.leadingComments.length > 0 && last(lastChild.leadingComments).end <= node.start) {
        node.leadingComments = lastChild.leadingComments;
        delete lastChild.leadingComments;
      } else {
        for (i = lastChild.leadingComments.length - 2; i >= 0; --i) {
          if (lastChild.leadingComments[i].end <= node.start) {
            node.leadingComments = lastChild.leadingComments.splice(0, i + 1);
            break;
          }
        }
      }
    }
  } else if (this.state.leadingComments.length > 0) {
    if (last(this.state.leadingComments).end <= node.start) {
      if (this.state.commentPreviousNode) {
        for (j = 0; j < this.state.leadingComments.length; j++) {
          if (this.state.leadingComments[j].end < this.state.commentPreviousNode.end) {
            this.state.leadingComments.splice(j, 1);
            j--;
          }
        }
      }

      if (this.state.leadingComments.length > 0) {
        node.leadingComments = this.state.leadingComments;
        this.state.leadingComments = [];
      }
    } else {
      for (i = 0; i < this.state.leadingComments.length; i++) {
        if (this.state.leadingComments[i].end > node.start) {
          break;
        }
      }

      const leadingComments = this.state.leadingComments.slice(0, i);

      if (leadingComments.length) {
        node.leadingComments = leadingComments;
      }

      trailingComments = this.state.leadingComments.slice(i);

      if (trailingComments.length === 0) {
        trailingComments = null;
      }
    }
  }

  this.state.commentPreviousNode = node;

  if (trailingComments) {
    if (trailingComments.length && trailingComments[0].start >= node.start && last(trailingComments).end <= node.end) {
      node.innerComments = trailingComments;
    } else {
      node.trailingComments = trailingComments;
    }
  }

  stack.push(node);
}

}

class LocationParser extends CommentsParser {

getLocationForPosition(pos) {
  let loc;
  if (pos === this.state.start) loc = this.state.startLoc;else if (pos === this.state.lastTokStart) loc = this.state.lastTokStartLoc;else if (pos === this.state.end) loc = this.state.endLoc;else if (pos === this.state.lastTokEnd) loc = this.state.lastTokEndLoc;else loc = getLineInfo(this.input, pos);
  return loc;
}

raise(pos, message, {
  missingPluginNames,
  code
} = {}) {
  const loc = this.getLocationForPosition(pos);
  message += ` (${loc.line}:${loc.column})`;
  const err = new SyntaxError(message);
  err.pos = pos;
  err.loc = loc;

  if (missingPluginNames) {
    err.missingPlugin = missingPluginNames;
  }

  if (code !== undefined) {
    err.code = code;
  }

  throw err;
}

}

class State {

constructor() {
  this.potentialArrowAt = -1;
  this.noArrowAt = [];
  this.noArrowParamsConversionAt = [];
  this.inParameters = false;
  this.maybeInArrowParameters = false;
  this.inPipeline = false;
  this.inType = false;
  this.noAnonFunctionType = false;
  this.inPropertyName = false;
  this.inClassProperty = false;
  this.hasFlowComment = false;
  this.isIterator = false;
  this.topicContext = {
    maxNumOfResolvableTopics: 0,
    maxTopicIndex: null
  };
  this.soloAwait = false;
  this.inFSharpPipelineDirectBody = false;
  this.classLevel = 0;
  this.labels = [];
  this.decoratorStack = [[]];
  this.yieldPos = -1;
  this.awaitPos = -1;
  this.tokens = [];
  this.comments = [];
  this.trailingComments = [];
  this.leadingComments = [];
  this.commentStack = [];
  this.commentPreviousNode = null;
  this.pos = 0;
  this.lineStart = 0;
  this.type = types.eof;
  this.value = null;
  this.start = 0;
  this.end = 0;
  this.lastTokEndLoc = null;
  this.lastTokStartLoc = null;
  this.lastTokStart = 0;
  this.lastTokEnd = 0;
  this.context = [types$1.braceStatement];
  this.exprAllowed = true;
  this.containsEsc = false;
  this.containsOctal = false;
  this.octalPosition = null;
  this.exportedIdentifiers = [];
  this.invalidTemplateEscapePosition = null;
}

init(options) {
  this.strict = options.strictMode === false ? false : options.sourceType === "module";
  this.curLine = options.startLine;
  this.startLoc = this.endLoc = this.curPosition();
}

curPosition() {
  return new Position(this.curLine, this.pos - this.lineStart);
}

clone(skipArrays) {
  const state = new State();
  const keys = Object.keys(this);

  for (let i = 0, length = keys.length; i < length; i++) {
    const key = keys[i];
    let val = this[key];

    if (!skipArrays && Array.isArray(val)) {
      val = val.slice();
    }

    state[key] = val;
  }

  return state;
}

}

var _isDigit = function isDigit(code) {

return code >= 48 && code <= 57;

}; const VALID_REGEX_FLAGS = new Set([“g”, “m”, “s”, “i”, “y”, “u”]); const forbiddenNumericSeparatorSiblings = {

decBinOct: [46, 66, 69, 79, 95, 98, 101, 111],
hex: [46, 88, 95, 120]

}; const allowedNumericSeparatorSiblings = {}; allowedNumericSeparatorSiblings.bin = [48, 49]; allowedNumericSeparatorSiblings.oct = […allowedNumericSeparatorSiblings.bin, 50, 51, 52, 53, 54, 55]; allowedNumericSeparatorSiblings.dec = […allowedNumericSeparatorSiblings.oct, 56, 57]; allowedNumericSeparatorSiblings.hex = […allowedNumericSeparatorSiblings.dec, 65, 66, 67, 68, 69, 70, 97, 98, 99, 100, 101, 102]; class Token {

constructor(state) {
  this.type = state.type;
  this.value = state.value;
  this.start = state.start;
  this.end = state.end;
  this.loc = new SourceLocation(state.startLoc, state.endLoc);
}

} class Tokenizer extends LocationParser {

constructor(options, input) {
  super();
  this.state = new State();
  this.state.init(options);
  this.input = input;
  this.length = input.length;
  this.isLookahead = false;
}

next() {
  if (this.options.tokens && !this.isLookahead) {
    this.state.tokens.push(new Token(this.state));
  }

  this.state.lastTokEnd = this.state.end;
  this.state.lastTokStart = this.state.start;
  this.state.lastTokEndLoc = this.state.endLoc;
  this.state.lastTokStartLoc = this.state.startLoc;
  this.nextToken();
}

eat(type) {
  if (this.match(type)) {
    this.next();
    return true;
  } else {
    return false;
  }
}

match(type) {
  return this.state.type === type;
}

lookahead() {
  const old = this.state;
  this.state = old.clone(true);
  this.isLookahead = true;
  this.next();
  this.isLookahead = false;
  const curr = this.state;
  this.state = old;
  return curr;
}

nextTokenStart() {
  const thisTokEnd = this.state.pos;
  skipWhiteSpace.lastIndex = thisTokEnd;
  const skip = skipWhiteSpace.exec(this.input);
  return thisTokEnd + skip[0].length;
}

lookaheadCharCode() {
  return this.input.charCodeAt(this.nextTokenStart());
}

setStrict(strict) {
  this.state.strict = strict;
  if (!this.match(types.num) && !this.match(types.string)) return;
  this.state.pos = this.state.start;

  while (this.state.pos < this.state.lineStart) {
    this.state.lineStart = this.input.lastIndexOf("\n", this.state.lineStart - 2) + 1;
    --this.state.curLine;
  }

  this.nextToken();
}

curContext() {
  return this.state.context[this.state.context.length - 1];
}

nextToken() {
  const curContext = this.curContext();
  if (!curContext || !curContext.preserveSpace) this.skipSpace();
  this.state.containsOctal = false;
  this.state.octalPosition = null;
  this.state.start = this.state.pos;
  this.state.startLoc = this.state.curPosition();

  if (this.state.pos >= this.length) {
    this.finishToken(types.eof);
    return;
  }

  if (curContext.override) {
    curContext.override(this);
  } else {
    this.getTokenFromCode(this.input.codePointAt(this.state.pos));
  }
}

pushComment(block, text, start, end, startLoc, endLoc) {
  const comment = {
    type: block ? "CommentBlock" : "CommentLine",
    value: text,
    start: start,
    end: end,
    loc: new SourceLocation(startLoc, endLoc)
  };
  if (this.options.tokens) this.state.tokens.push(comment);
  this.state.comments.push(comment);
  this.addComment(comment);
}

skipBlockComment() {
  const startLoc = this.state.curPosition();
  const start = this.state.pos;
  const end = this.input.indexOf("*/", this.state.pos + 2);
  if (end === -1) this.raise(start, "Unterminated comment");
  this.state.pos = end + 2;
  lineBreakG.lastIndex = start;
  let match;

  while ((match = lineBreakG.exec(this.input)) && match.index < this.state.pos) {
    ++this.state.curLine;
    this.state.lineStart = match.index + match[0].length;
  }

  if (this.isLookahead) return;
  this.pushComment(true, this.input.slice(start + 2, end), start, this.state.pos, startLoc, this.state.curPosition());
}

skipLineComment(startSkip) {
  const start = this.state.pos;
  const startLoc = this.state.curPosition();
  let ch = this.input.charCodeAt(this.state.pos += startSkip);

  if (this.state.pos < this.length) {
    while (!isNewLine(ch) && ++this.state.pos < this.length) {
      ch = this.input.charCodeAt(this.state.pos);
    }
  }

  if (this.isLookahead) return;
  this.pushComment(false, this.input.slice(start + startSkip, this.state.pos), start, this.state.pos, startLoc, this.state.curPosition());
}

skipSpace() {
  loop: while (this.state.pos < this.length) {
    const ch = this.input.charCodeAt(this.state.pos);

    switch (ch) {
      case 32:
      case 160:
      case 9:
        ++this.state.pos;
        break;

      case 13:
        if (this.input.charCodeAt(this.state.pos + 1) === 10) {
          ++this.state.pos;
        }

      case 10:
      case 8232:
      case 8233:
        ++this.state.pos;
        ++this.state.curLine;
        this.state.lineStart = this.state.pos;
        break;

      case 47:
        switch (this.input.charCodeAt(this.state.pos + 1)) {
          case 42:
            this.skipBlockComment();
            break;

          case 47:
            this.skipLineComment(2);
            break;

          default:
            break loop;
        }

        break;

      default:
        if (isWhitespace(ch)) {
          ++this.state.pos;
        } else {
          break loop;
        }

    }
  }
}

finishToken(type, val) {
  this.state.end = this.state.pos;
  this.state.endLoc = this.state.curPosition();
  const prevType = this.state.type;
  this.state.type = type;
  this.state.value = val;
  if (!this.isLookahead) this.updateContext(prevType);
}

readToken_numberSign() {
  if (this.state.pos === 0 && this.readToken_interpreter()) {
    return;
  }

  const nextPos = this.state.pos + 1;
  const next = this.input.charCodeAt(nextPos);

  if (next >= 48 && next <= 57) {
    this.raise(this.state.pos, "Unexpected digit after hash token");
  }

  if ((this.hasPlugin("classPrivateProperties") || this.hasPlugin("classPrivateMethods")) && this.state.classLevel > 0) {
    ++this.state.pos;
    this.finishToken(types.hash);
    return;
  } else if (this.getPluginOption("pipelineOperator", "proposal") === "smart") {
    this.finishOp(types.hash, 1);
  } else {
    this.raise(this.state.pos, "Unexpected character '#'");
  }
}

readToken_dot() {
  const next = this.input.charCodeAt(this.state.pos + 1);

  if (next >= 48 && next <= 57) {
    this.readNumber(true);
    return;
  }

  if (next === 46 && this.input.charCodeAt(this.state.pos + 2) === 46) {
    this.state.pos += 3;
    this.finishToken(types.ellipsis);
  } else {
    ++this.state.pos;
    this.finishToken(types.dot);
  }
}

readToken_slash() {
  if (this.state.exprAllowed && !this.state.inType) {
    ++this.state.pos;
    this.readRegexp();
    return;
  }

  const next = this.input.charCodeAt(this.state.pos + 1);

  if (next === 61) {
    this.finishOp(types.assign, 2);
  } else {
    this.finishOp(types.slash, 1);
  }
}

readToken_interpreter() {
  if (this.state.pos !== 0 || this.length < 2) return false;
  const start = this.state.pos;
  this.state.pos += 1;
  let ch = this.input.charCodeAt(this.state.pos);
  if (ch !== 33) return false;

  while (!isNewLine(ch) && ++this.state.pos < this.length) {
    ch = this.input.charCodeAt(this.state.pos);
  }

  const value = this.input.slice(start + 2, this.state.pos);
  this.finishToken(types.interpreterDirective, value);
  return true;
}

readToken_mult_modulo(code) {
  let type = code === 42 ? types.star : types.modulo;
  let width = 1;
  let next = this.input.charCodeAt(this.state.pos + 1);
  const exprAllowed = this.state.exprAllowed;

  if (code === 42 && next === 42) {
    width++;
    next = this.input.charCodeAt(this.state.pos + 2);
    type = types.exponent;
  }

  if (next === 61 && !exprAllowed) {
    width++;
    type = types.assign;
  }

  this.finishOp(type, width);
}

readToken_pipe_amp(code) {
  const next = this.input.charCodeAt(this.state.pos + 1);

  if (next === code) {
    if (this.input.charCodeAt(this.state.pos + 2) === 61) {
      this.finishOp(types.assign, 3);
    } else {
      this.finishOp(code === 124 ? types.logicalOR : types.logicalAND, 2);
    }

    return;
  }

  if (code === 124) {
    if (next === 62) {
      this.finishOp(types.pipeline, 2);
      return;
    }
  }

  if (next === 61) {
    this.finishOp(types.assign, 2);
    return;
  }

  this.finishOp(code === 124 ? types.bitwiseOR : types.bitwiseAND, 1);
}

readToken_caret() {
  const next = this.input.charCodeAt(this.state.pos + 1);

  if (next === 61) {
    this.finishOp(types.assign, 2);
  } else {
    this.finishOp(types.bitwiseXOR, 1);
  }
}

readToken_plus_min(code) {
  const next = this.input.charCodeAt(this.state.pos + 1);

  if (next === code) {
    if (next === 45 && !this.inModule && this.input.charCodeAt(this.state.pos + 2) === 62 && (this.state.lastTokEnd === 0 || lineBreak.test(this.input.slice(this.state.lastTokEnd, this.state.pos)))) {
      this.skipLineComment(3);
      this.skipSpace();
      this.nextToken();
      return;
    }

    this.finishOp(types.incDec, 2);
    return;
  }

  if (next === 61) {
    this.finishOp(types.assign, 2);
  } else {
    this.finishOp(types.plusMin, 1);
  }
}

readToken_lt_gt(code) {
  const next = this.input.charCodeAt(this.state.pos + 1);
  let size = 1;

  if (next === code) {
    size = code === 62 && this.input.charCodeAt(this.state.pos + 2) === 62 ? 3 : 2;

    if (this.input.charCodeAt(this.state.pos + size) === 61) {
      this.finishOp(types.assign, size + 1);
      return;
    }

    this.finishOp(types.bitShift, size);
    return;
  }

  if (next === 33 && code === 60 && !this.inModule && this.input.charCodeAt(this.state.pos + 2) === 45 && this.input.charCodeAt(this.state.pos + 3) === 45) {
    this.skipLineComment(4);
    this.skipSpace();
    this.nextToken();
    return;
  }

  if (next === 61) {
    size = 2;
  }

  this.finishOp(types.relational, size);
}

readToken_eq_excl(code) {
  const next = this.input.charCodeAt(this.state.pos + 1);

  if (next === 61) {
    this.finishOp(types.equality, this.input.charCodeAt(this.state.pos + 2) === 61 ? 3 : 2);
    return;
  }

  if (code === 61 && next === 62) {
    this.state.pos += 2;
    this.finishToken(types.arrow);
    return;
  }

  this.finishOp(code === 61 ? types.eq : types.bang, 1);
}

readToken_question() {
  const next = this.input.charCodeAt(this.state.pos + 1);
  const next2 = this.input.charCodeAt(this.state.pos + 2);

  if (next === 63 && !this.state.inType) {
    if (next2 === 61) {
      this.finishOp(types.assign, 3);
    } else {
      this.finishOp(types.nullishCoalescing, 2);
    }
  } else if (next === 46 && !(next2 >= 48 && next2 <= 57)) {
    this.state.pos += 2;
    this.finishToken(types.questionDot);
  } else {
    ++this.state.pos;
    this.finishToken(types.question);
  }
}

getTokenFromCode(code) {
  switch (code) {
    case 46:
      this.readToken_dot();
      return;

    case 40:
      ++this.state.pos;
      this.finishToken(types.parenL);
      return;

    case 41:
      ++this.state.pos;
      this.finishToken(types.parenR);
      return;

    case 59:
      ++this.state.pos;
      this.finishToken(types.semi);
      return;

    case 44:
      ++this.state.pos;
      this.finishToken(types.comma);
      return;

    case 91:
      ++this.state.pos;
      this.finishToken(types.bracketL);
      return;

    case 93:
      ++this.state.pos;
      this.finishToken(types.bracketR);
      return;

    case 123:
      ++this.state.pos;
      this.finishToken(types.braceL);
      return;

    case 125:
      ++this.state.pos;
      this.finishToken(types.braceR);
      return;

    case 58:
      if (this.hasPlugin("functionBind") && this.input.charCodeAt(this.state.pos + 1) === 58) {
        this.finishOp(types.doubleColon, 2);
      } else {
        ++this.state.pos;
        this.finishToken(types.colon);
      }

      return;

    case 63:
      this.readToken_question();
      return;

    case 96:
      ++this.state.pos;
      this.finishToken(types.backQuote);
      return;

    case 48:
      {
        const next = this.input.charCodeAt(this.state.pos + 1);

        if (next === 120 || next === 88) {
          this.readRadixNumber(16);
          return;
        }

        if (next === 111 || next === 79) {
          this.readRadixNumber(8);
          return;
        }

        if (next === 98 || next === 66) {
          this.readRadixNumber(2);
          return;
        }
      }

    case 49:
    case 50:
    case 51:
    case 52:
    case 53:
    case 54:
    case 55:
    case 56:
    case 57:
      this.readNumber(false);
      return;

    case 34:
    case 39:
      this.readString(code);
      return;

    case 47:
      this.readToken_slash();
      return;

    case 37:
    case 42:
      this.readToken_mult_modulo(code);
      return;

    case 124:
    case 38:
      this.readToken_pipe_amp(code);
      return;

    case 94:
      this.readToken_caret();
      return;

    case 43:
    case 45:
      this.readToken_plus_min(code);
      return;

    case 60:
    case 62:
      this.readToken_lt_gt(code);
      return;

    case 61:
    case 33:
      this.readToken_eq_excl(code);
      return;

    case 126:
      this.finishOp(types.tilde, 1);
      return;

    case 64:
      ++this.state.pos;
      this.finishToken(types.at);
      return;

    case 35:
      this.readToken_numberSign();
      return;

    case 92:
      this.readWord();
      return;

    default:
      if (isIdentifierStart(code)) {
        this.readWord();
        return;
      }

  }

  this.raise(this.state.pos, `Unexpected character '${String.fromCodePoint(code)}'`);
}

finishOp(type, size) {
  const str = this.input.slice(this.state.pos, this.state.pos + size);
  this.state.pos += size;
  this.finishToken(type, str);
}

readRegexp() {
  const start = this.state.pos;
  let escaped, inClass;

  for (;;) {
    if (this.state.pos >= this.length) {
      this.raise(start, "Unterminated regular expression");
    }

    const ch = this.input.charAt(this.state.pos);

    if (lineBreak.test(ch)) {
      this.raise(start, "Unterminated regular expression");
    }

    if (escaped) {
      escaped = false;
    } else {
      if (ch === "[") {
        inClass = true;
      } else if (ch === "]" && inClass) {
        inClass = false;
      } else if (ch === "/" && !inClass) {
        break;
      }

      escaped = ch === "\\";
    }

    ++this.state.pos;
  }

  const content = this.input.slice(start, this.state.pos);
  ++this.state.pos;
  let mods = "";

  while (this.state.pos < this.length) {
    const char = this.input[this.state.pos];
    const charCode = this.input.codePointAt(this.state.pos);

    if (VALID_REGEX_FLAGS.has(char)) {
      if (mods.indexOf(char) > -1) {
        this.raise(this.state.pos + 1, "Duplicate regular expression flag");
      }

      ++this.state.pos;
      mods += char;
    } else if (isIdentifierChar(charCode) || charCode === 92) {
      this.raise(this.state.pos + 1, "Invalid regular expression flag");
    } else {
      break;
    }
  }

  this.finishToken(types.regexp, {
    pattern: content,
    flags: mods
  });
}

readInt(radix, len, allowNumSeparator = true) {
  const start = this.state.pos;
  const forbiddenSiblings = radix === 16 ? forbiddenNumericSeparatorSiblings.hex : forbiddenNumericSeparatorSiblings.decBinOct;
  const allowedSiblings = radix === 16 ? allowedNumericSeparatorSiblings.hex : radix === 10 ? allowedNumericSeparatorSiblings.dec : radix === 8 ? allowedNumericSeparatorSiblings.oct : allowedNumericSeparatorSiblings.bin;
  let total = 0;

  for (let i = 0, e = len == null ? Infinity : len; i < e; ++i) {
    const code = this.input.charCodeAt(this.state.pos);
    let val;

    if (this.hasPlugin("numericSeparator")) {
      if (code === 95) {
        const prev = this.input.charCodeAt(this.state.pos - 1);
        const next = this.input.charCodeAt(this.state.pos + 1);

        if (allowedSiblings.indexOf(next) === -1) {
          this.raise(this.state.pos, "Invalid or unexpected token");
        }

        if (forbiddenSiblings.indexOf(prev) > -1 || forbiddenSiblings.indexOf(next) > -1 || Number.isNaN(next)) {
          this.raise(this.state.pos, "Invalid or unexpected token");
        }

        if (!allowNumSeparator) {
          this.raise(this.state.pos, "Numeric separators are not allowed inside unicode escape sequences or hex escape sequences");
        }

        ++this.state.pos;
        continue;
      }
    }

    if (code >= 97) {
      val = code - 97 + 10;
    } else if (code >= 65) {
      val = code - 65 + 10;
    } else if (_isDigit(code)) {
      val = code - 48;
    } else {
      val = Infinity;
    }

    if (val >= radix) break;
    ++this.state.pos;
    total = total * radix + val;
  }

  if (this.state.pos === start || len != null && this.state.pos - start !== len) {
    return null;
  }

  return total;
}

readRadixNumber(radix) {
  const start = this.state.pos;
  let isBigInt = false;
  this.state.pos += 2;
  const val = this.readInt(radix);

  if (val == null) {
    this.raise(this.state.start + 2, "Expected number in radix " + radix);
  }

  if (this.hasPlugin("bigInt")) {
    if (this.input.charCodeAt(this.state.pos) === 110) {
      ++this.state.pos;
      isBigInt = true;
    }
  }

  if (isIdentifierStart(this.input.codePointAt(this.state.pos))) {
    this.raise(this.state.pos, "Identifier directly after number");
  }

  if (isBigInt) {
    const str = this.input.slice(start, this.state.pos).replace(/[_n]/g, "");
    this.finishToken(types.bigint, str);
    return;
  }

  this.finishToken(types.num, val);
}

readNumber(startsWithDot) {
  const start = this.state.pos;
  let isFloat = false;
  let isBigInt = false;
  let isNonOctalDecimalInt = false;

  if (!startsWithDot && this.readInt(10) === null) {
    this.raise(start, "Invalid number");
  }

  let octal = this.state.pos - start >= 2 && this.input.charCodeAt(start) === 48;

  if (octal) {
    if (this.state.strict) {
      this.raise(start, "Legacy octal literals are not allowed in strict mode");
    }

    if (/[89]/.test(this.input.slice(start, this.state.pos))) {
      octal = false;
      isNonOctalDecimalInt = true;
    }
  }

  let next = this.input.charCodeAt(this.state.pos);

  if (next === 46 && !octal) {
    ++this.state.pos;
    this.readInt(10);
    isFloat = true;
    next = this.input.charCodeAt(this.state.pos);
  }

  if ((next === 69 || next === 101) && !octal) {
    next = this.input.charCodeAt(++this.state.pos);

    if (next === 43 || next === 45) {
      ++this.state.pos;
    }

    if (this.readInt(10) === null) this.raise(start, "Invalid number");
    isFloat = true;
    next = this.input.charCodeAt(this.state.pos);
  }

  if (this.hasPlugin("numericSeparator") && (octal || isNonOctalDecimalInt)) {
    const underscorePos = this.input.slice(start, this.state.pos).indexOf("_");

    if (underscorePos > 0) {
      this.raise(underscorePos + start, "Numeric separator can not be used after leading 0");
    }
  }

  if (this.hasPlugin("bigInt")) {
    if (next === 110) {
      if (isFloat || octal || isNonOctalDecimalInt) {
        this.raise(start, "Invalid BigIntLiteral");
      }

      ++this.state.pos;
      isBigInt = true;
    }
  }

  if (isIdentifierStart(this.input.codePointAt(this.state.pos))) {
    this.raise(this.state.pos, "Identifier directly after number");
  }

  const str = this.input.slice(start, this.state.pos).replace(/[_n]/g, "");

  if (isBigInt) {
    this.finishToken(types.bigint, str);
    return;
  }

  const val = octal ? parseInt(str, 8) : parseFloat(str);
  this.finishToken(types.num, val);
}

readCodePoint(throwOnInvalid) {
  const ch = this.input.charCodeAt(this.state.pos);
  let code;

  if (ch === 123) {
    const codePos = ++this.state.pos;
    code = this.readHexChar(this.input.indexOf("}", this.state.pos) - this.state.pos, throwOnInvalid);
    ++this.state.pos;

    if (code === null) {
      --this.state.invalidTemplateEscapePosition;
    } else if (code > 0x10ffff) {
      if (throwOnInvalid) {
        this.raise(codePos, "Code point out of bounds");
      } else {
        this.state.invalidTemplateEscapePosition = codePos - 2;
        return null;
      }
    }
  } else {
    code = this.readHexChar(4, throwOnInvalid);
  }

  return code;
}

readString(quote) {
  let out = "",
      chunkStart = ++this.state.pos;

  for (;;) {
    if (this.state.pos >= this.length) {
      this.raise(this.state.start, "Unterminated string constant");
    }

    const ch = this.input.charCodeAt(this.state.pos);
    if (ch === quote) break;

    if (ch === 92) {
      out += this.input.slice(chunkStart, this.state.pos);
      out += this.readEscapedChar(false);
      chunkStart = this.state.pos;
    } else if (ch === 8232 || ch === 8233) {
      ++this.state.pos;
      ++this.state.curLine;
    } else if (isNewLine(ch)) {
      this.raise(this.state.start, "Unterminated string constant");
    } else {
      ++this.state.pos;
    }
  }

  out += this.input.slice(chunkStart, this.state.pos++);
  this.finishToken(types.string, out);
}

readTmplToken() {
  let out = "",
      chunkStart = this.state.pos,
      containsInvalid = false;

  for (;;) {
    if (this.state.pos >= this.length) {
      this.raise(this.state.start, "Unterminated template");
    }

    const ch = this.input.charCodeAt(this.state.pos);

    if (ch === 96 || ch === 36 && this.input.charCodeAt(this.state.pos + 1) === 123) {
      if (this.state.pos === this.state.start && this.match(types.template)) {
        if (ch === 36) {
          this.state.pos += 2;
          this.finishToken(types.dollarBraceL);
          return;
        } else {
          ++this.state.pos;
          this.finishToken(types.backQuote);
          return;
        }
      }

      out += this.input.slice(chunkStart, this.state.pos);
      this.finishToken(types.template, containsInvalid ? null : out);
      return;
    }

    if (ch === 92) {
      out += this.input.slice(chunkStart, this.state.pos);
      const escaped = this.readEscapedChar(true);

      if (escaped === null) {
        containsInvalid = true;
      } else {
        out += escaped;
      }

      chunkStart = this.state.pos;
    } else if (isNewLine(ch)) {
      out += this.input.slice(chunkStart, this.state.pos);
      ++this.state.pos;

      switch (ch) {
        case 13:
          if (this.input.charCodeAt(this.state.pos) === 10) {
            ++this.state.pos;
          }

        case 10:
          out += "\n";
          break;

        default:
          out += String.fromCharCode(ch);
          break;
      }

      ++this.state.curLine;
      this.state.lineStart = this.state.pos;
      chunkStart = this.state.pos;
    } else {
      ++this.state.pos;
    }
  }
}

readEscapedChar(inTemplate) {
  const throwOnInvalid = !inTemplate;
  const ch = this.input.charCodeAt(++this.state.pos);
  ++this.state.pos;

  switch (ch) {
    case 110:
      return "\n";

    case 114:
      return "\r";

    case 120:
      {
        const code = this.readHexChar(2, throwOnInvalid);
        return code === null ? null : String.fromCharCode(code);
      }

    case 117:
      {
        const code = this.readCodePoint(throwOnInvalid);
        return code === null ? null : String.fromCodePoint(code);
      }

    case 116:
      return "\t";

    case 98:
      return "\b";

    case 118:
      return "\u000b";

    case 102:
      return "\f";

    case 13:
      if (this.input.charCodeAt(this.state.pos) === 10) {
        ++this.state.pos;
      }

    case 10:
      this.state.lineStart = this.state.pos;
      ++this.state.curLine;

    case 8232:
    case 8233:
      return "";

    default:
      if (ch >= 48 && ch <= 55) {
        const codePos = this.state.pos - 1;
        let octalStr = this.input.substr(this.state.pos - 1, 3).match(/^[0-7]+/)[0];
        let octal = parseInt(octalStr, 8);

        if (octal > 255) {
          octalStr = octalStr.slice(0, -1);
          octal = parseInt(octalStr, 8);
        }

        this.state.pos += octalStr.length - 1;
        const next = this.input.charCodeAt(this.state.pos);

        if (octalStr !== "0" || next === 56 || next === 57) {
          if (inTemplate) {
            this.state.invalidTemplateEscapePosition = codePos;
            return null;
          } else if (this.state.strict) {
            this.raise(codePos, "Octal literal in strict mode");
          } else if (!this.state.containsOctal) {
            this.state.containsOctal = true;
            this.state.octalPosition = codePos;
          }
        }

        return String.fromCharCode(octal);
      }

      return String.fromCharCode(ch);
  }
}

readHexChar(len, throwOnInvalid) {
  const codePos = this.state.pos;
  const n = this.readInt(16, len, false);

  if (n === null) {
    if (throwOnInvalid) {
      this.raise(codePos, "Bad character escape sequence");
    } else {
      this.state.pos = codePos - 1;
      this.state.invalidTemplateEscapePosition = codePos - 1;
    }
  }

  return n;
}

readWord1() {
  let word = "";
  this.state.containsEsc = false;
  const start = this.state.pos;
  let chunkStart = this.state.pos;

  while (this.state.pos < this.length) {
    const ch = this.input.codePointAt(this.state.pos);

    if (isIdentifierChar(ch)) {
      this.state.pos += ch <= 0xffff ? 1 : 2;
    } else if (this.state.isIterator && ch === 64) {
      ++this.state.pos;
    } else if (ch === 92) {
      this.state.containsEsc = true;
      word += this.input.slice(chunkStart, this.state.pos);
      const escStart = this.state.pos;
      const identifierCheck = this.state.pos === start ? isIdentifierStart : isIdentifierChar;

      if (this.input.charCodeAt(++this.state.pos) !== 117) {
        this.raise(this.state.pos, "Expecting Unicode escape sequence \\uXXXX");
      }

      ++this.state.pos;
      const esc = this.readCodePoint(true);

      if (!identifierCheck(esc, true)) {
        this.raise(escStart, "Invalid Unicode escape");
      }

      word += String.fromCodePoint(esc);
      chunkStart = this.state.pos;
    } else {
      break;
    }
  }

  return word + this.input.slice(chunkStart, this.state.pos);
}

isIterator(word) {
  return word === "@@iterator" || word === "@@asyncIterator";
}

readWord() {
  const word = this.readWord1();
  const type = !this.state.containsEsc && keywords.get(word) || types.name;

  if (this.state.isIterator && (!this.isIterator(word) || !this.state.inType)) {
    this.raise(this.state.pos, `Invalid identifier ${word}`);
  }

  this.finishToken(type, word);
}

braceIsBlock(prevType) {
  const parent = this.curContext();

  if (parent === types$1.functionExpression || parent === types$1.functionStatement) {
    return true;
  }

  if (prevType === types.colon && (parent === types$1.braceStatement || parent === types$1.braceExpression)) {
    return !parent.isExpr;
  }

  if (prevType === types._return || prevType === types.name && this.state.exprAllowed) {
    return lineBreak.test(this.input.slice(this.state.lastTokEnd, this.state.start));
  }

  if (prevType === types._else || prevType === types.semi || prevType === types.eof || prevType === types.parenR || prevType === types.arrow) {
    return true;
  }

  if (prevType === types.braceL) {
    return parent === types$1.braceStatement;
  }

  if (prevType === types._var || prevType === types._const || prevType === types.name) {
    return false;
  }

  if (prevType === types.relational) {
    return true;
  }

  return !this.state.exprAllowed;
}

updateContext(prevType) {
  const type = this.state.type;
  let update;

  if (type.keyword && (prevType === types.dot || prevType === types.questionDot)) {
    this.state.exprAllowed = false;
  } else if (update = type.updateContext) {
    update.call(this, prevType);
  } else {
    this.state.exprAllowed = type.beforeExpr;
  }
}

}

const literal = /^('|“)((?:\?.)*?)1/; class UtilParser extends Tokenizer {

addExtra(node, key, val) {
  if (!node) return;
  const extra = node.extra = node.extra || {};
  extra[key] = val;
}

isRelational(op) {
  return this.match(types.relational) && this.state.value === op;
}

isLookaheadRelational(op) {
  const next = this.nextTokenStart();

  if (this.input.charAt(next) === op) {
    if (next + 1 === this.input.length) {
      return true;
    }

    const afterNext = this.input.charCodeAt(next + 1);
    return afterNext !== op.charCodeAt(0) && afterNext !== 61;
  }

  return false;
}

expectRelational(op) {
  if (this.isRelational(op)) {
    this.next();
  } else {
    this.unexpected(null, types.relational);
  }
}

eatRelational(op) {
  if (this.isRelational(op)) {
    this.next();
    return true;
  }

  return false;
}

isContextual(name) {
  return this.match(types.name) && this.state.value === name && !this.state.containsEsc;
}

isUnparsedContextual(nameStart, name) {
  const nameEnd = nameStart + name.length;
  return this.input.slice(nameStart, nameEnd) === name && (nameEnd === this.input.length || !isIdentifierChar(this.input.charCodeAt(nameEnd)));
}

isLookaheadContextual(name) {
  const next = this.nextTokenStart();
  return this.isUnparsedContextual(next, name);
}

eatContextual(name) {
  return this.isContextual(name) && this.eat(types.name);
}

expectContextual(name, message) {
  if (!this.eatContextual(name)) this.unexpected(null, message);
}

canInsertSemicolon() {
  return this.match(types.eof) || this.match(types.braceR) || this.hasPrecedingLineBreak();
}

hasPrecedingLineBreak() {
  return lineBreak.test(this.input.slice(this.state.lastTokEnd, this.state.start));
}

isLineTerminator() {
  return this.eat(types.semi) || this.canInsertSemicolon();
}

semicolon() {
  if (!this.isLineTerminator()) this.unexpected(null, types.semi);
}

expect(type, pos) {
  this.eat(type) || this.unexpected(pos, type);
}

assertNoSpace(message = "Unexpected space.") {
  if (this.state.start > this.state.lastTokEnd) {
    this.raise(this.state.lastTokEnd, message);
  }
}

unexpected(pos, messageOrType = "Unexpected token") {
  if (typeof messageOrType !== "string") {
    messageOrType = `Unexpected token, expected "${messageOrType.label}"`;
  }

  throw this.raise(pos != null ? pos : this.state.start, messageOrType);
}

expectPlugin(name, pos) {
  if (!this.hasPlugin(name)) {
    throw this.raise(pos != null ? pos : this.state.start, `This experimental syntax requires enabling the parser plugin: '${name}'`, {
      missingPluginNames: [name]
    });
  }

  return true;
}

expectOnePlugin(names, pos) {
  if (!names.some(n => this.hasPlugin(n))) {
    throw this.raise(pos != null ? pos : this.state.start, `This experimental syntax requires enabling one of the following parser plugin(s): '${names.join(", ")}'`, {
      missingPluginNames: names
    });
  }
}

checkYieldAwaitInDefaultParams() {
  if (this.state.yieldPos !== -1 && (this.state.awaitPos === -1 || this.state.yieldPos < this.state.awaitPos)) {
    this.raise(this.state.yieldPos, "Yield cannot be used as name inside a generator function");
  }

  if (this.state.awaitPos !== -1) {
    this.raise(this.state.awaitPos, "Await cannot be used as name inside an async function");
  }
}

strictDirective(start) {
  for (;;) {
    skipWhiteSpace.lastIndex = start;
    start += skipWhiteSpace.exec(this.input)[0].length;
    const match = literal.exec(this.input.slice(start));
    if (!match) break;
    if (match[2] === "use strict") return true;
    start += match[0].length;
    skipWhiteSpace.lastIndex = start;
    start += skipWhiteSpace.exec(this.input)[0].length;

    if (this.input[start] === ";") {
      start++;
    }
  }

  return false;
}

}

class Node {

constructor(parser, pos, loc) {
  this.type = "";
  this.start = pos;
  this.end = 0;
  this.loc = new SourceLocation(loc);
  if (parser && parser.options.ranges) this.range = [pos, 0];
  if (parser && parser.filename) this.loc.filename = parser.filename;
}

__clone() {
  const newNode = new Node();
  const keys = Object.keys(this);

  for (let i = 0, length = keys.length; i < length; i++) {
    const key = keys[i];

    if (key !== "leadingComments" && key !== "trailingComments" && key !== "innerComments") {
      newNode[key] = this[key];
    }
  }

  return newNode;
}

}

class NodeUtils extends UtilParser {

startNode() {
  return new Node(this, this.state.start, this.state.startLoc);
}

startNodeAt(pos, loc) {
  return new Node(this, pos, loc);
}

startNodeAtNode(type) {
  return this.startNodeAt(type.start, type.loc.start);
}

finishNode(node, type) {
  return this.finishNodeAt(node, type, this.state.lastTokEnd, this.state.lastTokEndLoc);
}

finishNodeAt(node, type, pos, loc) {

  node.type = type;
  node.end = pos;
  node.loc.end = loc;
  if (this.options.ranges) node.range[1] = pos;
  this.processComment(node);
  return node;
}

resetStartLocation(node, start, startLoc) {
  node.start = start;
  node.loc.start = startLoc;
  if (this.options.ranges) node.range[0] = start;
}

resetEndLocation(node, end = this.state.lastTokEnd, endLoc = this.state.lastTokEndLoc) {
  node.end = end;
  node.loc.end = endLoc;
  if (this.options.ranges) node.range[1] = end;
}

resetStartLocationFromNode(node, locationNode) {
  this.resetStartLocation(node, locationNode.start, locationNode.loc.start);
}

}

class LValParser extends NodeUtils {

toAssignable(node, isBinding, contextDescription) {
  var _node$extra2;

  if (node) {
    switch (node.type) {
      case "Identifier":
      case "ObjectPattern":
      case "ArrayPattern":
      case "AssignmentPattern":
        break;

      case "ObjectExpression":
        node.type = "ObjectPattern";

        for (let i = 0, length = node.properties.length, last = length - 1; i < length; i++) {
          var _node$extra;

          const prop = node.properties[i];
          const isLast = i === last;
          this.toAssignableObjectExpressionProp(prop, isBinding, isLast);

          if (isLast && prop.type === "RestElement" && ((_node$extra = node.extra) === null || _node$extra === void 0 ? void 0 : _node$extra.trailingComma)) {
            this.raiseRestNotLast(node.extra.trailingComma);
          }
        }

        break;

      case "ObjectProperty":
        this.toAssignable(node.value, isBinding, contextDescription);
        break;

      case "SpreadElement":
        {
          this.checkToRestConversion(node);
          node.type = "RestElement";
          const arg = node.argument;
          this.toAssignable(arg, isBinding, contextDescription);
          break;
        }

      case "ArrayExpression":
        node.type = "ArrayPattern";
        this.toAssignableList(node.elements, isBinding, contextDescription, (_node$extra2 = node.extra) === null || _node$extra2 === void 0 ? void 0 : _node$extra2.trailingComma);
        break;

      case "AssignmentExpression":
        if (node.operator === "=") {
          node.type = "AssignmentPattern";
          delete node.operator;
        } else {
          this.raise(node.left.end, "Only '=' operator can be used for specifying default value.");
        }

        break;

      case "ParenthesizedExpression":
        node.expression = this.toAssignable(node.expression, isBinding, contextDescription);
        break;

      case "MemberExpression":
        if (!isBinding) break;

      default:
        {
          const message = "Invalid left-hand side" + (contextDescription ? " in " + contextDescription : "expression");
          this.raise(node.start, message);
        }
    }
  }

  return node;
}

toAssignableObjectExpressionProp(prop, isBinding, isLast) {
  if (prop.type === "ObjectMethod") {
    const error = prop.kind === "get" || prop.kind === "set" ? "Object pattern can't contain getter or setter" : "Object pattern can't contain methods";
    this.raise(prop.key.start, error);
  } else if (prop.type === "SpreadElement" && !isLast) {
    this.raiseRestNotLast(prop.start);
  } else {
    this.toAssignable(prop, isBinding, "object destructuring pattern");
  }
}

toAssignableList(exprList, isBinding, contextDescription, trailingCommaPos) {
  let end = exprList.length;

  if (end) {
    const last = exprList[end - 1];

    if (last && last.type === "RestElement") {
      --end;
    } else if (last && last.type === "SpreadElement") {
      last.type = "RestElement";
      const arg = last.argument;
      this.toAssignable(arg, isBinding, contextDescription);

      if (arg.type !== "Identifier" && arg.type !== "MemberExpression" && arg.type !== "ArrayPattern" && arg.type !== "ObjectPattern") {
        this.unexpected(arg.start);
      }

      if (trailingCommaPos) {
        this.raiseTrailingCommaAfterRest(trailingCommaPos);
      }

      --end;
    }
  }

  for (let i = 0; i < end; i++) {
    const elt = exprList[i];

    if (elt) {
      this.toAssignable(elt, isBinding, contextDescription);

      if (elt.type === "RestElement") {
        this.raiseRestNotLast(elt.start);
      }
    }
  }

  return exprList;
}

toReferencedList(exprList, isParenthesizedExpr) {
  return exprList;
}

toReferencedListDeep(exprList, isParenthesizedExpr) {
  this.toReferencedList(exprList, isParenthesizedExpr);

  for (let _i = 0; _i < exprList.length; _i++) {
    const expr = exprList[_i];

    if (expr && expr.type === "ArrayExpression") {
      this.toReferencedListDeep(expr.elements);
    }
  }

  return exprList;
}

parseSpread(refShorthandDefaultPos, refNeedsArrowPos) {
  const node = this.startNode();
  this.next();
  node.argument = this.parseMaybeAssign(false, refShorthandDefaultPos, undefined, refNeedsArrowPos);
  return this.finishNode(node, "SpreadElement");
}

parseRestBinding() {
  const node = this.startNode();
  this.next();
  node.argument = this.parseBindingAtom();
  return this.finishNode(node, "RestElement");
}

parseBindingAtom() {
  switch (this.state.type) {
    case types.bracketL:
      {
        const node = this.startNode();
        this.next();
        node.elements = this.parseBindingList(types.bracketR, 93, true);
        return this.finishNode(node, "ArrayPattern");
      }

    case types.braceL:
      return this.parseObj(true);
  }

  return this.parseIdentifier();
}

parseBindingList(close, closeCharCode, allowEmpty, allowModifiers) {
  const elts = [];
  let first = true;

  while (!this.eat(close)) {
    if (first) {
      first = false;
    } else {
      this.expect(types.comma);
    }

    if (allowEmpty && this.match(types.comma)) {
      elts.push(null);
    } else if (this.eat(close)) {
      break;
    } else if (this.match(types.ellipsis)) {
      elts.push(this.parseAssignableListItemTypes(this.parseRestBinding()));
      this.checkCommaAfterRest(closeCharCode);
      this.expect(close);
      break;
    } else {
      const decorators = [];

      if (this.match(types.at) && this.hasPlugin("decorators")) {
        this.raise(this.state.start, "Stage 2 decorators cannot be used to decorate parameters");
      }

      while (this.match(types.at)) {
        decorators.push(this.parseDecorator());
      }

      elts.push(this.parseAssignableListItem(allowModifiers, decorators));
    }
  }

  return elts;
}

parseAssignableListItem(allowModifiers, decorators) {
  const left = this.parseMaybeDefault();
  this.parseAssignableListItemTypes(left);
  const elt = this.parseMaybeDefault(left.start, left.loc.start, left);

  if (decorators.length) {
    left.decorators = decorators;
  }

  return elt;
}

parseAssignableListItemTypes(param) {
  return param;
}

parseMaybeDefault(startPos, startLoc, left) {
  startLoc = startLoc || this.state.startLoc;
  startPos = startPos || this.state.start;
  left = left || this.parseBindingAtom();
  if (!this.eat(types.eq)) return left;
  const node = this.startNodeAt(startPos, startLoc);
  node.left = left;
  node.right = this.parseMaybeAssign();
  return this.finishNode(node, "AssignmentPattern");
}

checkLVal(expr, bindingType = BIND_NONE, checkClashes, contextDescription) {
  switch (expr.type) {
    case "Identifier":
      if (this.state.strict && isStrictBindReservedWord(expr.name, this.inModule)) {
        this.raise(expr.start, `${bindingType === BIND_NONE ? "Assigning to" : "Binding"} '${expr.name}' in strict mode`);
      }

      if (checkClashes) {
        const key = `_${expr.name}`;

        if (checkClashes[key]) {
          this.raise(expr.start, "Argument name clash");
        } else {
          checkClashes[key] = true;
        }
      }

      if (bindingType === BIND_LEXICAL && expr.name === "let") {
        this.raise(expr.start, "'let' is not allowed to be used as a name in 'let' or 'const' declarations.");
      }

      if (!(bindingType & BIND_NONE)) {
        this.scope.declareName(expr.name, bindingType, expr.start);
      }

      break;

    case "MemberExpression":
      if (bindingType !== BIND_NONE) {
        this.raise(expr.start, "Binding member expression");
      }

      break;

    case "ObjectPattern":
      for (let _i2 = 0, _expr$properties = expr.properties; _i2 < _expr$properties.length; _i2++) {
        let prop = _expr$properties[_i2];
        if (prop.type === "ObjectProperty") prop = prop.value;
        this.checkLVal(prop, bindingType, checkClashes, "object destructuring pattern");
      }

      break;

    case "ArrayPattern":
      for (let _i3 = 0, _expr$elements = expr.elements; _i3 < _expr$elements.length; _i3++) {
        const elem = _expr$elements[_i3];

        if (elem) {
          this.checkLVal(elem, bindingType, checkClashes, "array destructuring pattern");
        }
      }

      break;

    case "AssignmentPattern":
      this.checkLVal(expr.left, bindingType, checkClashes, "assignment pattern");
      break;

    case "RestElement":
      this.checkLVal(expr.argument, bindingType, checkClashes, "rest element");
      break;

    case "ParenthesizedExpression":
      this.checkLVal(expr.expression, bindingType, checkClashes, "parenthesized expression");
      break;

    default:
      {
        const message = (bindingType === BIND_NONE ? "Invalid" : "Binding invalid") + " left-hand side" + (contextDescription ? " in " + contextDescription : "expression");
        this.raise(expr.start, message);
      }
  }
}

checkToRestConversion(node) {
  if (node.argument.type !== "Identifier" && node.argument.type !== "MemberExpression") {
    this.raise(node.argument.start, "Invalid rest operator's argument");
  }
}

checkCommaAfterRest(close) {
  if (this.match(types.comma)) {
    if (this.lookaheadCharCode() === close) {
      this.raiseTrailingCommaAfterRest(this.state.start);
    } else {
      this.raiseRestNotLast(this.state.start);
    }
  }
}

raiseRestNotLast(pos) {
  this.raise(pos, `Rest element must be last element`);
}

raiseTrailingCommaAfterRest(pos) {
  this.raise(pos, `Unexpected trailing comma after rest element`);
}

}

const unwrapParenthesizedExpression = node => {

return node.type === "ParenthesizedExpression" ? unwrapParenthesizedExpression(node.expression) : node;

};

class ExpressionParser extends LValParser {

checkPropClash(prop, propHash) {
  if (prop.type === "SpreadElement" || prop.computed || prop.kind || prop.shorthand) {
    return;
  }

  const key = prop.key;
  const name = key.type === "Identifier" ? key.name : String(key.value);

  if (name === "__proto__") {
    if (propHash.proto) {
      this.raise(key.start, "Redefinition of __proto__ property");
    }

    propHash.proto = true;
  }
}

getExpression() {
  this.scope.enter(SCOPE_PROGRAM);
  this.nextToken();
  const expr = this.parseExpression();

  if (!this.match(types.eof)) {
    this.unexpected();
  }

  expr.comments = this.state.comments;
  return expr;
}

parseExpression(noIn, refShorthandDefaultPos) {
  const startPos = this.state.start;
  const startLoc = this.state.startLoc;
  const expr = this.parseMaybeAssign(noIn, refShorthandDefaultPos);

  if (this.match(types.comma)) {
    const node = this.startNodeAt(startPos, startLoc);
    node.expressions = [expr];

    while (this.eat(types.comma)) {
      node.expressions.push(this.parseMaybeAssign(noIn, refShorthandDefaultPos));
    }

    this.toReferencedList(node.expressions);
    return this.finishNode(node, "SequenceExpression");
  }

  return expr;
}

parseMaybeAssign(noIn, refShorthandDefaultPos, afterLeftParse, refNeedsArrowPos) {
  const startPos = this.state.start;
  const startLoc = this.state.startLoc;

  if (this.isContextual("yield")) {
    if (this.scope.inGenerator) {
      let left = this.parseYield(noIn);

      if (afterLeftParse) {
        left = afterLeftParse.call(this, left, startPos, startLoc);
      }

      return left;
    } else {
      this.state.exprAllowed = false;
    }
  }

  let failOnShorthandAssign;

  if (refShorthandDefaultPos) {
    failOnShorthandAssign = false;
  } else {
    refShorthandDefaultPos = {
      start: 0
    };
    failOnShorthandAssign = true;
  }

  if (this.match(types.parenL) || this.match(types.name)) {
    this.state.potentialArrowAt = this.state.start;
  }

  let left = this.parseMaybeConditional(noIn, refShorthandDefaultPos, refNeedsArrowPos);

  if (afterLeftParse) {
    left = afterLeftParse.call(this, left, startPos, startLoc);
  }

  if (this.state.type.isAssign) {
    const node = this.startNodeAt(startPos, startLoc);
    const operator = this.state.value;
    node.operator = operator;

    if (operator === "??=") {
      this.expectPlugin("nullishCoalescingOperator");
      this.expectPlugin("logicalAssignment");
    }

    if (operator === "||=" || operator === "&&=") {
      this.expectPlugin("logicalAssignment");
    }

    node.left = this.match(types.eq) ? this.toAssignable(left, undefined, "assignment expression") : left;
    refShorthandDefaultPos.start = 0;
    this.checkLVal(left, undefined, undefined, "assignment expression");
    const maybePattern = unwrapParenthesizedExpression(left);
    let patternErrorMsg;

    if (maybePattern.type === "ObjectPattern") {
      patternErrorMsg = "`({a}) = 0` use `({a} = 0)`";
    } else if (maybePattern.type === "ArrayPattern") {
      patternErrorMsg = "`([a]) = 0` use `([a] = 0)`";
    }

    if (patternErrorMsg && (left.extra && left.extra.parenthesized || left.type === "ParenthesizedExpression")) {
      this.raise(maybePattern.start, `You're trying to assign to a parenthesized expression, eg. instead of ${patternErrorMsg}`);
    }

    this.next();
    node.right = this.parseMaybeAssign(noIn);
    return this.finishNode(node, "AssignmentExpression");
  } else if (failOnShorthandAssign && refShorthandDefaultPos.start) {
    this.unexpected(refShorthandDefaultPos.start);
  }

  return left;
}

parseMaybeConditional(noIn, refShorthandDefaultPos, refNeedsArrowPos) {
  const startPos = this.state.start;
  const startLoc = this.state.startLoc;
  const potentialArrowAt = this.state.potentialArrowAt;
  const expr = this.parseExprOps(noIn, refShorthandDefaultPos);

  if (expr.type === "ArrowFunctionExpression" && expr.start === potentialArrowAt) {
    return expr;
  }

  if (refShorthandDefaultPos && refShorthandDefaultPos.start) return expr;
  return this.parseConditional(expr, noIn, startPos, startLoc, refNeedsArrowPos);
}

parseConditional(expr, noIn, startPos, startLoc, refNeedsArrowPos) {
  if (this.eat(types.question)) {
    const node = this.startNodeAt(startPos, startLoc);
    node.test = expr;
    node.consequent = this.parseMaybeAssign();
    this.expect(types.colon);
    node.alternate = this.parseMaybeAssign(noIn);
    return this.finishNode(node, "ConditionalExpression");
  }

  return expr;
}

parseExprOps(noIn, refShorthandDefaultPos) {
  const startPos = this.state.start;
  const startLoc = this.state.startLoc;
  const potentialArrowAt = this.state.potentialArrowAt;
  const expr = this.parseMaybeUnary(refShorthandDefaultPos);

  if (expr.type === "ArrowFunctionExpression" && expr.start === potentialArrowAt) {
    return expr;
  }

  if (refShorthandDefaultPos && refShorthandDefaultPos.start) {
    return expr;
  }

  return this.parseExprOp(expr, startPos, startLoc, -1, noIn);
}

parseExprOp(left, leftStartPos, leftStartLoc, minPrec, noIn) {
  const prec = this.state.type.binop;

  if (prec != null && (!noIn || !this.match(types._in))) {
    if (prec > minPrec) {
      const operator = this.state.value;

      if (operator === "|>" && this.state.inFSharpPipelineDirectBody) {
        return left;
      }

      const node = this.startNodeAt(leftStartPos, leftStartLoc);
      node.left = left;
      node.operator = operator;

      if (operator === "**" && left.type === "UnaryExpression" && (this.options.createParenthesizedExpressions || !(left.extra && left.extra.parenthesized))) {
        this.raise(left.argument.start, "Illegal expression. Wrap left hand side or entire exponentiation in parentheses.");
      }

      const op = this.state.type;

      if (op === types.pipeline) {
        this.expectPlugin("pipelineOperator");
        this.state.inPipeline = true;
        this.checkPipelineAtInfixOperator(left, leftStartPos);
      } else if (op === types.nullishCoalescing) {
        this.expectPlugin("nullishCoalescingOperator");
      }

      this.next();

      if (op === types.pipeline && this.getPluginOption("pipelineOperator", "proposal") === "minimal") {
        if (this.match(types.name) && this.state.value === "await" && this.scope.inAsync) {
          throw this.raise(this.state.start, `Unexpected "await" after pipeline body; await must have parentheses in minimal proposal`);
        }
      }

      node.right = this.parseExprOpRightExpr(op, prec, noIn);

      if (op === types.nullishCoalescing) {
        if (left.type === "LogicalExpression" && left.operator !== "??" && !(left.extra && left.extra.parenthesized)) {
          throw this.raise(left.start, `Nullish coalescing operator(??) requires parens when mixing with logical operators`);
        } else if (node.right.type === "LogicalExpression" && node.right.operator !== "??" && !(node.right.extra && node.right.extra.parenthesized)) {
          throw this.raise(node.right.start, `Nullish coalescing operator(??) requires parens when mixing with logical operators`);
        }
      }

      this.finishNode(node, op === types.logicalOR || op === types.logicalAND || op === types.nullishCoalescing ? "LogicalExpression" : "BinaryExpression");
      return this.parseExprOp(node, leftStartPos, leftStartLoc, minPrec, noIn);
    }
  }

  return left;
}

parseExprOpRightExpr(op, prec, noIn) {
  const startPos = this.state.start;
  const startLoc = this.state.startLoc;

  switch (op) {
    case types.pipeline:
      switch (this.getPluginOption("pipelineOperator", "proposal")) {
        case "smart":
          return this.withTopicPermittingContext(() => {
            return this.parseSmartPipelineBody(this.parseExprOpBaseRightExpr(op, prec, noIn), startPos, startLoc);
          });

        case "fsharp":
          return this.withSoloAwaitPermittingContext(() => {
            return this.parseFSharpPipelineBody(prec, noIn);
          });
      }

    default:
      return this.parseExprOpBaseRightExpr(op, prec, noIn);
  }
}

parseExprOpBaseRightExpr(op, prec, noIn) {
  const startPos = this.state.start;
  const startLoc = this.state.startLoc;
  return this.parseExprOp(this.parseMaybeUnary(), startPos, startLoc, op.rightAssociative ? prec - 1 : prec, noIn);
}

parseMaybeUnary(refShorthandDefaultPos) {
  if (this.isContextual("await") && this.isAwaitAllowed()) {
    return this.parseAwait();
  } else if (this.state.type.prefix) {
    const node = this.startNode();
    const update = this.match(types.incDec);
    node.operator = this.state.value;
    node.prefix = true;

    if (node.operator === "throw") {
      this.expectPlugin("throwExpressions");
    }

    this.next();
    node.argument = this.parseMaybeUnary();

    if (refShorthandDefaultPos && refShorthandDefaultPos.start) {
      this.unexpected(refShorthandDefaultPos.start);
    }

    if (update) {
      this.checkLVal(node.argument, undefined, undefined, "prefix operation");
    } else if (this.state.strict && node.operator === "delete") {
      const arg = node.argument;

      if (arg.type === "Identifier") {
        this.raise(node.start, "Deleting local variable in strict mode");
      } else if (arg.type === "MemberExpression" && arg.property.type === "PrivateName") {
        this.raise(node.start, "Deleting a private field is not allowed");
      }
    }

    return this.finishNode(node, update ? "UpdateExpression" : "UnaryExpression");
  }

  const startPos = this.state.start;
  const startLoc = this.state.startLoc;
  let expr = this.parseExprSubscripts(refShorthandDefaultPos);
  if (refShorthandDefaultPos && refShorthandDefaultPos.start) return expr;

  while (this.state.type.postfix && !this.canInsertSemicolon()) {
    const node = this.startNodeAt(startPos, startLoc);
    node.operator = this.state.value;
    node.prefix = false;
    node.argument = expr;
    this.checkLVal(expr, undefined, undefined, "postfix operation");
    this.next();
    expr = this.finishNode(node, "UpdateExpression");
  }

  return expr;
}

parseExprSubscripts(refShorthandDefaultPos) {
  const startPos = this.state.start;
  const startLoc = this.state.startLoc;
  const potentialArrowAt = this.state.potentialArrowAt;
  const expr = this.parseExprAtom(refShorthandDefaultPos);

  if (expr.type === "ArrowFunctionExpression" && expr.start === potentialArrowAt) {
    return expr;
  }

  if (refShorthandDefaultPos && refShorthandDefaultPos.start) {
    return expr;
  }

  return this.parseSubscripts(expr, startPos, startLoc);
}

parseSubscripts(base, startPos, startLoc, noCalls) {
  const state = {
    optionalChainMember: false,
    maybeAsyncArrow: this.atPossibleAsync(base),
    stop: false
  };

  do {
    base = this.parseSubscript(base, startPos, startLoc, noCalls, state);
    state.maybeAsyncArrow = false;
  } while (!state.stop);

  return base;
}

parseSubscript(base, startPos, startLoc, noCalls, state) {
  if (!noCalls && this.eat(types.doubleColon)) {
    const node = this.startNodeAt(startPos, startLoc);
    node.object = base;
    node.callee = this.parseNoCallExpr();
    state.stop = true;
    return this.parseSubscripts(this.finishNode(node, "BindExpression"), startPos, startLoc, noCalls);
  } else if (this.match(types.questionDot)) {
    this.expectPlugin("optionalChaining");
    state.optionalChainMember = true;

    if (noCalls && this.lookaheadCharCode() === 40) {
      state.stop = true;
      return base;
    }

    this.next();
    const node = this.startNodeAt(startPos, startLoc);

    if (this.eat(types.bracketL)) {
      node.object = base;
      node.property = this.parseExpression();
      node.computed = true;
      node.optional = true;
      this.expect(types.bracketR);
      return this.finishNode(node, "OptionalMemberExpression");
    } else if (this.eat(types.parenL)) {
      node.callee = base;
      node.arguments = this.parseCallExpressionArguments(types.parenR, false);
      node.optional = true;
      return this.finishNode(node, "OptionalCallExpression");
    } else {
      node.object = base;
      node.property = this.parseIdentifier(true);
      node.computed = false;
      node.optional = true;
      return this.finishNode(node, "OptionalMemberExpression");
    }
  } else if (this.eat(types.dot)) {
    const node = this.startNodeAt(startPos, startLoc);
    node.object = base;
    node.property = this.parseMaybePrivateName();
    node.computed = false;

    if (node.property.type === "PrivateName" && node.object.type === "Super") {
      this.raise(startPos, "Private fields can't be accessed on super");
    }

    if (state.optionalChainMember) {
      node.optional = false;
      return this.finishNode(node, "OptionalMemberExpression");
    }

    return this.finishNode(node, "MemberExpression");
  } else if (this.eat(types.bracketL)) {
    const node = this.startNodeAt(startPos, startLoc);
    node.object = base;
    node.property = this.parseExpression();
    node.computed = true;
    this.expect(types.bracketR);

    if (state.optionalChainMember) {
      node.optional = false;
      return this.finishNode(node, "OptionalMemberExpression");
    }

    return this.finishNode(node, "MemberExpression");
  } else if (!noCalls && this.match(types.parenL)) {
    const oldMaybeInArrowParameters = this.state.maybeInArrowParameters;
    const oldYieldPos = this.state.yieldPos;
    const oldAwaitPos = this.state.awaitPos;
    this.state.maybeInArrowParameters = true;
    this.state.yieldPos = -1;
    this.state.awaitPos = -1;
    this.next();
    let node = this.startNodeAt(startPos, startLoc);
    node.callee = base;
    node.arguments = this.parseCallExpressionArguments(types.parenR, state.maybeAsyncArrow, base.type === "Import", base.type !== "Super", node);

    if (!state.optionalChainMember) {
      this.finishCallExpression(node);
    } else {
      this.finishOptionalCallExpression(node);
    }

    if (state.maybeAsyncArrow && this.shouldParseAsyncArrow()) {
      state.stop = true;
      node = this.parseAsyncArrowFromCallExpression(this.startNodeAt(startPos, startLoc), node);
      this.checkYieldAwaitInDefaultParams();
      this.state.yieldPos = oldYieldPos;
      this.state.awaitPos = oldAwaitPos;
    } else {
      this.toReferencedListDeep(node.arguments);
      if (oldYieldPos !== -1) this.state.yieldPos = oldYieldPos;

      if (!this.isAwaitAllowed() && !oldMaybeInArrowParameters || oldAwaitPos !== -1) {
        this.state.awaitPos = oldAwaitPos;
      }
    }

    this.state.maybeInArrowParameters = oldMaybeInArrowParameters;
    return node;
  } else if (this.match(types.backQuote)) {
    return this.parseTaggedTemplateExpression(startPos, startLoc, base, state);
  } else {
    state.stop = true;
    return base;
  }
}

parseTaggedTemplateExpression(startPos, startLoc, base, state, typeArguments) {
  const node = this.startNodeAt(startPos, startLoc);
  node.tag = base;
  node.quasi = this.parseTemplate(true);
  if (typeArguments) node.typeParameters = typeArguments;

  if (state.optionalChainMember) {
    this.raise(startPos, "Tagged Template Literals are not allowed in optionalChain");
  }

  return this.finishNode(node, "TaggedTemplateExpression");
}

atPossibleAsync(base) {
  return base.type === "Identifier" && base.name === "async" && this.state.lastTokEnd === base.end && !this.canInsertSemicolon() && this.input.slice(base.start, base.end) === "async";
}

finishCallExpression(node) {
  if (node.callee.type === "Import") {
    if (node.arguments.length !== 1) {
      this.raise(node.start, "import() requires exactly one argument");
    }

    const importArg = node.arguments[0];

    if (importArg && importArg.type === "SpreadElement") {
      this.raise(importArg.start, "... is not allowed in import()");
    }
  }

  return this.finishNode(node, "CallExpression");
}

finishOptionalCallExpression(node) {
  if (node.callee.type === "Import") {
    if (node.arguments.length !== 1) {
      this.raise(node.start, "import() requires exactly one argument");
    }

    const importArg = node.arguments[0];

    if (importArg && importArg.type === "SpreadElement") {
      this.raise(importArg.start, "... is not allowed in import()");
    }
  }

  return this.finishNode(node, "OptionalCallExpression");
}

parseCallExpressionArguments(close, possibleAsyncArrow, dynamicImport, allowPlaceholder, nodeForExtra) {
  const elts = [];
  let innerParenStart;
  let first = true;
  const oldInFSharpPipelineDirectBody = this.state.inFSharpPipelineDirectBody;
  this.state.inFSharpPipelineDirectBody = false;

  while (!this.eat(close)) {
    if (first) {
      first = false;
    } else {
      this.expect(types.comma);

      if (this.match(close)) {
        if (dynamicImport) {
          this.raise(this.state.lastTokStart, "Trailing comma is disallowed inside import(...) arguments");
        }

        if (nodeForExtra) {
          this.addExtra(nodeForExtra, "trailingComma", this.state.lastTokStart);
        }

        this.next();
        break;
      }
    }

    if (this.match(types.parenL) && !innerParenStart) {
      innerParenStart = this.state.start;
    }

    elts.push(this.parseExprListItem(false, possibleAsyncArrow ? {
      start: 0
    } : undefined, possibleAsyncArrow ? {
      start: 0
    } : undefined, allowPlaceholder));
  }

  if (possibleAsyncArrow && innerParenStart && this.shouldParseAsyncArrow()) {
    this.unexpected();
  }

  this.state.inFSharpPipelineDirectBody = oldInFSharpPipelineDirectBody;
  return elts;
}

shouldParseAsyncArrow() {
  return this.match(types.arrow) && !this.canInsertSemicolon();
}

parseAsyncArrowFromCallExpression(node, call) {
  var _call$extra;

  this.expect(types.arrow);
  this.parseArrowExpression(node, call.arguments, true, (_call$extra = call.extra) === null || _call$extra === void 0 ? void 0 : _call$extra.trailingComma);
  return node;
}

parseNoCallExpr() {
  const startPos = this.state.start;
  const startLoc = this.state.startLoc;
  return this.parseSubscripts(this.parseExprAtom(), startPos, startLoc, true);
}

parseExprAtom(refShorthandDefaultPos) {
  if (this.state.type === types.slash) this.readRegexp();
  const canBeArrow = this.state.potentialArrowAt === this.state.start;
  let node;

  switch (this.state.type) {
    case types._super:
      if (!this.scope.allowSuper && !this.options.allowSuperOutsideMethod) {
        this.raise(this.state.start, "super is only allowed in object methods and classes");
      }

      node = this.startNode();
      this.next();

      if (this.match(types.parenL) && !this.scope.allowDirectSuper && !this.options.allowSuperOutsideMethod) {
        this.raise(node.start, "super() is only valid inside a class constructor of a subclass. " + "Maybe a typo in the method name ('constructor') or not extending another class?");
      }

      if (!this.match(types.parenL) && !this.match(types.bracketL) && !this.match(types.dot)) {
        this.unexpected();
      }

      return this.finishNode(node, "Super");

    case types._import:
      node = this.startNode();
      this.next();

      if (this.match(types.dot)) {
        return this.parseImportMetaProperty(node);
      }

      this.expectPlugin("dynamicImport", node.start);

      if (!this.match(types.parenL)) {
        this.unexpected(null, types.parenL);
      }

      return this.finishNode(node, "Import");

    case types._this:
      node = this.startNode();
      this.next();
      return this.finishNode(node, "ThisExpression");

    case types.name:
      {
        node = this.startNode();
        const containsEsc = this.state.containsEsc;
        const id = this.parseIdentifier();

        if (!containsEsc && id.name === "async" && this.match(types._function) && !this.canInsertSemicolon()) {
          this.next();
          return this.parseFunction(node, undefined, true);
        } else if (canBeArrow && !containsEsc && id.name === "async" && this.match(types.name) && !this.canInsertSemicolon()) {
          const params = [this.parseIdentifier()];
          this.expect(types.arrow);
          this.parseArrowExpression(node, params, true);
          return node;
        }

        if (canBeArrow && this.match(types.arrow) && !this.canInsertSemicolon()) {
          this.next();
          this.parseArrowExpression(node, [id], false);
          return node;
        }

        return id;
      }

    case types._do:
      {
        this.expectPlugin("doExpressions");
        const node = this.startNode();
        this.next();
        const oldLabels = this.state.labels;
        this.state.labels = [];
        node.body = this.parseBlock();
        this.state.labels = oldLabels;
        return this.finishNode(node, "DoExpression");
      }

    case types.regexp:
      {
        const value = this.state.value;
        node = this.parseLiteral(value.value, "RegExpLiteral");
        node.pattern = value.pattern;
        node.flags = value.flags;
        return node;
      }

    case types.num:
      return this.parseLiteral(this.state.value, "NumericLiteral");

    case types.bigint:
      return this.parseLiteral(this.state.value, "BigIntLiteral");

    case types.string:
      return this.parseLiteral(this.state.value, "StringLiteral");

    case types._null:
      node = this.startNode();
      this.next();
      return this.finishNode(node, "NullLiteral");

    case types._true:
    case types._false:
      return this.parseBooleanLiteral();

    case types.parenL:
      return this.parseParenAndDistinguishExpression(canBeArrow);

    case types.bracketL:
      {
        const oldInFSharpPipelineDirectBody = this.state.inFSharpPipelineDirectBody;
        this.state.inFSharpPipelineDirectBody = false;
        node = this.startNode();
        this.next();
        node.elements = this.parseExprList(types.bracketR, true, refShorthandDefaultPos, node);

        if (!this.state.maybeInArrowParameters) {
          this.toReferencedList(node.elements);
        }

        this.state.inFSharpPipelineDirectBody = oldInFSharpPipelineDirectBody;
        return this.finishNode(node, "ArrayExpression");
      }

    case types.braceL:
      {
        const oldInFSharpPipelineDirectBody = this.state.inFSharpPipelineDirectBody;
        this.state.inFSharpPipelineDirectBody = false;
        const ret = this.parseObj(false, refShorthandDefaultPos);
        this.state.inFSharpPipelineDirectBody = oldInFSharpPipelineDirectBody;
        return ret;
      }

    case types._function:
      return this.parseFunctionExpression();

    case types.at:
      this.parseDecorators();

    case types._class:
      node = this.startNode();
      this.takeDecorators(node);
      return this.parseClass(node, false);

    case types._new:
      return this.parseNew();

    case types.backQuote:
      return this.parseTemplate(false);

    case types.doubleColon:
      {
        node = this.startNode();
        this.next();
        node.object = null;
        const callee = node.callee = this.parseNoCallExpr();

        if (callee.type === "MemberExpression") {
          return this.finishNode(node, "BindExpression");
        } else {
          throw this.raise(callee.start, "Binding should be performed on object property.");
        }
      }

    case types.hash:
      {
        if (this.state.inPipeline) {
          node = this.startNode();

          if (this.getPluginOption("pipelineOperator", "proposal") !== "smart") {
            this.raise(node.start, "Primary Topic Reference found but pipelineOperator not passed 'smart' for 'proposal' option.");
          }

          this.next();

          if (this.primaryTopicReferenceIsAllowedInCurrentTopicContext()) {
            this.registerTopicReference();
            return this.finishNode(node, "PipelinePrimaryTopicReference");
          } else {
            throw this.raise(node.start, `Topic reference was used in a lexical context without topic binding`);
          }
        }
      }

    default:
      throw this.unexpected();
  }
}

parseBooleanLiteral() {
  const node = this.startNode();
  node.value = this.match(types._true);
  this.next();
  return this.finishNode(node, "BooleanLiteral");
}

parseMaybePrivateName() {
  const isPrivate = this.match(types.hash);

  if (isPrivate) {
    this.expectOnePlugin(["classPrivateProperties", "classPrivateMethods"]);
    const node = this.startNode();
    this.next();
    this.assertNoSpace("Unexpected space between # and identifier");
    node.id = this.parseIdentifier(true);
    return this.finishNode(node, "PrivateName");
  } else {
    return this.parseIdentifier(true);
  }
}

parseFunctionExpression() {
  const node = this.startNode();
  let meta = this.startNode();
  this.next();
  meta = this.createIdentifier(meta, "function");

  if (this.scope.inGenerator && this.eat(types.dot)) {
    return this.parseMetaProperty(node, meta, "sent");
  }

  return this.parseFunction(node);
}

parseMetaProperty(node, meta, propertyName) {
  node.meta = meta;

  if (meta.name === "function" && propertyName === "sent") {
    if (this.isContextual(propertyName)) {
      this.expectPlugin("functionSent");
    } else if (!this.hasPlugin("functionSent")) {
      this.unexpected();
    }
  }

  const containsEsc = this.state.containsEsc;
  node.property = this.parseIdentifier(true);

  if (node.property.name !== propertyName || containsEsc) {
    this.raise(node.property.start, `The only valid meta property for ${meta.name} is ${meta.name}.${propertyName}`);
  }

  return this.finishNode(node, "MetaProperty");
}

parseImportMetaProperty(node) {
  const id = this.createIdentifier(this.startNodeAtNode(node), "import");
  this.expect(types.dot);

  if (this.isContextual("meta")) {
    this.expectPlugin("importMeta");
  } else if (!this.hasPlugin("importMeta")) {
    this.raise(id.start, `Dynamic imports require a parameter: import('a.js')`);
  }

  if (!this.inModule) {
    this.raise(id.start, `import.meta may appear only with 'sourceType: "module"'`, {
      code: "BABEL_PARSER_SOURCETYPE_MODULE_REQUIRED"
    });
  }

  this.sawUnambiguousESM = true;
  return this.parseMetaProperty(node, id, "meta");
}

parseLiteral(value, type, startPos, startLoc) {
  startPos = startPos || this.state.start;
  startLoc = startLoc || this.state.startLoc;
  const node = this.startNodeAt(startPos, startLoc);
  this.addExtra(node, "rawValue", value);
  this.addExtra(node, "raw", this.input.slice(startPos, this.state.end));
  node.value = value;
  this.next();
  return this.finishNode(node, type);
}

parseParenAndDistinguishExpression(canBeArrow) {
  const startPos = this.state.start;
  const startLoc = this.state.startLoc;
  let val;
  this.expect(types.parenL);
  const oldMaybeInArrowParameters = this.state.maybeInArrowParameters;
  const oldYieldPos = this.state.yieldPos;
  const oldAwaitPos = this.state.awaitPos;
  const oldInFSharpPipelineDirectBody = this.state.inFSharpPipelineDirectBody;
  this.state.maybeInArrowParameters = true;
  this.state.yieldPos = -1;
  this.state.awaitPos = -1;
  this.state.inFSharpPipelineDirectBody = false;
  const innerStartPos = this.state.start;
  const innerStartLoc = this.state.startLoc;
  const exprList = [];
  const refShorthandDefaultPos = {
    start: 0
  };
  const refNeedsArrowPos = {
    start: 0
  };
  let first = true;
  let spreadStart;
  let optionalCommaStart;

  while (!this.match(types.parenR)) {
    if (first) {
      first = false;
    } else {
      this.expect(types.comma, refNeedsArrowPos.start || null);

      if (this.match(types.parenR)) {
        optionalCommaStart = this.state.start;
        break;
      }
    }

    if (this.match(types.ellipsis)) {
      const spreadNodeStartPos = this.state.start;
      const spreadNodeStartLoc = this.state.startLoc;
      spreadStart = this.state.start;
      exprList.push(this.parseParenItem(this.parseRestBinding(), spreadNodeStartPos, spreadNodeStartLoc));
      this.checkCommaAfterRest(41);
      break;
    } else {
      exprList.push(this.parseMaybeAssign(false, refShorthandDefaultPos, this.parseParenItem, refNeedsArrowPos));
    }
  }

  const innerEndPos = this.state.start;
  const innerEndLoc = this.state.startLoc;
  this.expect(types.parenR);
  this.state.maybeInArrowParameters = oldMaybeInArrowParameters;
  this.state.inFSharpPipelineDirectBody = oldInFSharpPipelineDirectBody;
  let arrowNode = this.startNodeAt(startPos, startLoc);

  if (canBeArrow && this.shouldParseArrow() && (arrowNode = this.parseArrow(arrowNode))) {
    this.checkYieldAwaitInDefaultParams();
    this.state.yieldPos = oldYieldPos;
    this.state.awaitPos = oldAwaitPos;

    for (let _i = 0; _i < exprList.length; _i++) {
      const param = exprList[_i];

      if (param.extra && param.extra.parenthesized) {
        this.unexpected(param.extra.parenStart);
      }
    }

    this.parseArrowExpression(arrowNode, exprList, false);
    return arrowNode;
  }

  if (oldYieldPos !== -1) this.state.yieldPos = oldYieldPos;
  if (oldAwaitPos !== -1) this.state.awaitPos = oldAwaitPos;

  if (!exprList.length) {
    this.unexpected(this.state.lastTokStart);
  }

  if (optionalCommaStart) this.unexpected(optionalCommaStart);
  if (spreadStart) this.unexpected(spreadStart);

  if (refShorthandDefaultPos.start) {
    this.unexpected(refShorthandDefaultPos.start);
  }

  if (refNeedsArrowPos.start) this.unexpected(refNeedsArrowPos.start);
  this.toReferencedListDeep(exprList, true);

  if (exprList.length > 1) {
    val = this.startNodeAt(innerStartPos, innerStartLoc);
    val.expressions = exprList;
    this.finishNodeAt(val, "SequenceExpression", innerEndPos, innerEndLoc);
  } else {
    val = exprList[0];
  }

  if (!this.options.createParenthesizedExpressions) {
    this.addExtra(val, "parenthesized", true);
    this.addExtra(val, "parenStart", startPos);
    return val;
  }

  const parenExpression = this.startNodeAt(startPos, startLoc);
  parenExpression.expression = val;
  this.finishNode(parenExpression, "ParenthesizedExpression");
  return parenExpression;
}

shouldParseArrow() {
  return !this.canInsertSemicolon();
}

parseArrow(node) {
  if (this.eat(types.arrow)) {
    return node;
  }
}

parseParenItem(node, startPos, startLoc) {
  return node;
}

parseNew() {
  const node = this.startNode();
  const meta = this.parseIdentifier(true);

  if (this.eat(types.dot)) {
    const metaProp = this.parseMetaProperty(node, meta, "target");

    if (!this.scope.inNonArrowFunction && !this.state.inClassProperty) {
      let error = "new.target can only be used in functions";

      if (this.hasPlugin("classProperties")) {
        error += " or class properties";
      }

      this.raise(metaProp.start, error);
    }

    return metaProp;
  }

  node.callee = this.parseNoCallExpr();

  if (node.callee.type === "Import") {
    this.raise(node.callee.start, "Cannot use new with import(...)");
  } else if (node.callee.type === "OptionalMemberExpression" || node.callee.type === "OptionalCallExpression") {
    this.raise(this.state.lastTokEnd, "constructors in/after an Optional Chain are not allowed");
  } else if (this.eat(types.questionDot)) {
    this.raise(this.state.start, "constructors in/after an Optional Chain are not allowed");
  }

  this.parseNewArguments(node);
  return this.finishNode(node, "NewExpression");
}

parseNewArguments(node) {
  if (this.eat(types.parenL)) {
    const args = this.parseExprList(types.parenR);
    this.toReferencedList(args);
    node.arguments = args;
  } else {
    node.arguments = [];
  }
}

parseTemplateElement(isTagged) {
  const elem = this.startNode();

  if (this.state.value === null) {
    if (!isTagged) {
      this.raise(this.state.invalidTemplateEscapePosition || 0, "Invalid escape sequence in template");
    } else {
      this.state.invalidTemplateEscapePosition = null;
    }
  }

  elem.value = {
    raw: this.input.slice(this.state.start, this.state.end).replace(/\r\n?/g, "\n"),
    cooked: this.state.value
  };
  this.next();
  elem.tail = this.match(types.backQuote);
  return this.finishNode(elem, "TemplateElement");
}

parseTemplate(isTagged) {
  const node = this.startNode();
  this.next();
  node.expressions = [];
  let curElt = this.parseTemplateElement(isTagged);
  node.quasis = [curElt];

  while (!curElt.tail) {
    this.expect(types.dollarBraceL);
    node.expressions.push(this.parseExpression());
    this.expect(types.braceR);
    node.quasis.push(curElt = this.parseTemplateElement(isTagged));
  }

  this.next();
  return this.finishNode(node, "TemplateLiteral");
}

parseObj(isPattern, refShorthandDefaultPos) {
  const propHash = Object.create(null);
  let first = true;
  const node = this.startNode();
  node.properties = [];
  this.next();

  while (!this.eat(types.braceR)) {
    if (first) {
      first = false;
    } else {
      this.expect(types.comma);

      if (this.match(types.braceR)) {
        this.addExtra(node, "trailingComma", this.state.lastTokStart);
        this.next();
        break;
      }
    }

    const prop = this.parseObjectMember(isPattern, refShorthandDefaultPos);
    if (!isPattern) this.checkPropClash(prop, propHash);

    if (prop.shorthand) {
      this.addExtra(prop, "shorthand", true);
    }

    node.properties.push(prop);
  }

  return this.finishNode(node, isPattern ? "ObjectPattern" : "ObjectExpression");
}

isAsyncProp(prop) {
  return !prop.computed && prop.key.type === "Identifier" && prop.key.name === "async" && (this.match(types.name) || this.match(types.num) || this.match(types.string) || this.match(types.bracketL) || this.state.type.keyword || this.match(types.star)) && !this.hasPrecedingLineBreak();
}

parseObjectMember(isPattern, refShorthandDefaultPos) {
  let decorators = [];

  if (this.match(types.at)) {
    if (this.hasPlugin("decorators")) {
      this.raise(this.state.start, "Stage 2 decorators disallow object literal property decorators");
    } else {
      while (this.match(types.at)) {
        decorators.push(this.parseDecorator());
      }
    }
  }

  const prop = this.startNode();
  let isGenerator = false;
  let isAsync = false;
  let startPos;
  let startLoc;

  if (this.match(types.ellipsis)) {
    if (decorators.length) this.unexpected();

    if (isPattern) {
      this.next();
      prop.argument = this.parseIdentifier();
      this.checkCommaAfterRest(125);
      return this.finishNode(prop, "RestElement");
    }

    return this.parseSpread();
  }

  if (decorators.length) {
    prop.decorators = decorators;
    decorators = [];
  }

  prop.method = false;

  if (isPattern || refShorthandDefaultPos) {
    startPos = this.state.start;
    startLoc = this.state.startLoc;
  }

  if (!isPattern) {
    isGenerator = this.eat(types.star);
  }

  const containsEsc = this.state.containsEsc;
  this.parsePropertyName(prop);

  if (!isPattern && !containsEsc && !isGenerator && this.isAsyncProp(prop)) {
    isAsync = true;
    isGenerator = this.eat(types.star);
    this.parsePropertyName(prop);
  } else {
    isAsync = false;
  }

  this.parseObjPropValue(prop, startPos, startLoc, isGenerator, isAsync, isPattern, refShorthandDefaultPos, containsEsc);
  return prop;
}

isGetterOrSetterMethod(prop, isPattern) {
  return !isPattern && !prop.computed && prop.key.type === "Identifier" && (prop.key.name === "get" || prop.key.name === "set") && (this.match(types.string) || this.match(types.num) || this.match(types.bracketL) || this.match(types.name) || !!this.state.type.keyword);
}

getGetterSetterExpectedParamCount(method) {
  return method.kind === "get" ? 0 : 1;
}

checkGetterSetterParams(method) {
  const paramCount = this.getGetterSetterExpectedParamCount(method);
  const start = method.start;

  if (method.params.length !== paramCount) {
    if (method.kind === "get") {
      this.raise(start, "getter must not have any formal parameters");
    } else {
      this.raise(start, "setter must have exactly one formal parameter");
    }
  }

  if (method.kind === "set" && method.params[method.params.length - 1].type === "RestElement") {
    this.raise(start, "setter function argument must not be a rest parameter");
  }
}

parseObjectMethod(prop, isGenerator, isAsync, isPattern, containsEsc) {
  if (isAsync || isGenerator || this.match(types.parenL)) {
    if (isPattern) this.unexpected();
    prop.kind = "method";
    prop.method = true;
    return this.parseMethod(prop, isGenerator, isAsync, false, false, "ObjectMethod");
  }

  if (!containsEsc && this.isGetterOrSetterMethod(prop, isPattern)) {
    if (isGenerator || isAsync) this.unexpected();
    prop.kind = prop.key.name;
    this.parsePropertyName(prop);
    this.parseMethod(prop, false, false, false, false, "ObjectMethod");
    this.checkGetterSetterParams(prop);
    return prop;
  }
}

parseObjectProperty(prop, startPos, startLoc, isPattern, refShorthandDefaultPos) {
  prop.shorthand = false;

  if (this.eat(types.colon)) {
    prop.value = isPattern ? this.parseMaybeDefault(this.state.start, this.state.startLoc) : this.parseMaybeAssign(false, refShorthandDefaultPos);
    return this.finishNode(prop, "ObjectProperty");
  }

  if (!prop.computed && prop.key.type === "Identifier") {
    this.checkReservedWord(prop.key.name, prop.key.start, true, true);

    if (isPattern) {
      prop.value = this.parseMaybeDefault(startPos, startLoc, prop.key.__clone());
    } else if (this.match(types.eq) && refShorthandDefaultPos) {
      if (!refShorthandDefaultPos.start) {
        refShorthandDefaultPos.start = this.state.start;
      }

      prop.value = this.parseMaybeDefault(startPos, startLoc, prop.key.__clone());
    } else {
      prop.value = prop.key.__clone();
    }

    prop.shorthand = true;
    return this.finishNode(prop, "ObjectProperty");
  }
}

parseObjPropValue(prop, startPos, startLoc, isGenerator, isAsync, isPattern, refShorthandDefaultPos, containsEsc) {
  const node = this.parseObjectMethod(prop, isGenerator, isAsync, isPattern, containsEsc) || this.parseObjectProperty(prop, startPos, startLoc, isPattern, refShorthandDefaultPos);
  if (!node) this.unexpected();
  return node;
}

parsePropertyName(prop) {
  if (this.eat(types.bracketL)) {
    prop.computed = true;
    prop.key = this.parseMaybeAssign();
    this.expect(types.bracketR);
  } else {
    const oldInPropertyName = this.state.inPropertyName;
    this.state.inPropertyName = true;
    prop.key = this.match(types.num) || this.match(types.string) ? this.parseExprAtom() : this.parseMaybePrivateName();

    if (prop.key.type !== "PrivateName") {
      prop.computed = false;
    }

    this.state.inPropertyName = oldInPropertyName;
  }

  return prop.key;
}

initFunction(node, isAsync) {
  node.id = null;
  node.generator = false;
  node.async = !!isAsync;
}

parseMethod(node, isGenerator, isAsync, isConstructor, allowDirectSuper, type, inClassScope = false) {
  const oldYieldPos = this.state.yieldPos;
  const oldAwaitPos = this.state.awaitPos;
  this.state.yieldPos = -1;
  this.state.awaitPos = -1;
  this.initFunction(node, isAsync);
  node.generator = !!isGenerator;
  const allowModifiers = isConstructor;
  this.scope.enter(functionFlags(isAsync, node.generator) | SCOPE_SUPER | (inClassScope ? SCOPE_CLASS : 0) | (allowDirectSuper ? SCOPE_DIRECT_SUPER : 0));
  this.parseFunctionParams(node, allowModifiers);
  this.checkYieldAwaitInDefaultParams();
  this.parseFunctionBodyAndFinish(node, type, true);
  this.scope.exit();
  this.state.yieldPos = oldYieldPos;
  this.state.awaitPos = oldAwaitPos;
  return node;
}

parseArrowExpression(node, params, isAsync, trailingCommaPos) {
  this.scope.enter(functionFlags(isAsync, false) | SCOPE_ARROW);
  this.initFunction(node, isAsync);
  const oldMaybeInArrowParameters = this.state.maybeInArrowParameters;
  const oldYieldPos = this.state.yieldPos;
  const oldAwaitPos = this.state.awaitPos;
  this.state.maybeInArrowParameters = false;
  this.state.yieldPos = -1;
  this.state.awaitPos = -1;
  if (params) this.setArrowFunctionParameters(node, params, trailingCommaPos);
  this.parseFunctionBody(node, true);
  this.scope.exit();
  this.state.maybeInArrowParameters = oldMaybeInArrowParameters;
  this.state.yieldPos = oldYieldPos;
  this.state.awaitPos = oldAwaitPos;
  return this.finishNode(node, "ArrowFunctionExpression");
}

setArrowFunctionParameters(node, params, trailingCommaPos) {
  node.params = this.toAssignableList(params, true, "arrow function parameters", trailingCommaPos);
}

isStrictBody(node) {
  const isBlockStatement = node.body.type === "BlockStatement";

  if (isBlockStatement && node.body.directives.length) {
    for (let _i2 = 0, _node$body$directives = node.body.directives; _i2 < _node$body$directives.length; _i2++) {
      const directive = _node$body$directives[_i2];

      if (directive.value.value === "use strict") {
        return true;
      }
    }
  }

  return false;
}

parseFunctionBodyAndFinish(node, type, isMethod = false) {
  this.parseFunctionBody(node, false, isMethod);
  this.finishNode(node, type);
}

parseFunctionBody(node, allowExpression, isMethod = false) {
  const isExpression = allowExpression && !this.match(types.braceL);
  const oldStrict = this.state.strict;
  let useStrict = false;
  const oldInParameters = this.state.inParameters;
  this.state.inParameters = false;

  if (isExpression) {
    node.body = this.parseMaybeAssign();
    this.checkParams(node, false, allowExpression);
  } else {
    const nonSimple = !this.isSimpleParamList(node.params);

    if (!oldStrict || nonSimple) {
      useStrict = this.strictDirective(this.state.end);

      if (useStrict && nonSimple) {
        const errorPos = (node.kind === "method" || node.kind === "constructor") && !!node.key ? node.key.end : node.start;
        this.raise(errorPos, "Illegal 'use strict' directive in function with non-simple parameter list");
      }
    }

    const oldLabels = this.state.labels;
    this.state.labels = [];
    if (useStrict) this.state.strict = true;
    this.checkParams(node, !oldStrict && !useStrict && !allowExpression && !isMethod && !nonSimple, allowExpression);
    node.body = this.parseBlock(true, false);
    this.state.labels = oldLabels;
  }

  this.state.inParameters = oldInParameters;

  if (this.state.strict && node.id) {
    this.checkLVal(node.id, BIND_OUTSIDE, undefined, "function name");
  }

  this.state.strict = oldStrict;
}

isSimpleParamList(params) {
  for (let i = 0, len = params.length; i < len; i++) {
    if (params[i].type !== "Identifier") return false;
  }

  return true;
}

checkParams(node, allowDuplicates, isArrowFunction) {
  const nameHash = Object.create(null);

  for (let i = 0; i < node.params.length; i++) {
    this.checkLVal(node.params[i], BIND_VAR, allowDuplicates ? null : nameHash, "function parameter list");
  }
}

parseExprList(close, allowEmpty, refShorthandDefaultPos, nodeForExtra) {
  const elts = [];
  let first = true;

  while (!this.eat(close)) {
    if (first) {
      first = false;
    } else {
      this.expect(types.comma);

      if (this.match(close)) {
        if (nodeForExtra) {
          this.addExtra(nodeForExtra, "trailingComma", this.state.lastTokStart);
        }

        this.next();
        break;
      }
    }

    elts.push(this.parseExprListItem(allowEmpty, refShorthandDefaultPos));
  }

  return elts;
}

parseExprListItem(allowEmpty, refShorthandDefaultPos, refNeedsArrowPos, allowPlaceholder) {
  let elt;

  if (allowEmpty && this.match(types.comma)) {
    elt = null;
  } else if (this.match(types.ellipsis)) {
    const spreadNodeStartPos = this.state.start;
    const spreadNodeStartLoc = this.state.startLoc;
    elt = this.parseParenItem(this.parseSpread(refShorthandDefaultPos, refNeedsArrowPos), spreadNodeStartPos, spreadNodeStartLoc);
  } else if (this.match(types.question)) {
    this.expectPlugin("partialApplication");

    if (!allowPlaceholder) {
      this.raise(this.state.start, "Unexpected argument placeholder");
    }

    const node = this.startNode();
    this.next();
    elt = this.finishNode(node, "ArgumentPlaceholder");
  } else {
    elt = this.parseMaybeAssign(false, refShorthandDefaultPos, this.parseParenItem, refNeedsArrowPos);
  }

  return elt;
}

parseIdentifier(liberal) {
  const node = this.startNode();
  const name = this.parseIdentifierName(node.start, liberal);
  return this.createIdentifier(node, name);
}

createIdentifier(node, name) {
  node.name = name;
  node.loc.identifierName = name;
  return this.finishNode(node, "Identifier");
}

parseIdentifierName(pos, liberal) {
  let name;

  if (this.match(types.name)) {
    name = this.state.value;

    if (!liberal && this.state.containsEsc && isKeyword(name)) {
      this.raise(this.state.pos, `Escape sequence in keyword ${name}`);
    }
  } else if (this.state.type.keyword) {
    name = this.state.type.keyword;

    if ((name === "class" || name === "function") && (this.state.lastTokEnd !== this.state.lastTokStart + 1 || this.input.charCodeAt(this.state.lastTokStart) !== 46)) {
      this.state.context.pop();
    }
  } else {
    throw this.unexpected();
  }

  if (!liberal) {
    this.checkReservedWord(name, this.state.start, !!this.state.type.keyword, false);
  }

  this.next();
  return name;
}

checkReservedWord(word, startLoc, checkKeywords, isBinding) {
  if (this.scope.inGenerator && word === "yield") {
    this.raise(startLoc, "Can not use 'yield' as identifier inside a generator");
  }

  if (word === "await") {
    if (this.scope.inAsync) {
      this.raise(startLoc, "Can not use 'await' as identifier inside an async function");
    } else if (this.state.awaitPos === -1 && (this.state.maybeInArrowParameters || this.isAwaitAllowed())) {
      this.state.awaitPos = this.state.start;
    }
  }

  if (this.state.inClassProperty && word === "arguments") {
    this.raise(startLoc, "'arguments' is not allowed in class field initializer");
  }

  if (checkKeywords && isKeyword(word)) {
    this.raise(startLoc, `Unexpected keyword '${word}'`);
  }

  const reservedTest = !this.state.strict ? isReservedWord : isBinding ? isStrictBindReservedWord : isStrictReservedWord;

  if (reservedTest(word, this.inModule)) {
    if (!this.scope.inAsync && word === "await") {
      this.raise(startLoc, "Can not use keyword 'await' outside an async function");
    }

    this.raise(startLoc, `Unexpected reserved word '${word}'`);
  }
}

isAwaitAllowed() {
  if (this.scope.inFunction) return this.scope.inAsync;
  if (this.options.allowAwaitOutsideFunction) return true;
  return false;
}

parseAwait() {
  if (this.state.awaitPos === -1) {
    this.state.awaitPos = this.state.start;
  }

  const node = this.startNode();
  this.next();

  if (this.state.inParameters) {
    this.raise(node.start, "await is not allowed in async function parameters");
  }

  if (this.match(types.star)) {
    this.raise(node.start, "await* has been removed from the async functions proposal. Use Promise.all() instead.");
  }

  if (!this.state.soloAwait) {
    node.argument = this.parseMaybeUnary();
  }

  return this.finishNode(node, "AwaitExpression");
}

parseYield(noIn) {
  if (this.state.yieldPos === -1) {
    this.state.yieldPos = this.state.start;
  }

  const node = this.startNode();

  if (this.state.inParameters) {
    this.raise(node.start, "yield is not allowed in generator parameters");
  }

  this.next();

  if (this.match(types.semi) || !this.match(types.star) && !this.state.type.startsExpr || this.hasPrecedingLineBreak()) {
    node.delegate = false;
    node.argument = null;
  } else {
    node.delegate = this.eat(types.star);
    node.argument = this.parseMaybeAssign(noIn);
  }

  return this.finishNode(node, "YieldExpression");
}

checkPipelineAtInfixOperator(left, leftStartPos) {
  if (this.getPluginOption("pipelineOperator", "proposal") === "smart") {
    if (left.type === "SequenceExpression") {
      throw this.raise(leftStartPos, `Pipeline head should not be a comma-separated sequence expression`);
    }
  }
}

parseSmartPipelineBody(childExpression, startPos, startLoc) {
  const pipelineStyle = this.checkSmartPipelineBodyStyle(childExpression);
  this.checkSmartPipelineBodyEarlyErrors(childExpression, pipelineStyle, startPos);
  return this.parseSmartPipelineBodyInStyle(childExpression, pipelineStyle, startPos, startLoc);
}

checkSmartPipelineBodyEarlyErrors(childExpression, pipelineStyle, startPos) {
  if (this.match(types.arrow)) {
    throw this.raise(this.state.start, `Unexpected arrow "=>" after pipeline body; arrow function in pipeline body must be parenthesized`);
  } else if (pipelineStyle === "PipelineTopicExpression" && childExpression.type === "SequenceExpression") {
    throw this.raise(startPos, `Pipeline body may not be a comma-separated sequence expression`);
  }
}

parseSmartPipelineBodyInStyle(childExpression, pipelineStyle, startPos, startLoc) {
  const bodyNode = this.startNodeAt(startPos, startLoc);

  switch (pipelineStyle) {
    case "PipelineBareFunction":
      bodyNode.callee = childExpression;
      break;

    case "PipelineBareConstructor":
      bodyNode.callee = childExpression.callee;
      break;

    case "PipelineBareAwaitedFunction":
      bodyNode.callee = childExpression.argument;
      break;

    case "PipelineTopicExpression":
      if (!this.topicReferenceWasUsedInCurrentTopicContext()) {
        throw this.raise(startPos, `Pipeline is in topic style but does not use topic reference`);
      }

      bodyNode.expression = childExpression;
      break;

    default:
      throw this.raise(startPos, `Unknown pipeline style ${pipelineStyle}`);
  }

  return this.finishNode(bodyNode, pipelineStyle);
}

checkSmartPipelineBodyStyle(expression) {
  switch (expression.type) {
    default:
      return this.isSimpleReference(expression) ? "PipelineBareFunction" : "PipelineTopicExpression";
  }
}

isSimpleReference(expression) {
  switch (expression.type) {
    case "MemberExpression":
      return !expression.computed && this.isSimpleReference(expression.object);

    case "Identifier":
      return true;

    default:
      return false;
  }
}

withTopicPermittingContext(callback) {
  const outerContextTopicState = this.state.topicContext;
  this.state.topicContext = {
    maxNumOfResolvableTopics: 1,
    maxTopicIndex: null
  };

  try {
    return callback();
  } finally {
    this.state.topicContext = outerContextTopicState;
  }
}

withTopicForbiddingContext(callback) {
  const outerContextTopicState = this.state.topicContext;
  this.state.topicContext = {
    maxNumOfResolvableTopics: 0,
    maxTopicIndex: null
  };

  try {
    return callback();
  } finally {
    this.state.topicContext = outerContextTopicState;
  }
}

withSoloAwaitPermittingContext(callback) {
  const outerContextSoloAwaitState = this.state.soloAwait;
  this.state.soloAwait = true;

  try {
    return callback();
  } finally {
    this.state.soloAwait = outerContextSoloAwaitState;
  }
}

registerTopicReference() {
  this.state.topicContext.maxTopicIndex = 0;
}

primaryTopicReferenceIsAllowedInCurrentTopicContext() {
  return this.state.topicContext.maxNumOfResolvableTopics >= 1;
}

topicReferenceWasUsedInCurrentTopicContext() {
  return this.state.topicContext.maxTopicIndex != null && this.state.topicContext.maxTopicIndex >= 0;
}

parseFSharpPipelineBody(prec, noIn) {
  const startPos = this.state.start;
  const startLoc = this.state.startLoc;
  this.state.potentialArrowAt = this.state.start;
  const oldInFSharpPipelineDirectBody = this.state.inFSharpPipelineDirectBody;
  this.state.inFSharpPipelineDirectBody = true;
  const ret = this.parseExprOp(this.parseMaybeUnary(), startPos, startLoc, prec, noIn);
  this.state.inFSharpPipelineDirectBody = oldInFSharpPipelineDirectBody;
  return ret;
}

}

const loopLabel = {

kind: "loop"

},

    switchLabel = {
kind: "switch"

}; const FUNC_NO_FLAGS = 0b000,

FUNC_STATEMENT = 0b001,
FUNC_HANGING_STATEMENT = 0b010,
FUNC_NULLABLE_ID = 0b100;

class StatementParser extends ExpressionParser {

parseTopLevel(file, program) {
  program.sourceType = this.options.sourceType;
  program.interpreter = this.parseInterpreterDirective();
  this.parseBlockBody(program, true, true, types.eof);

  if (this.inModule && !this.options.allowUndeclaredExports && this.scope.undefinedExports.size > 0) {
    for (let _i = 0, _Array$from = Array.from(this.scope.undefinedExports); _i < _Array$from.length; _i++) {
      const [name] = _Array$from[_i];
      const pos = this.scope.undefinedExports.get(name);
      this.raise(pos, `Export '${name}' is not defined`);
    }
  }

  file.program = this.finishNode(program, "Program");
  file.comments = this.state.comments;
  if (this.options.tokens) file.tokens = this.state.tokens;
  return this.finishNode(file, "File");
}

stmtToDirective(stmt) {
  const expr = stmt.expression;
  const directiveLiteral = this.startNodeAt(expr.start, expr.loc.start);
  const directive = this.startNodeAt(stmt.start, stmt.loc.start);
  const raw = this.input.slice(expr.start, expr.end);
  const val = directiveLiteral.value = raw.slice(1, -1);
  this.addExtra(directiveLiteral, "raw", raw);
  this.addExtra(directiveLiteral, "rawValue", val);
  directive.value = this.finishNodeAt(directiveLiteral, "DirectiveLiteral", expr.end, expr.loc.end);
  return this.finishNodeAt(directive, "Directive", stmt.end, stmt.loc.end);
}

parseInterpreterDirective() {
  if (!this.match(types.interpreterDirective)) {
    return null;
  }

  const node = this.startNode();
  node.value = this.state.value;
  this.next();
  return this.finishNode(node, "InterpreterDirective");
}

isLet(context) {
  if (!this.isContextual("let")) {
    return false;
  }

  const next = this.nextTokenStart();
  const nextCh = this.input.charCodeAt(next);
  if (nextCh === 91) return true;
  if (context) return false;
  if (nextCh === 123) return true;

  if (isIdentifierStart(nextCh)) {
    let pos = next + 1;

    while (isIdentifierChar(this.input.charCodeAt(pos))) {
      ++pos;
    }

    const ident = this.input.slice(next, pos);
    if (!keywordRelationalOperator.test(ident)) return true;
  }

  return false;
}

parseStatement(context, topLevel) {
  if (this.match(types.at)) {
    this.parseDecorators(true);
  }

  return this.parseStatementContent(context, topLevel);
}

parseStatementContent(context, topLevel) {
  let starttype = this.state.type;
  const node = this.startNode();
  let kind;

  if (this.isLet(context)) {
    starttype = types._var;
    kind = "let";
  }

  switch (starttype) {
    case types._break:
    case types._continue:
      return this.parseBreakContinueStatement(node, starttype.keyword);

    case types._debugger:
      return this.parseDebuggerStatement(node);

    case types._do:
      return this.parseDoStatement(node);

    case types._for:
      return this.parseForStatement(node);

    case types._function:
      if (this.lookaheadCharCode() === 46) break;

      if (context) {
        if (this.state.strict) {
          this.raise(this.state.start, "In strict mode code, functions can only be declared at top level or inside a block");
        } else if (context !== "if" && context !== "label") {
          this.raise(this.state.start, "In non-strict mode code, functions can only be declared at top level, " + "inside a block, or as the body of an if statement");
        }
      }

      return this.parseFunctionStatement(node, false, !context);

    case types._class:
      if (context) this.unexpected();
      return this.parseClass(node, true);

    case types._if:
      return this.parseIfStatement(node);

    case types._return:
      return this.parseReturnStatement(node);

    case types._switch:
      return this.parseSwitchStatement(node);

    case types._throw:
      return this.parseThrowStatement(node);

    case types._try:
      return this.parseTryStatement(node);

    case types._const:
    case types._var:
      kind = kind || this.state.value;

      if (context && kind !== "var") {
        this.unexpected(this.state.start, "Lexical declaration cannot appear in a single-statement context");
      }

      return this.parseVarStatement(node, kind);

    case types._while:
      return this.parseWhileStatement(node);

    case types._with:
      return this.parseWithStatement(node);

    case types.braceL:
      return this.parseBlock();

    case types.semi:
      return this.parseEmptyStatement(node);

    case types._export:
    case types._import:
      {
        const nextTokenCharCode = this.lookaheadCharCode();

        if (nextTokenCharCode === 40 || nextTokenCharCode === 46) {
          break;
        }

        if (!this.options.allowImportExportEverywhere && !topLevel) {
          this.raise(this.state.start, "'import' and 'export' may only appear at the top level");
        }

        this.next();
        let result;

        if (starttype === types._import) {
          result = this.parseImport(node);

          if (result.type === "ImportDeclaration" && (!result.importKind || result.importKind === "value")) {
            this.sawUnambiguousESM = true;
          }
        } else {
          result = this.parseExport(node);

          if (result.type === "ExportNamedDeclaration" && (!result.exportKind || result.exportKind === "value") || result.type === "ExportAllDeclaration" && (!result.exportKind || result.exportKind === "value") || result.type === "ExportDefaultDeclaration") {
            this.sawUnambiguousESM = true;
          }
        }

        this.assertModuleNodeAllowed(node);
        return result;
      }

    default:
      {
        if (this.isAsyncFunction()) {
          if (context) {
            this.unexpected(null, "Async functions can only be declared at the top level or inside a block");
          }

          this.next();
          return this.parseFunctionStatement(node, true, !context);
        }
      }
  }

  const maybeName = this.state.value;
  const expr = this.parseExpression();

  if (starttype === types.name && expr.type === "Identifier" && this.eat(types.colon)) {
    return this.parseLabeledStatement(node, maybeName, expr, context);
  } else {
    return this.parseExpressionStatement(node, expr);
  }
}

assertModuleNodeAllowed(node) {
  if (!this.options.allowImportExportEverywhere && !this.inModule) {
    this.raise(node.start, `'import' and 'export' may appear only with 'sourceType: "module"'`, {
      code: "BABEL_PARSER_SOURCETYPE_MODULE_REQUIRED"
    });
  }
}

takeDecorators(node) {
  const decorators = this.state.decoratorStack[this.state.decoratorStack.length - 1];

  if (decorators.length) {
    node.decorators = decorators;
    this.resetStartLocationFromNode(node, decorators[0]);
    this.state.decoratorStack[this.state.decoratorStack.length - 1] = [];
  }
}

canHaveLeadingDecorator() {
  return this.match(types._class);
}

parseDecorators(allowExport) {
  const currentContextDecorators = this.state.decoratorStack[this.state.decoratorStack.length - 1];

  while (this.match(types.at)) {
    const decorator = this.parseDecorator();
    currentContextDecorators.push(decorator);
  }

  if (this.match(types._export)) {
    if (!allowExport) {
      this.unexpected();
    }

    if (this.hasPlugin("decorators") && !this.getPluginOption("decorators", "decoratorsBeforeExport")) {
      this.raise(this.state.start, "Using the export keyword between a decorator and a class is not allowed. " + "Please use `export @dec class` instead.");
    }
  } else if (!this.canHaveLeadingDecorator()) {
    this.raise(this.state.start, "Leading decorators must be attached to a class declaration");
  }
}

parseDecorator() {
  this.expectOnePlugin(["decorators-legacy", "decorators"]);
  const node = this.startNode();
  this.next();

  if (this.hasPlugin("decorators")) {
    this.state.decoratorStack.push([]);
    const startPos = this.state.start;
    const startLoc = this.state.startLoc;
    let expr;

    if (this.eat(types.parenL)) {
      expr = this.parseExpression();
      this.expect(types.parenR);
    } else {
      expr = this.parseIdentifier(false);

      while (this.eat(types.dot)) {
        const node = this.startNodeAt(startPos, startLoc);
        node.object = expr;
        node.property = this.parseIdentifier(true);
        node.computed = false;
        expr = this.finishNode(node, "MemberExpression");
      }
    }

    node.expression = this.parseMaybeDecoratorArguments(expr);
    this.state.decoratorStack.pop();
  } else {
    node.expression = this.parseExprSubscripts();
  }

  return this.finishNode(node, "Decorator");
}

parseMaybeDecoratorArguments(expr) {
  if (this.eat(types.parenL)) {
    const node = this.startNodeAtNode(expr);
    node.callee = expr;
    node.arguments = this.parseCallExpressionArguments(types.parenR, false);
    this.toReferencedList(node.arguments);
    return this.finishNode(node, "CallExpression");
  }

  return expr;
}

parseBreakContinueStatement(node, keyword) {
  const isBreak = keyword === "break";
  this.next();

  if (this.isLineTerminator()) {
    node.label = null;
  } else {
    node.label = this.parseIdentifier();
    this.semicolon();
  }

  this.verifyBreakContinue(node, keyword);
  return this.finishNode(node, isBreak ? "BreakStatement" : "ContinueStatement");
}

verifyBreakContinue(node, keyword) {
  const isBreak = keyword === "break";
  let i;

  for (i = 0; i < this.state.labels.length; ++i) {
    const lab = this.state.labels[i];

    if (node.label == null || lab.name === node.label.name) {
      if (lab.kind != null && (isBreak || lab.kind === "loop")) break;
      if (node.label && isBreak) break;
    }
  }

  if (i === this.state.labels.length) {
    this.raise(node.start, "Unsyntactic " + keyword);
  }
}

parseDebuggerStatement(node) {
  this.next();
  this.semicolon();
  return this.finishNode(node, "DebuggerStatement");
}

parseHeaderExpression() {
  this.expect(types.parenL);
  const val = this.parseExpression();
  this.expect(types.parenR);
  return val;
}

parseDoStatement(node) {
  this.next();
  this.state.labels.push(loopLabel);
  node.body = this.withTopicForbiddingContext(() => this.parseStatement("do"));
  this.state.labels.pop();
  this.expect(types._while);
  node.test = this.parseHeaderExpression();
  this.eat(types.semi);
  return this.finishNode(node, "DoWhileStatement");
}

parseForStatement(node) {
  this.next();
  this.state.labels.push(loopLabel);
  let awaitAt = -1;

  if ((this.scope.inAsync || !this.scope.inFunction && this.options.allowAwaitOutsideFunction) && this.eatContextual("await")) {
    awaitAt = this.state.lastTokStart;
  }

  this.scope.enter(SCOPE_OTHER);
  this.expect(types.parenL);

  if (this.match(types.semi)) {
    if (awaitAt > -1) {
      this.unexpected(awaitAt);
    }

    return this.parseFor(node, null);
  }

  const isLet = this.isLet();

  if (this.match(types._var) || this.match(types._const) || isLet) {
    const init = this.startNode();
    const kind = isLet ? "let" : this.state.value;
    this.next();
    this.parseVar(init, true, kind);
    this.finishNode(init, "VariableDeclaration");

    if ((this.match(types._in) || this.isContextual("of")) && init.declarations.length === 1) {
      return this.parseForIn(node, init, awaitAt);
    }

    if (awaitAt > -1) {
      this.unexpected(awaitAt);
    }

    return this.parseFor(node, init);
  }

  const refShorthandDefaultPos = {
    start: 0
  };
  const init = this.parseExpression(true, refShorthandDefaultPos);

  if (this.match(types._in) || this.isContextual("of")) {
    const description = this.isContextual("of") ? "for-of statement" : "for-in statement";
    this.toAssignable(init, undefined, description);
    this.checkLVal(init, undefined, undefined, description);
    return this.parseForIn(node, init, awaitAt);
  } else if (refShorthandDefaultPos.start) {
    this.unexpected(refShorthandDefaultPos.start);
  }

  if (awaitAt > -1) {
    this.unexpected(awaitAt);
  }

  return this.parseFor(node, init);
}

parseFunctionStatement(node, isAsync, declarationPosition) {
  this.next();
  return this.parseFunction(node, FUNC_STATEMENT | (declarationPosition ? 0 : FUNC_HANGING_STATEMENT), isAsync);
}

parseIfStatement(node) {
  this.next();
  node.test = this.parseHeaderExpression();
  node.consequent = this.parseStatement("if");
  node.alternate = this.eat(types._else) ? this.parseStatement("if") : null;
  return this.finishNode(node, "IfStatement");
}

parseReturnStatement(node) {
  if (!this.scope.inFunction && !this.options.allowReturnOutsideFunction) {
    this.raise(this.state.start, "'return' outside of function");
  }

  this.next();

  if (this.isLineTerminator()) {
    node.argument = null;
  } else {
    node.argument = this.parseExpression();
    this.semicolon();
  }

  return this.finishNode(node, "ReturnStatement");
}

parseSwitchStatement(node) {
  this.next();
  node.discriminant = this.parseHeaderExpression();
  const cases = node.cases = [];
  this.expect(types.braceL);
  this.state.labels.push(switchLabel);
  this.scope.enter(SCOPE_OTHER);
  let cur;

  for (let sawDefault; !this.match(types.braceR);) {
    if (this.match(types._case) || this.match(types._default)) {
      const isCase = this.match(types._case);
      if (cur) this.finishNode(cur, "SwitchCase");
      cases.push(cur = this.startNode());
      cur.consequent = [];
      this.next();

      if (isCase) {
        cur.test = this.parseExpression();
      } else {
        if (sawDefault) {
          this.raise(this.state.lastTokStart, "Multiple default clauses");
        }

        sawDefault = true;
        cur.test = null;
      }

      this.expect(types.colon);
    } else {
      if (cur) {
        cur.consequent.push(this.parseStatement(null));
      } else {
        this.unexpected();
      }
    }
  }

  this.scope.exit();
  if (cur) this.finishNode(cur, "SwitchCase");
  this.next();
  this.state.labels.pop();
  return this.finishNode(node, "SwitchStatement");
}

parseThrowStatement(node) {
  this.next();

  if (lineBreak.test(this.input.slice(this.state.lastTokEnd, this.state.start))) {
    this.raise(this.state.lastTokEnd, "Illegal newline after throw");
  }

  node.argument = this.parseExpression();
  this.semicolon();
  return this.finishNode(node, "ThrowStatement");
}

parseTryStatement(node) {
  this.next();
  node.block = this.parseBlock();
  node.handler = null;

  if (this.match(types._catch)) {
    const clause = this.startNode();
    this.next();

    if (this.match(types.parenL)) {
      this.expect(types.parenL);
      clause.param = this.parseBindingAtom();
      const simple = clause.param.type === "Identifier";
      this.scope.enter(simple ? SCOPE_SIMPLE_CATCH : 0);
      this.checkLVal(clause.param, BIND_LEXICAL, null, "catch clause");
      this.expect(types.parenR);
    } else {
      clause.param = null;
      this.scope.enter(SCOPE_OTHER);
    }

    clause.body = this.withTopicForbiddingContext(() => this.parseBlock(false, false));
    this.scope.exit();
    node.handler = this.finishNode(clause, "CatchClause");
  }

  node.finalizer = this.eat(types._finally) ? this.parseBlock() : null;

  if (!node.handler && !node.finalizer) {
    this.raise(node.start, "Missing catch or finally clause");
  }

  return this.finishNode(node, "TryStatement");
}

parseVarStatement(node, kind) {
  this.next();
  this.parseVar(node, false, kind);
  this.semicolon();
  return this.finishNode(node, "VariableDeclaration");
}

parseWhileStatement(node) {
  this.next();
  node.test = this.parseHeaderExpression();
  this.state.labels.push(loopLabel);
  node.body = this.withTopicForbiddingContext(() => this.parseStatement("while"));
  this.state.labels.pop();
  return this.finishNode(node, "WhileStatement");
}

parseWithStatement(node) {
  if (this.state.strict) {
    this.raise(this.state.start, "'with' in strict mode");
  }

  this.next();
  node.object = this.parseHeaderExpression();
  node.body = this.withTopicForbiddingContext(() => this.parseStatement("with"));
  return this.finishNode(node, "WithStatement");
}

parseEmptyStatement(node) {
  this.next();
  return this.finishNode(node, "EmptyStatement");
}

parseLabeledStatement(node, maybeName, expr, context) {
  for (let _i2 = 0, _this$state$labels = this.state.labels; _i2 < _this$state$labels.length; _i2++) {
    const label = _this$state$labels[_i2];

    if (label.name === maybeName) {
      this.raise(expr.start, `Label '${maybeName}' is already declared`);
    }
  }

  const kind = this.state.type.isLoop ? "loop" : this.match(types._switch) ? "switch" : null;

  for (let i = this.state.labels.length - 1; i >= 0; i--) {
    const label = this.state.labels[i];

    if (label.statementStart === node.start) {
      label.statementStart = this.state.start;
      label.kind = kind;
    } else {
      break;
    }
  }

  this.state.labels.push({
    name: maybeName,
    kind: kind,
    statementStart: this.state.start
  });
  node.body = this.parseStatement(context ? context.indexOf("label") === -1 ? context + "label" : context : "label");
  this.state.labels.pop();
  node.label = expr;
  return this.finishNode(node, "LabeledStatement");
}

parseExpressionStatement(node, expr) {
  node.expression = expr;
  this.semicolon();
  return this.finishNode(node, "ExpressionStatement");
}

parseBlock(allowDirectives = false, createNewLexicalScope = true) {
  const node = this.startNode();
  this.expect(types.braceL);

  if (createNewLexicalScope) {
    this.scope.enter(SCOPE_OTHER);
  }

  this.parseBlockBody(node, allowDirectives, false, types.braceR);

  if (createNewLexicalScope) {
    this.scope.exit();
  }

  return this.finishNode(node, "BlockStatement");
}

isValidDirective(stmt) {
  return stmt.type === "ExpressionStatement" && stmt.expression.type === "StringLiteral" && !stmt.expression.extra.parenthesized;
}

parseBlockBody(node, allowDirectives, topLevel, end) {
  const body = node.body = [];
  const directives = node.directives = [];
  this.parseBlockOrModuleBlockBody(body, allowDirectives ? directives : undefined, topLevel, end);
}

parseBlockOrModuleBlockBody(body, directives, topLevel, end) {
  let parsedNonDirective = false;
  let oldStrict;
  let octalPosition;

  while (!this.eat(end)) {
    if (!parsedNonDirective && this.state.containsOctal && !octalPosition) {
      octalPosition = this.state.octalPosition;
    }

    const stmt = this.parseStatement(null, topLevel);

    if (directives && !parsedNonDirective && this.isValidDirective(stmt)) {
      const directive = this.stmtToDirective(stmt);
      directives.push(directive);

      if (oldStrict === undefined && directive.value.value === "use strict") {
        oldStrict = this.state.strict;
        this.setStrict(true);

        if (octalPosition) {
          this.raise(octalPosition, "Octal literal in strict mode");
        }
      }

      continue;
    }

    parsedNonDirective = true;
    body.push(stmt);
  }

  if (oldStrict === false) {
    this.setStrict(false);
  }
}

parseFor(node, init) {
  node.init = init;
  this.expect(types.semi);
  node.test = this.match(types.semi) ? null : this.parseExpression();
  this.expect(types.semi);
  node.update = this.match(types.parenR) ? null : this.parseExpression();
  this.expect(types.parenR);
  node.body = this.withTopicForbiddingContext(() => this.parseStatement("for"));
  this.scope.exit();
  this.state.labels.pop();
  return this.finishNode(node, "ForStatement");
}

parseForIn(node, init, awaitAt) {
  const isForIn = this.match(types._in);
  this.next();

  if (isForIn) {
    if (awaitAt > -1) this.unexpected(awaitAt);
  } else {
    node.await = awaitAt > -1;
  }

  if (init.type === "VariableDeclaration" && init.declarations[0].init != null && (!isForIn || this.state.strict || init.kind !== "var" || init.declarations[0].id.type !== "Identifier")) {
    this.raise(init.start, `${isForIn ? "for-in" : "for-of"} loop variable declaration may not have an initializer`);
  } else if (init.type === "AssignmentPattern") {
    this.raise(init.start, "Invalid left-hand side in for-loop");
  }

  node.left = init;
  node.right = isForIn ? this.parseExpression() : this.parseMaybeAssign();
  this.expect(types.parenR);
  node.body = this.withTopicForbiddingContext(() => this.parseStatement("for"));
  this.scope.exit();
  this.state.labels.pop();
  return this.finishNode(node, isForIn ? "ForInStatement" : "ForOfStatement");
}

parseVar(node, isFor, kind) {
  const declarations = node.declarations = [];
  const isTypescript = this.hasPlugin("typescript");
  node.kind = kind;

  for (;;) {
    const decl = this.startNode();
    this.parseVarId(decl, kind);

    if (this.eat(types.eq)) {
      decl.init = this.parseMaybeAssign(isFor);
    } else {
      if (kind === "const" && !(this.match(types._in) || this.isContextual("of"))) {
        if (!isTypescript) {
          this.unexpected();
        }
      } else if (decl.id.type !== "Identifier" && !(isFor && (this.match(types._in) || this.isContextual("of")))) {
        this.raise(this.state.lastTokEnd, "Complex binding patterns require an initialization value");
      }

      decl.init = null;
    }

    declarations.push(this.finishNode(decl, "VariableDeclarator"));
    if (!this.eat(types.comma)) break;
  }

  return node;
}

parseVarId(decl, kind) {
  decl.id = this.parseBindingAtom();
  this.checkLVal(decl.id, kind === "var" ? BIND_VAR : BIND_LEXICAL, undefined, "variable declaration");
}

parseFunction(node, statement = FUNC_NO_FLAGS, isAsync = false) {
  const isStatement = statement & FUNC_STATEMENT;
  const isHangingStatement = statement & FUNC_HANGING_STATEMENT;
  const requireId = !!isStatement && !(statement & FUNC_NULLABLE_ID);
  this.initFunction(node, isAsync);

  if (this.match(types.star) && isHangingStatement) {
    this.unexpected(this.state.start, "Generators can only be declared at the top level or inside a block");
  }

  node.generator = this.eat(types.star);

  if (isStatement) {
    node.id = this.parseFunctionId(requireId);
  }

  const oldMaybeInArrowParameters = this.state.maybeInArrowParameters;
  const oldInClassProperty = this.state.inClassProperty;
  const oldYieldPos = this.state.yieldPos;
  const oldAwaitPos = this.state.awaitPos;
  this.state.maybeInArrowParameters = false;
  this.state.inClassProperty = false;
  this.state.yieldPos = -1;
  this.state.awaitPos = -1;
  this.scope.enter(functionFlags(node.async, node.generator));

  if (!isStatement) {
    node.id = this.parseFunctionId();
  }

  this.parseFunctionParams(node);
  this.withTopicForbiddingContext(() => {
    this.parseFunctionBodyAndFinish(node, isStatement ? "FunctionDeclaration" : "FunctionExpression");
  });
  this.scope.exit();

  if (isStatement && !isHangingStatement) {
    this.checkFunctionStatementId(node);
  }

  this.state.maybeInArrowParameters = oldMaybeInArrowParameters;
  this.state.inClassProperty = oldInClassProperty;
  this.state.yieldPos = oldYieldPos;
  this.state.awaitPos = oldAwaitPos;
  return node;
}

parseFunctionId(requireId) {
  return requireId || this.match(types.name) ? this.parseIdentifier() : null;
}

parseFunctionParams(node, allowModifiers) {
  const oldInParameters = this.state.inParameters;
  this.state.inParameters = true;
  this.expect(types.parenL);
  node.params = this.parseBindingList(types.parenR, 41, false, allowModifiers);
  this.state.inParameters = oldInParameters;
  this.checkYieldAwaitInDefaultParams();
}

checkFunctionStatementId(node) {
  if (!node.id) return;
  this.checkLVal(node.id, this.state.strict || node.generator || node.async ? this.scope.treatFunctionsAsVar ? BIND_VAR : BIND_LEXICAL : BIND_FUNCTION, null, "function name");
}

parseClass(node, isStatement, optionalId) {
  this.next();
  this.takeDecorators(node);
  const oldStrict = this.state.strict;
  this.state.strict = true;
  this.parseClassId(node, isStatement, optionalId);
  this.parseClassSuper(node);
  node.body = this.parseClassBody(!!node.superClass);
  this.state.strict = oldStrict;
  return this.finishNode(node, isStatement ? "ClassDeclaration" : "ClassExpression");
}

isClassProperty() {
  return this.match(types.eq) || this.match(types.semi) || this.match(types.braceR);
}

isClassMethod() {
  return this.match(types.parenL);
}

isNonstaticConstructor(method) {
  return !method.computed && !method.static && (method.key.name === "constructor" || method.key.value === "constructor");
}

parseClassBody(constructorAllowsSuper) {
  this.state.classLevel++;
  const state = {
    hadConstructor: false
  };
  let decorators = [];
  const classBody = this.startNode();
  classBody.body = [];
  this.expect(types.braceL);
  this.withTopicForbiddingContext(() => {
    while (!this.eat(types.braceR)) {
      if (this.eat(types.semi)) {
        if (decorators.length > 0) {
          this.raise(this.state.lastTokEnd, "Decorators must not be followed by a semicolon");
        }

        continue;
      }

      if (this.match(types.at)) {
        decorators.push(this.parseDecorator());
        continue;
      }

      const member = this.startNode();

      if (decorators.length) {
        member.decorators = decorators;
        this.resetStartLocationFromNode(member, decorators[0]);
        decorators = [];
      }

      this.parseClassMember(classBody, member, state, constructorAllowsSuper);

      if (member.kind === "constructor" && member.decorators && member.decorators.length > 0) {
        this.raise(member.start, "Decorators can't be used with a constructor. Did you mean '@dec class { ... }'?");
      }
    }
  });

  if (decorators.length) {
    this.raise(this.state.start, "You have trailing decorators with no method");
  }

  this.state.classLevel--;
  return this.finishNode(classBody, "ClassBody");
}

parseClassMember(classBody, member, state, constructorAllowsSuper) {
  let isStatic = false;
  const containsEsc = this.state.containsEsc;

  if (this.match(types.name) && this.state.value === "static") {
    const key = this.parseIdentifier(true);

    if (this.isClassMethod()) {
      const method = member;
      method.kind = "method";
      method.computed = false;
      method.key = key;
      method.static = false;
      this.pushClassMethod(classBody, method, false, false, false, false);
      return;
    } else if (this.isClassProperty()) {
      const prop = member;
      prop.computed = false;
      prop.key = key;
      prop.static = false;
      classBody.body.push(this.parseClassProperty(prop));
      return;
    } else if (containsEsc) {
      throw this.unexpected();
    }

    isStatic = true;
  }

  this.parseClassMemberWithIsStatic(classBody, member, state, isStatic, constructorAllowsSuper);
}

parseClassMemberWithIsStatic(classBody, member, state, isStatic, constructorAllowsSuper) {
  const publicMethod = member;
  const privateMethod = member;
  const publicProp = member;
  const privateProp = member;
  const method = publicMethod;
  const publicMember = publicMethod;
  member.static = isStatic;

  if (this.eat(types.star)) {
    method.kind = "method";
    this.parseClassPropertyName(method);

    if (method.key.type === "PrivateName") {
      this.pushClassPrivateMethod(classBody, privateMethod, true, false);
      return;
    }

    if (this.isNonstaticConstructor(publicMethod)) {
      this.raise(publicMethod.key.start, "Constructor can't be a generator");
    }

    this.pushClassMethod(classBody, publicMethod, true, false, false, false);
    return;
  }

  const containsEsc = this.state.containsEsc;
  const key = this.parseClassPropertyName(member);
  const isPrivate = key.type === "PrivateName";
  const isSimple = key.type === "Identifier";
  this.parsePostMemberNameModifiers(publicMember);

  if (this.isClassMethod()) {
    method.kind = "method";

    if (isPrivate) {
      this.pushClassPrivateMethod(classBody, privateMethod, false, false);
      return;
    }

    const isConstructor = this.isNonstaticConstructor(publicMethod);
    let allowsDirectSuper = false;

    if (isConstructor) {
      publicMethod.kind = "constructor";

      if (publicMethod.decorators) {
        this.raise(publicMethod.start, "You can't attach decorators to a class constructor");
      }

      if (state.hadConstructor && !this.hasPlugin("typescript")) {
        this.raise(key.start, "Duplicate constructor in the same class");
      }

      state.hadConstructor = true;
      allowsDirectSuper = constructorAllowsSuper;
    }

    this.pushClassMethod(classBody, publicMethod, false, false, isConstructor, allowsDirectSuper);
  } else if (this.isClassProperty()) {
    if (isPrivate) {
      this.pushClassPrivateProperty(classBody, privateProp);
    } else {
      this.pushClassProperty(classBody, publicProp);
    }
  } else if (isSimple && key.name === "async" && !containsEsc && !this.isLineTerminator()) {
    const isGenerator = this.eat(types.star);
    method.kind = "method";
    this.parseClassPropertyName(method);

    if (method.key.type === "PrivateName") {
      this.pushClassPrivateMethod(classBody, privateMethod, isGenerator, true);
    } else {
      if (this.isNonstaticConstructor(publicMethod)) {
        this.raise(publicMethod.key.start, "Constructor can't be an async function");
      }

      this.pushClassMethod(classBody, publicMethod, isGenerator, true, false, false);
    }
  } else if (isSimple && (key.name === "get" || key.name === "set") && !containsEsc && !(this.match(types.star) && this.isLineTerminator())) {
    method.kind = key.name;
    this.parseClassPropertyName(publicMethod);

    if (method.key.type === "PrivateName") {
      this.pushClassPrivateMethod(classBody, privateMethod, false, false);
    } else {
      if (this.isNonstaticConstructor(publicMethod)) {
        this.raise(publicMethod.key.start, "Constructor can't have get/set modifier");
      }

      this.pushClassMethod(classBody, publicMethod, false, false, false, false);
    }

    this.checkGetterSetterParams(publicMethod);
  } else if (this.isLineTerminator()) {
    if (isPrivate) {
      this.pushClassPrivateProperty(classBody, privateProp);
    } else {
      this.pushClassProperty(classBody, publicProp);
    }
  } else {
    this.unexpected();
  }
}

parseClassPropertyName(member) {
  const key = this.parsePropertyName(member);

  if (!member.computed && member.static && (key.name === "prototype" || key.value === "prototype")) {
    this.raise(key.start, "Classes may not have static property named prototype");
  }

  if (key.type === "PrivateName" && key.id.name === "constructor") {
    this.raise(key.start, "Classes may not have a private field named '#constructor'");
  }

  return key;
}

pushClassProperty(classBody, prop) {
  if (!prop.computed && (prop.key.name === "constructor" || prop.key.value === "constructor")) {
    this.raise(prop.key.start, "Classes may not have a field named 'constructor'");
  }

  classBody.body.push(this.parseClassProperty(prop));
}

pushClassPrivateProperty(classBody, prop) {
  this.expectPlugin("classPrivateProperties", prop.key.start);
  classBody.body.push(this.parseClassPrivateProperty(prop));
}

pushClassMethod(classBody, method, isGenerator, isAsync, isConstructor, allowsDirectSuper) {
  classBody.body.push(this.parseMethod(method, isGenerator, isAsync, isConstructor, allowsDirectSuper, "ClassMethod", true));
}

pushClassPrivateMethod(classBody, method, isGenerator, isAsync) {
  this.expectPlugin("classPrivateMethods", method.key.start);
  classBody.body.push(this.parseMethod(method, isGenerator, isAsync, false, false, "ClassPrivateMethod", true));
}

parsePostMemberNameModifiers(methodOrProp) {}

parseAccessModifier() {
  return undefined;
}

parseClassPrivateProperty(node) {
  this.state.inClassProperty = true;
  this.scope.enter(SCOPE_CLASS | SCOPE_SUPER);
  node.value = this.eat(types.eq) ? this.parseMaybeAssign() : null;
  this.semicolon();
  this.state.inClassProperty = false;
  this.scope.exit();
  return this.finishNode(node, "ClassPrivateProperty");
}

parseClassProperty(node) {
  if (!node.typeAnnotation) {
    this.expectPlugin("classProperties");
  }

  this.state.inClassProperty = true;
  this.scope.enter(SCOPE_CLASS | SCOPE_SUPER);

  if (this.match(types.eq)) {
    this.expectPlugin("classProperties");
    this.next();
    node.value = this.parseMaybeAssign();
  } else {
    node.value = null;
  }

  this.semicolon();
  this.state.inClassProperty = false;
  this.scope.exit();
  return this.finishNode(node, "ClassProperty");
}

parseClassId(node, isStatement, optionalId, bindingType = BIND_CLASS) {
  if (this.match(types.name)) {
    node.id = this.parseIdentifier();

    if (isStatement) {
      this.checkLVal(node.id, bindingType, undefined, "class name");
    }
  } else {
    if (optionalId || !isStatement) {
      node.id = null;
    } else {
      this.unexpected(null, "A class name is required");
    }
  }
}

parseClassSuper(node) {
  node.superClass = this.eat(types._extends) ? this.parseExprSubscripts() : null;
}

parseExport(node) {
  const hasDefault = this.maybeParseExportDefaultSpecifier(node);
  const parseAfterDefault = !hasDefault || this.eat(types.comma);
  const hasStar = parseAfterDefault && this.eatExportStar(node);
  const hasNamespace = hasStar && this.maybeParseExportNamespaceSpecifier(node);
  const parseAfterNamespace = parseAfterDefault && (!hasNamespace || this.eat(types.comma));
  const isFromRequired = hasDefault || hasStar;

  if (hasStar && !hasNamespace) {
    if (hasDefault) this.unexpected();
    this.parseExportFrom(node, true);
    return this.finishNode(node, "ExportAllDeclaration");
  }

  const hasSpecifiers = this.maybeParseExportNamedSpecifiers(node);

  if (hasDefault && parseAfterDefault && !hasStar && !hasSpecifiers || hasNamespace && parseAfterNamespace && !hasSpecifiers) {
    throw this.unexpected(null, types.braceL);
  }

  let hasDeclaration;

  if (isFromRequired || hasSpecifiers) {
    hasDeclaration = false;
    this.parseExportFrom(node, isFromRequired);
  } else {
    hasDeclaration = this.maybeParseExportDeclaration(node);
  }

  if (isFromRequired || hasSpecifiers || hasDeclaration) {
    this.checkExport(node, true, false, !!node.source);
    return this.finishNode(node, "ExportNamedDeclaration");
  }

  if (this.eat(types._default)) {
    node.declaration = this.parseExportDefaultExpression();
    this.checkExport(node, true, true);
    return this.finishNode(node, "ExportDefaultDeclaration");
  }

  throw this.unexpected(null, types.braceL);
}

eatExportStar(node) {
  return this.eat(types.star);
}

maybeParseExportDefaultSpecifier(node) {
  if (this.isExportDefaultSpecifier()) {
    this.expectPlugin("exportDefaultFrom");
    const specifier = this.startNode();
    specifier.exported = this.parseIdentifier(true);
    node.specifiers = [this.finishNode(specifier, "ExportDefaultSpecifier")];
    return true;
  }

  return false;
}

maybeParseExportNamespaceSpecifier(node) {
  if (this.isContextual("as")) {
    if (!node.specifiers) node.specifiers = [];
    this.expectPlugin("exportNamespaceFrom");
    const specifier = this.startNodeAt(this.state.lastTokStart, this.state.lastTokStartLoc);
    this.next();
    specifier.exported = this.parseIdentifier(true);
    node.specifiers.push(this.finishNode(specifier, "ExportNamespaceSpecifier"));
    return true;
  }

  return false;
}

maybeParseExportNamedSpecifiers(node) {
  if (this.match(types.braceL)) {
    if (!node.specifiers) node.specifiers = [];
    node.specifiers.push(...this.parseExportSpecifiers());
    node.source = null;
    node.declaration = null;
    return true;
  }

  return false;
}

maybeParseExportDeclaration(node) {
  if (this.shouldParseExportDeclaration()) {
    if (this.isContextual("async")) {
      const next = this.nextTokenStart();

      if (!this.isUnparsedContextual(next, "function")) {
        this.unexpected(next, `Unexpected token, expected "function"`);
      }
    }

    node.specifiers = [];
    node.source = null;
    node.declaration = this.parseExportDeclaration(node);
    return true;
  }

  return false;
}

isAsyncFunction() {
  if (!this.isContextual("async")) return false;
  const next = this.nextTokenStart();
  return !lineBreak.test(this.input.slice(this.state.pos, next)) && this.isUnparsedContextual(next, "function");
}

parseExportDefaultExpression() {
  const expr = this.startNode();
  const isAsync = this.isAsyncFunction();

  if (this.match(types._function) || isAsync) {
    this.next();

    if (isAsync) {
      this.next();
    }

    return this.parseFunction(expr, FUNC_STATEMENT | FUNC_NULLABLE_ID, isAsync);
  } else if (this.match(types._class)) {
    return this.parseClass(expr, true, true);
  } else if (this.match(types.at)) {
    if (this.hasPlugin("decorators") && this.getPluginOption("decorators", "decoratorsBeforeExport")) {
      this.unexpected(this.state.start, "Decorators must be placed *before* the 'export' keyword." + " You can set the 'decoratorsBeforeExport' option to false to use" + " the 'export @decorator class {}' syntax");
    }

    this.parseDecorators(false);
    return this.parseClass(expr, true, true);
  } else if (this.match(types._const) || this.match(types._var) || this.isLet()) {
    return this.raise(this.state.start, "Only expressions, functions or classes are allowed as the `default` export.");
  } else {
    const res = this.parseMaybeAssign();
    this.semicolon();
    return res;
  }
}

parseExportDeclaration(node) {
  return this.parseStatement(null);
}

isExportDefaultSpecifier() {
  if (this.match(types.name)) {
    return this.state.value !== "async" && this.state.value !== "let";
  }

  if (!this.match(types._default)) {
    return false;
  }

  const next = this.nextTokenStart();
  return this.input.charCodeAt(next) === 44 || this.isUnparsedContextual(next, "from");
}

parseExportFrom(node, expect) {
  if (this.eatContextual("from")) {
    node.source = this.parseImportSource();
    this.checkExport(node);
  } else {
    if (expect) {
      this.unexpected();
    } else {
      node.source = null;
    }
  }

  this.semicolon();
}

shouldParseExportDeclaration() {
  if (this.match(types.at)) {
    this.expectOnePlugin(["decorators", "decorators-legacy"]);

    if (this.hasPlugin("decorators")) {
      if (this.getPluginOption("decorators", "decoratorsBeforeExport")) {
        this.unexpected(this.state.start, "Decorators must be placed *before* the 'export' keyword." + " You can set the 'decoratorsBeforeExport' option to false to use" + " the 'export @decorator class {}' syntax");
      } else {
        return true;
      }
    }
  }

  return this.state.type.keyword === "var" || this.state.type.keyword === "const" || this.state.type.keyword === "function" || this.state.type.keyword === "class" || this.isLet() || this.isAsyncFunction();
}

checkExport(node, checkNames, isDefault, isFrom) {
  if (checkNames) {
    if (isDefault) {
      this.checkDuplicateExports(node, "default");
    } else if (node.specifiers && node.specifiers.length) {
      for (let _i3 = 0, _node$specifiers = node.specifiers; _i3 < _node$specifiers.length; _i3++) {
        const specifier = _node$specifiers[_i3];
        this.checkDuplicateExports(specifier, specifier.exported.name);

        if (!isFrom && specifier.local) {
          this.checkReservedWord(specifier.local.name, specifier.local.start, true, false);
          this.scope.checkLocalExport(specifier.local);
        }
      }
    } else if (node.declaration) {
      if (node.declaration.type === "FunctionDeclaration" || node.declaration.type === "ClassDeclaration") {
        const id = node.declaration.id;
        if (!id) throw new Error("Assertion failure");
        this.checkDuplicateExports(node, id.name);
      } else if (node.declaration.type === "VariableDeclaration") {
        for (let _i4 = 0, _node$declaration$dec = node.declaration.declarations; _i4 < _node$declaration$dec.length; _i4++) {
          const declaration = _node$declaration$dec[_i4];
          this.checkDeclaration(declaration.id);
        }
      }
    }
  }

  const currentContextDecorators = this.state.decoratorStack[this.state.decoratorStack.length - 1];

  if (currentContextDecorators.length) {
    const isClass = node.declaration && (node.declaration.type === "ClassDeclaration" || node.declaration.type === "ClassExpression");

    if (!node.declaration || !isClass) {
      throw this.raise(node.start, "You can only use decorators on an export when exporting a class");
    }

    this.takeDecorators(node.declaration);
  }
}

checkDeclaration(node) {
  if (node.type === "Identifier") {
    this.checkDuplicateExports(node, node.name);
  } else if (node.type === "ObjectPattern") {
    for (let _i5 = 0, _node$properties = node.properties; _i5 < _node$properties.length; _i5++) {
      const prop = _node$properties[_i5];
      this.checkDeclaration(prop);
    }
  } else if (node.type === "ArrayPattern") {
    for (let _i6 = 0, _node$elements = node.elements; _i6 < _node$elements.length; _i6++) {
      const elem = _node$elements[_i6];

      if (elem) {
        this.checkDeclaration(elem);
      }
    }
  } else if (node.type === "ObjectProperty") {
    this.checkDeclaration(node.value);
  } else if (node.type === "RestElement") {
    this.checkDeclaration(node.argument);
  } else if (node.type === "AssignmentPattern") {
    this.checkDeclaration(node.left);
  }
}

checkDuplicateExports(node, name) {
  if (this.state.exportedIdentifiers.indexOf(name) > -1) {
    throw this.raise(node.start, name === "default" ? "Only one default export allowed per module." : `\`${name}\` has already been exported. Exported identifiers must be unique.`);
  }

  this.state.exportedIdentifiers.push(name);
}

parseExportSpecifiers() {
  const nodes = [];
  let first = true;
  this.expect(types.braceL);

  while (!this.eat(types.braceR)) {
    if (first) {
      first = false;
    } else {
      this.expect(types.comma);
      if (this.eat(types.braceR)) break;
    }

    const node = this.startNode();
    node.local = this.parseIdentifier(true);
    node.exported = this.eatContextual("as") ? this.parseIdentifier(true) : node.local.__clone();
    nodes.push(this.finishNode(node, "ExportSpecifier"));
  }

  return nodes;
}

parseImport(node) {
  node.specifiers = [];

  if (!this.match(types.string)) {
    const hasDefault = this.maybeParseDefaultImportSpecifier(node);
    const parseNext = !hasDefault || this.eat(types.comma);
    const hasStar = parseNext && this.maybeParseStarImportSpecifier(node);
    if (parseNext && !hasStar) this.parseNamedImportSpecifiers(node);
    this.expectContextual("from");
  }

  node.source = this.parseImportSource();
  this.semicolon();
  return this.finishNode(node, "ImportDeclaration");
}

parseImportSource() {
  if (!this.match(types.string)) this.unexpected();
  return this.parseExprAtom();
}

shouldParseDefaultImport(node) {
  return this.match(types.name);
}

parseImportSpecifierLocal(node, specifier, type, contextDescription) {
  specifier.local = this.parseIdentifier();
  this.checkLVal(specifier.local, BIND_LEXICAL, undefined, contextDescription);
  node.specifiers.push(this.finishNode(specifier, type));
}

maybeParseDefaultImportSpecifier(node) {
  if (this.shouldParseDefaultImport(node)) {
    this.parseImportSpecifierLocal(node, this.startNode(), "ImportDefaultSpecifier", "default import specifier");
    return true;
  }

  return false;
}

maybeParseStarImportSpecifier(node) {
  if (this.match(types.star)) {
    const specifier = this.startNode();
    this.next();
    this.expectContextual("as");
    this.parseImportSpecifierLocal(node, specifier, "ImportNamespaceSpecifier", "import namespace specifier");
    return true;
  }

  return false;
}

parseNamedImportSpecifiers(node) {
  let first = true;
  this.expect(types.braceL);

  while (!this.eat(types.braceR)) {
    if (first) {
      first = false;
    } else {
      if (this.eat(types.colon)) {
        this.unexpected(null, "ES2015 named imports do not destructure. " + "Use another statement for destructuring after the import.");
      }

      this.expect(types.comma);
      if (this.eat(types.braceR)) break;
    }

    this.parseImportSpecifier(node);
  }
}

parseImportSpecifier(node) {
  const specifier = this.startNode();
  specifier.imported = this.parseIdentifier(true);

  if (this.eatContextual("as")) {
    specifier.local = this.parseIdentifier();
  } else {
    this.checkReservedWord(specifier.imported.name, specifier.start, true, true);
    specifier.local = specifier.imported.__clone();
  }

  this.checkLVal(specifier.local, BIND_LEXICAL, undefined, "import specifier");
  node.specifiers.push(this.finishNode(specifier, "ImportSpecifier"));
}

}

class Parser extends StatementParser {

constructor(options, input) {
  options = getOptions(options);
  super(options, input);
  const ScopeHandler = this.getScopeHandler();
  this.options = options;
  this.inModule = this.options.sourceType === "module";
  this.scope = new ScopeHandler(this.raise.bind(this), this.inModule);
  this.plugins = pluginsMap(this.options.plugins);
  this.filename = options.sourceFilename;
}

getScopeHandler() {
  return ScopeHandler;
}

parse() {
  this.scope.enter(SCOPE_PROGRAM);
  const file = this.startNode();
  const program = this.startNode();
  this.nextToken();
  return this.parseTopLevel(file, program);
}

}

function pluginsMap(plugins) {

const pluginMap = new Map();

for (let _i = 0; _i < plugins.length; _i++) {
  const plugin = plugins[_i];
  const [name, options] = Array.isArray(plugin) ? plugin : [plugin, {}];
  if (!pluginMap.has(name)) pluginMap.set(name, options || {});
}

return pluginMap;

}

function parse(input, options) {

if (options && options.sourceType === "unambiguous") {
  options = Object.assign({}, options);

  try {
    options.sourceType = "module";
    const parser = getParser(options, input);
    const ast = parser.parse();
    if (!parser.sawUnambiguousESM) ast.program.sourceType = "script";
    return ast;
  } catch (moduleError) {
    try {
      options.sourceType = "script";
      return getParser(options, input).parse();
    } catch (scriptError) {}

    throw moduleError;
  }
} else {
  return getParser(options, input).parse();
}

} function parseExpression(input, options) {

const parser = getParser(options, input);

if (parser.options.strictMode) {
  parser.state.strict = true;
}

return parser.getExpression();

}

function getParser(options, input) {

let cls = Parser;

if (options && options.plugins) {
  validatePlugins(options.plugins);
  cls = getParserClass(options.plugins);
}

return new cls(options, input);

}

const parserClassCache = {};

function getParserClass(pluginsFromOptions) {

const pluginList = mixinPluginNames.filter(name => hasPlugin(pluginsFromOptions, name));
const key = pluginList.join("/");
let cls = parserClassCache[key];

if (!cls) {
  cls = Parser;

  for (let _i = 0; _i < pluginList.length; _i++) {
    const plugin = pluginList[_i];
    cls = mixinPlugins[plugin](cls);
  }

  parserClassCache[key] = cls;
}

return cls;

}

exports.parse = parse; exports.parseExpression = parseExpression; exports.tokTypes = types;