     1→import { Errors } from './errors';
     2→import { nextToken } from './lexer/scan';
     3→import { type Parser } from './parser/parser';
     4→import { KeywordDescTable, Token } from './token';
     5→
     6→/**
     7→ * The core context, passed around everywhere as a simple immutable bit set
     8→ */
     9→export const enum Context {
    10→  None = 0,
    11→  Strict = 1 << 0,
    12→  Module = 1 << 1, // Current code should be parsed as a module body
    13→  InSwitch = 1 << 2,
    14→  InGlobal = 1 << 3,
    15→  InClass = 1 << 4,
    16→  AllowRegExp = 1 << 5,
    17→  TaggedTemplate = 1 << 6,
    18→  InIteration = 1 << 7,
    19→  SuperProperty = 1 << 8,
    20→  SuperCall = 1 << 9,
    21→  InYieldContext = 1 << 10,
    22→  InAwaitContext = 1 << 11,
    23→  InReturnContext = 1 << 12,
    24→  InArgumentList = 1 << 13,
    25→  InConstructor = 1 << 14,
    26→  InMethodOrFunction = 1 << 15,
    27→  AllowNewTarget = 1 << 16,
    28→  DisallowIn = 1 << 17,
    29→  AllowEscapedKeyword = 1 << 18,
    30→  InStaticBlock = 1 << 19,
    31→}
    32→
    33→/**
    34→ * Masks to track the property kind
    35→ */
    36→export const enum PropertyKind {
    37→  None = 0,
    38→  Method = 1 << 0,
    39→  Computed = 1 << 1,
    40→  Shorthand = 1 << 2,
    41→  Generator = 1 << 3,
    42→  Async = 1 << 4,
    43→  Static = 1 << 5,
    44→  Constructor = 1 << 6,
    45→  ClassField = 1 << 7,
    46→  Getter = 1 << 8,
    47→  Setter = 1 << 9,
    48→  Accessor = 1 << 10,
    49→  Extends = 1 << 11,
    50→  Literal = 1 << 12,
    51→  PrivateField = 1 << 13,
    52→  GetSet = Getter | Setter,
    53→}
    54→
    55→/**
    56→ * Masks to track the binding kind
    57→ */
    58→export const enum BindingKind {
    59→  None = 0,
    60→  ArgumentList = 1 << 0,
    61→  Empty = 1 << 1,
    62→  Variable = 1 << 2,
    63→  Let = 1 << 3,
    64→  Const = 1 << 4,
    65→  Class = 1 << 5,
    66→  FunctionLexical = 1 << 6,
    67→  FunctionStatement = 1 << 7,
    68→  CatchPattern = 1 << 8,
    69→  CatchIdentifier = 1 << 9,
    70→  Async = 1 << 10,
    71→  Generator = 1 << 10,
    72→  AsyncFunctionLexical = Async | FunctionLexical,
    73→  GeneratorFunctionLexical = Generator | FunctionLexical,
    74→  AsyncGeneratorFunctionLexical = Async | Generator | FunctionLexical,
    75→  CatchIdentifierOrPattern = CatchIdentifier | CatchPattern,
    76→  LexicalOrFunction = Variable | FunctionLexical,
    77→  LexicalBinding = Let | Const | FunctionLexical | FunctionStatement | Class,
    78→}
    79→
    80→/**
    81→ * The masks to track where something begins. E.g. statements, declarations or arrows.
    82→ */
    83→export const enum Origin {
    84→  None = 0,
    85→  Statement = 1 << 0,
    86→  BlockStatement = 1 << 1,
    87→  TopLevel = 1 << 2,
    88→  Declaration = 1 << 3,
    89→  Arrow = 1 << 4,
    90→  ForStatement = 1 << 5,
    91→  Export = 1 << 6,
    92→}
    93→
    94→/**
    95→ * Masks to track the assignment kind
    96→ */
    97→export const enum AssignmentKind {
    98→  None = 0,
    99→  Assignable = 1 << 0,
   100→  CannotAssign = 1 << 1,
   101→}
   102→
   103→/**
   104→ * Masks to track the destructuring kind
   105→ */
   106→export const enum DestructuringKind {
   107→  None = 0,
   108→  HasToDestruct = 1 << 3,
   109→  // "Cannot" rather than "can" so that this flag can be ORed together across
   110→  // multiple characters.
   111→  CannotDestruct = 1 << 4,
   112→  // Only destructible if assignable
   113→  Assignable = 1 << 5,
   114→  // `__proto__` is a special case and only valid to parse if destructible
   115→  SeenProto = 1 << 6,
   116→  Await = 1 << 7,
   117→  Yield = 1 << 8,
   118→}
   119→
   120→/**
   121→ * The mutable parser flags, in case any flags need passed by reference.
   122→ */
   123→export const enum Flags {
   124→  None = 0,
   125→  NewLine = 1 << 0,
   126→  HasConstructor = 1 << 5,
   127→  Octal = 1 << 6,
   128→  NonSimpleParameterList = 1 << 7,
   129→  HasStrictReserved = 1 << 8,
   130→  StrictEvalArguments = 1 << 9,
   131→  DisallowCall = 1 << 10,
   132→  HasOptionalChaining = 1 << 11,
   133→  EightAndNine = 1 << 12,
   134→}
   135→
   136→export const enum HoistedClassFlags {
   137→  None,
   138→  Hoisted = 1 << 0,
   139→  Export = 1 << 1,
   140→}
   141→
   142→export const enum HoistedFunctionFlags {
   143→  None,
   144→  Hoisted = 1 << 0,
   145→  Export = 1 << 1,
   146→}
   147→
   148→/**
   149→ * Check for automatic semicolon insertion according to the rules
   150→ * given in `ECMA-262, section 11.9`.
   151→ *
   152→ * @param parser Parser object
   153→ * @param context Context masks
   154→ */
   155→
   156→export function matchOrInsertSemicolon(parser: Parser, context: Context): void {
   157→  if ((parser.flags & Flags.NewLine) === 0 && (parser.getToken() & Token.IsAutoSemicolon) !== Token.IsAutoSemicolon) {
   158→    parser.report(Errors.UnexpectedToken, KeywordDescTable[parser.getToken() & Token.Type]);
   159→  }
   160→
   161→  if (!consumeOpt(parser, context, Token.Semicolon)) {
   162→    // Automatic semicolon insertion has occurred
   163→    parser.options.onInsertedSemicolon?.(parser.startIndex);
   164→  }
   165→}
   166→
   167→export function isValidStrictMode(parser: Parser, index: number, tokenIndex: number, tokenValue: string): 0 | 1 {
   168→  if (index - tokenIndex < 13 && tokenValue === 'use strict') {
   169→    if ((parser.getToken() & Token.IsAutoSemicolon) === Token.IsAutoSemicolon || parser.flags & Flags.NewLine) {
   170→      return 1;
   171→    }
   172→  }
   173→  return 0;
   174→}
   175→
   176→/**
   177→ * Consumes the current token if the current token kind is
   178→ * the specified `kind` and returns `0`. Otherwise returns `1`.
   179→ *
   180→ * @param parser Parser state
   181→ * @param context Context masks
   182→ * @param token The type of token to consume
   183→ */
   184→export function optionalBit(parser: Parser, context: Context, t: Token): 0 | 1 {
   185→  if (parser.getToken() !== t) return 0;
   186→  nextToken(parser, context);
   187→  return 1;
   188→}
   189→
   190→/** Consumes the current token if the current token kind is
   191→ * the specified `kind` and returns `true`. Otherwise returns
   192→ * `false`.
   193→ *
   194→ * @param parser Parser state
   195→ * @param context Context masks
   196→ * @param token The type of token to consume
   197→ */
   198→export function consumeOpt(parser: Parser, context: Context, t: Token): boolean {
   199→  if (parser.getToken() !== t) return false;
   200→  nextToken(parser, context);
   201→  return true;
   202→}
   203→
   204→/**
   205→ * Consumes the current token. If the current token kind is not
   206→ * the specified `kind`, an error will be reported.
   207→ *
   208→ * @param parser Parser state
   209→ * @param context Context masks
   210→ * @param t The type of token to consume
   211→ */
   212→export function consume(parser: Parser, context: Context, t: Token): void {
   213→  if (parser.getToken() !== t) parser.report(Errors.ExpectedToken, KeywordDescTable[t & Token.Type]);
   214→  nextToken(parser, context);
   215→}
   216→
   217→/**
   218→ * Transforms a `LeftHandSideExpression` into a `AssignmentPattern` if possible,
   219→ * otherwise it returns the original tree.
   220→ *
   221→ * @param parser Parser state
   222→ * @param {*} node
   223→ */
   224→export function reinterpretToPattern(parser: Parser, node: any): void {
   225→  switch (node.type) {
   226→    case 'ArrayExpression': {
   227→      node.type = 'ArrayPattern';
   228→      const { elements } = node;
   229→      for (let i = 0, n = elements.length; i < n; ++i) {
   230→        const element = elements[i];
   231→        if (element) reinterpretToPattern(parser, element);
   232→      }
   233→      return;
   234→    }
   235→    case 'ObjectExpression': {
   236→      node.type = 'ObjectPattern';
   237→      const { properties } = node;
   238→      for (let i = 0, n = properties.length; i < n; ++i) {
   239→        reinterpretToPattern(parser, properties[i]);
   240→      }
   241→      return;
   242→    }
   243→    case 'AssignmentExpression':
   244→      node.type = 'AssignmentPattern';
   245→      if (node.operator !== '=') parser.report(Errors.InvalidDestructuringTarget);
   246→      delete node.operator;
   247→      reinterpretToPattern(parser, node.left);
   248→      return;
   249→    case 'Property':
   250→      reinterpretToPattern(parser, node.value);
   251→      return;
   252→    case 'SpreadElement':
   253→      node.type = 'RestElement';
   254→      reinterpretToPattern(parser, node.argument);
   255→    // No default
   256→  }
   257→}
   258→
   259→/**
   260→ * Validates binding identifier
   261→ *
   262→ * @param parser Parser state
   263→ * @param context Context masks
   264→ * @param type Binding type
   265→ * @param token Token
   266→ */
   267→
   268→export function validateBindingIdentifier(
   269→  parser: Parser,
   270→  context: Context,
   271→  kind: BindingKind,
   272→  t: Token,
   273→  skipEvalArgCheck: 0 | 1,
   274→): void {
   275→  if (context & Context.Strict) {
   276→    if ((t & Token.FutureReserved) === Token.FutureReserved) {
   277→      parser.report(Errors.UnexpectedStrictReserved);
   278→    }
   279→
   280→    if (!skipEvalArgCheck && (t & Token.IsEvalOrArguments) === Token.IsEvalOrArguments) {
   281→      parser.report(Errors.StrictEvalArguments);
   282→    }
   283→  }
   284→
   285→  if ((t & Token.Reserved) === Token.Reserved || t === Token.EscapedReserved) {
   286→    parser.report(Errors.KeywordNotId);
   287→  }
   288→
   289→  // The BoundNames of LexicalDeclaration and ForDeclaration must not
   290→  // contain 'let'. (CatchParameter is the only lexical binding form
   291→  // without this restriction.)
   292→  if (kind & (BindingKind.Let | BindingKind.Const) && (t & Token.Type) === (Token.LetKeyword & Token.Type)) {
   293→    parser.report(Errors.InvalidLetConstBinding);
   294→  }
   295→
   296→  if (context & (Context.InAwaitContext | Context.Module) && t === Token.AwaitKeyword) {
   297→    parser.report(Errors.AwaitIdentInModuleOrAsyncFunc);
   298→  }
   299→
   300→  if (context & (Context.InYieldContext | Context.Strict) && t === Token.YieldKeyword) {
   301→    parser.report(Errors.DisallowedInContext, 'yield');
   302→  }
   303→}
   304→
   305→export function validateFunctionName(parser: Parser, context: Context, t: Token): void {
   306→  if (context & Context.Strict) {
   307→    if ((t & Token.FutureReserved) === Token.FutureReserved) {
   308→      parser.report(Errors.UnexpectedStrictReserved);
   309→    }
   310→
   311→    if ((t & Token.IsEvalOrArguments) === Token.IsEvalOrArguments) {
   312→      parser.report(Errors.StrictEvalArguments);
   313→    }
   314→
   315→    if (t === Token.EscapedFutureReserved) {
   316→      parser.report(Errors.InvalidEscapedKeyword);
   317→    }
   318→
   319→    if (t === Token.EscapedReserved) {
   320→      parser.report(Errors.InvalidEscapedKeyword);
   321→    }
   322→  }
   323→
   324→  if ((t & Token.Reserved) === Token.Reserved) {
   325→    parser.report(Errors.KeywordNotId);
   326→  }
   327→
   328→  if (context & (Context.InAwaitContext | Context.Module) && t === Token.AwaitKeyword) {
   329→    parser.report(Errors.AwaitIdentInModuleOrAsyncFunc);
   330→  }
   331→
   332→  if (context & (Context.InYieldContext | Context.Strict) && t === Token.YieldKeyword) {
   333→    parser.report(Errors.DisallowedInContext, 'yield');
   334→  }
   335→}
   336→
   337→/**
   338→ * Validates binding identifier
   339→ *
   340→ * @param parser Parser state
   341→ * @param context Context masks
   342→ * @param t Token
   343→ */
   344→
   345→export function isStrictReservedWord(parser: Parser, context: Context, t: Token): boolean {
   346→  if (t === Token.AwaitKeyword) {
   347→    if (context & (Context.InAwaitContext | Context.Module)) parser.report(Errors.AwaitIdentInModuleOrAsyncFunc);
   348→    parser.destructible |= DestructuringKind.Await;
   349→  }
   350→
   351→  if (t === Token.YieldKeyword && context & Context.InYieldContext) parser.report(Errors.DisallowedInContext, 'yield');
   352→
   353→  return (
   354→    (t & Token.Reserved) === Token.Reserved ||
   355→    (t & Token.FutureReserved) === Token.FutureReserved ||
   356→    t == Token.EscapedFutureReserved
   357→  );
   358→}
   359→
   360→/**
   361→ * Checks if the property has any private field key
   362→ *
   363→ * @param parser Parser object
   364→ * @param context  Context masks
   365→ */
   366→export function isPropertyWithPrivateFieldKey(expr: any): boolean {
   367→  return !expr.property ? false : expr.property.type === 'PrivateIdentifier';
   368→}
   369→
   370→/**
   371→ * Checks if a label in `LabelledStatement` are valid or not
   372→ *
   373→ * @param parser Parser state
   374→ * @param labels Object holding the labels
   375→ * @param name Current label
   376→ * @param isIterationStatement
   377→ */
   378→export function isValidLabel(parser: Parser, labels: any, name: string, isIterationStatement: 0 | 1): 0 | 1 {
   379→  while (labels) {
   380→    if (labels['$' + name]) {
   381→      if (isIterationStatement) parser.report(Errors.InvalidNestedStatement);
   382→      return 1;
   383→    }
   384→    if (isIterationStatement && labels.loop) isIterationStatement = 0;
   385→    labels = labels['$'];
   386→  }
   387→
   388→  return 0;
   389→}
   390→
   391→/**
   392→ * Checks if current label already have been declared, and if not
   393→ * declare it
   394→ *
   395→ * @param parser Parser state
   396→ * @param labels Object holding the labels
   397→ * @param name Current label
   398→ */
   399→export function validateAndDeclareLabel(parser: Parser, labels: any, name: string): void {
   400→  let set = labels;
   401→  while (set) {
   402→    if (set['$' + name]) parser.report(Errors.LabelRedeclaration, name);
   403→    set = set['$'];
   404→  }
   405→
   406→  labels['$' + name] = 1;
   407→}
   408→
   409→/** @internal */
   410→export function isEqualTagName(elementName: any): any {
   411→  switch (elementName.type) {
   412→    case 'JSXIdentifier':
   413→      return elementName.name;
   414→    case 'JSXNamespacedName':
   415→      return elementName.namespace + ':' + elementName.name;
   416→    case 'JSXMemberExpression':
   417→      return isEqualTagName(elementName.object) + '.' + isEqualTagName(elementName.property);
   418→    /* istanbul ignore next */
   419→    default:
   420→    // ignore
   421→  }
   422→}
   423→
   424→export function isValidIdentifier(context: Context, t: Token): boolean {
   425→  if (context & (Context.Strict | Context.InYieldContext)) {
   426→    // Module code is also "strict mode code"
   427→    if (context & Context.Module && t === Token.AwaitKeyword) return false;
   428→    if (context & Context.InYieldContext && t === Token.YieldKeyword) return false;
   429→    return (t & Token.Contextual) === Token.Contextual;
   430→  }
   431→
   432→  return (t & Token.Contextual) === Token.Contextual || (t & Token.FutureReserved) === Token.FutureReserved;
   433→}
   434→
   435→export function classifyIdentifier(parser: Parser, context: Context, t: Token): any {
   436→  if ((t & Token.IsEvalOrArguments) === Token.IsEvalOrArguments) {
   437→    if (context & Context.Strict) parser.report(Errors.StrictEvalArguments);
   438→    parser.flags |= Flags.StrictEvalArguments;
   439→  }
   440→
   441→  if (!isValidIdentifier(context, t)) parser.report(Errors.Unexpected);
   442→}
   443→
   444→export type Location = {
   445→  readonly index: number;
   446→  readonly line: number;
   447→  readonly column: number;
   448→};
