aboutsummaryrefslogtreecommitdiff
path: root/node_modules/meriyah/src/common.ts
diff options
context:
space:
mode:
authorMinteck <nekostarfan@gmail.com>2021-08-24 14:41:48 +0200
committerMinteck <nekostarfan@gmail.com>2021-08-24 14:41:48 +0200
commitd25e11bee6ca5ca523884da132d18e1400e077b9 (patch)
tree8af39fde19f7ed640a60fb397c7edd647dff1c4c /node_modules/meriyah/src/common.ts
downloadkartik-iridium-d25e11bee6ca5ca523884da132d18e1400e077b9.tar.gz
kartik-iridium-d25e11bee6ca5ca523884da132d18e1400e077b9.tar.bz2
kartik-iridium-d25e11bee6ca5ca523884da132d18e1400e077b9.zip
Initial commit
Diffstat (limited to 'node_modules/meriyah/src/common.ts')
-rw-r--r--node_modules/meriyah/src/common.ts835
1 files changed, 835 insertions, 0 deletions
diff --git a/node_modules/meriyah/src/common.ts b/node_modules/meriyah/src/common.ts
new file mode 100644
index 0000000..333bb9d
--- /dev/null
+++ b/node_modules/meriyah/src/common.ts
@@ -0,0 +1,835 @@
+import { Token, KeywordDescTable } from './token';
+import { Errors, report } from './errors';
+import { Node, Comment, Decorator, SourceLocation } from './estree';
+import { nextToken } from './lexer/scan';
+
+/**
+ * The core context, passed around everywhere as a simple immutable bit set
+ */
+export const enum Context {
+ None = 0,
+ OptionsNext = 1 << 0,
+ OptionsRanges = 1 << 1,
+ OptionsLoc = 1 << 2,
+ OptionsDirectives = 1 << 3,
+ OptionsJSX = 1 << 4,
+ OptionsGlobalReturn = 1 << 5,
+ OptionsLexical = 1 << 6,
+ OptionsPreserveParens = 1 << 7,
+ OptionsWebCompat = 1 << 8,
+ OptionsRaw = 1 << 9,
+ Strict = 1 << 10,
+ Module = 1 << 11, // Current code should be parsed as a module body
+ InSwitch = 1 << 12,
+ InGlobal = 1 << 13,
+ InClass = 1 << 14,
+ AllowRegExp = 1 << 15,
+ TaggedTemplate = 1 << 16,
+ InIteration = 1 << 17,
+ SuperProperty = 1 << 18,
+ SuperCall = 1 << 19,
+ InYieldContext = 1 << 21,
+ InAwaitContext = 1 << 22,
+ InArgumentList = 1 << 23,
+ InConstructor = 1 << 24,
+ InMethod = 1 << 25,
+ AllowNewTarget = 1 << 26,
+ DisallowIn = 1 << 27,
+ OptionsIdentifierPattern = 1 << 28,
+ OptionsSpecDeviation = 1 << 29,
+ AllowEscapedKeyword = 1 << 30,
+ OptionsUniqueKeyInPattern = 1 << 31,
+}
+
+/**
+ * Masks to track the property kind
+ */
+export const enum PropertyKind {
+ None = 0,
+ Method = 1 << 0,
+ Computed = 1 << 1,
+ Shorthand = 1 << 2,
+ Generator = 1 << 3,
+ Async = 1 << 4,
+ Static = 1 << 5,
+ Constructor = 1 << 6,
+ ClassField = 1 << 7,
+ Getter = 1 << 8,
+ Setter = 1 << 9,
+ Extends = 1 << 10,
+ Literal = 1 << 11,
+ PrivateField = 1 << 12,
+ GetSet = Getter | Setter
+}
+
+/**
+ * Masks to track the binding kind
+ */
+export const enum BindingKind {
+ None = 0,
+ ArgumentList = 1 << 0,
+ Empty = 1 << 1,
+ Variable = 1 << 2,
+ Let = 1 << 3,
+ Const = 1 << 4,
+ Class = 1 << 5,
+ FunctionLexical = 1 << 6,
+ FunctionStatement = 1 << 7,
+ CatchPattern = 1 << 8,
+ CatchIdentifier = 1 << 9,
+ CatchIdentifierOrPattern = CatchIdentifier | CatchPattern,
+ LexicalOrFunction = Variable | FunctionLexical,
+ LexicalBinding = Let | Const | FunctionLexical | FunctionStatement | Class
+}
+
+/**
+ * The masks to track where something begins. E.g. statements, declarations or arrows.
+ */
+export const enum Origin {
+ None = 0,
+ Statement = 1 << 0,
+ BlockStatement = 1 << 1,
+ TopLevel = 1 << 2,
+ Declaration = 1 << 3,
+ Arrow = 1 << 4,
+ ForStatement = 1 << 5,
+ Export = 1 << 6,
+}
+
+/**
+ * Masks to track the assignment kind
+ */
+export const enum AssignmentKind {
+ None = 0,
+ Assignable = 1 << 0,
+ CannotAssign = 1 << 1
+}
+
+/**
+ * Masks to track the destructuring kind
+ */
+export const enum DestructuringKind {
+ None = 0,
+ HasToDestruct = 1 << 3,
+ // "Cannot" rather than "can" so that this flag can be ORed together across
+ // multiple characters.
+ CannotDestruct = 1 << 4,
+ // Only destructible if assignable
+ Assignable = 1 << 5,
+ // `__proto__` is a special case and only valid to parse if destructible
+ SeenProto = 1 << 6,
+ Await = 1 << 7,
+ Yield = 1 << 8
+}
+
+/**
+ * The mutable parser flags, in case any flags need passed by reference.
+ */
+export const enum Flags {
+ None = 0,
+ NewLine = 1 << 0,
+ HasConstructor = 1 << 5,
+ Octals = 1 << 6,
+ SimpleParameterList = 1 << 7,
+ HasStrictReserved = 1 << 8,
+ StrictEvalArguments = 1 << 9,
+ DisallowCall = 1 << 10,
+ HasOptionalChaining = 1 << 11
+}
+
+export const enum HoistedClassFlags {
+ None,
+ Hoisted = 1 << 0,
+ Export = 1 << 1
+}
+
+export const enum HoistedFunctionFlags {
+ None,
+ Hoisted = 1 << 0,
+ Export = 1 << 1
+}
+
+/**
+ * Scope kinds
+ */
+export const enum ScopeKind {
+ None = 0,
+ ForStatement = 1 << 0,
+ Block = 1 << 1,
+ CatchStatement = 1 << 2,
+ SwitchStatement = 1 << 3,
+ ArgList = 1 << 4,
+ TryStatement = 1 << 5,
+ CatchBlock = 1 << 6,
+ FunctionBody = 1 << 7,
+ FunctionRoot = 1 << 8,
+ FunctionParams = 1 << 9,
+ ArrowParams = 1 << 10,
+ CatchIdentifier = 1 << 11,
+}
+
+/**
+ * The type of the `onComment` option.
+ */
+export type OnComment = void | Comment[] | ((type: string, value: string, start: number, end: number, loc: SourceLocation) => any);
+
+/**
+ * The type of the `onToken` option.
+ */
+export type OnToken = void | Token[] | ((token: string, start: number, end: number, loc: SourceLocation) => any);
+
+/**
+ * Lexical scope interface
+ */
+export interface ScopeState {
+ parent: ScopeState | undefined;
+ type: ScopeKind;
+ scopeError?: ScopeError | null;
+}
+
+/** Scope error interface */
+export interface ScopeError {
+ type: Errors;
+ params: string[];
+ index: number;
+ line: number;
+ column: number;
+}
+
+/**
+ * The parser interface.
+ */
+export interface ParserState {
+ source: string;
+ flags: Flags;
+ index: number;
+ line: number;
+ column: number;
+ tokenPos: number;
+ startPos: number;
+ startColumn: number;
+ startLine: number;
+ colPos: number;
+ linePos: number;
+ end: number;
+ token: Token;
+ onComment: any;
+ onToken: any;
+ tokenValue: any;
+ tokenRaw: string;
+ tokenRegExp: void | {
+ pattern: string;
+ flags: string;
+ };
+ sourceFile: string | void;
+ assignable: AssignmentKind | DestructuringKind;
+ destructible: AssignmentKind | DestructuringKind;
+ currentChar: number;
+ exportedNames: any;
+ exportedBindings: any;
+ leadingDecorators: Decorator[];
+}
+
+/**
+ * Check for automatic semicolon insertion according to the rules
+ * given in `ECMA-262, section 11.9`.
+ *
+ * @param parser Parser object
+ * @param context Context masks
+ */
+
+export function matchOrInsertSemicolon(parser: ParserState, context: Context, specDeviation?: number): void {
+
+ if (
+ (parser.flags & Flags.NewLine) === 0 &&
+ (parser.token & Token.IsAutoSemicolon) !== Token.IsAutoSemicolon &&
+ !specDeviation
+ ) {
+ report(parser, Errors.UnexpectedToken, KeywordDescTable[parser.token & Token.Type]);
+ }
+ consumeOpt(parser, context, Token.Semicolon);
+}
+
+export function isValidStrictMode(parser: ParserState, index: number, tokenPos: number, tokenValue: string): 0 | 1 {
+ if (index - tokenPos < 13 && tokenValue === 'use strict') {
+ if ((parser.token & Token.IsAutoSemicolon) === Token.IsAutoSemicolon || parser.flags & Flags.NewLine) {
+ return 1;
+ }
+ }
+ return 0;
+}
+
+/**
+ * Consumes the current token if the current token kind is
+ * the specified `kind` and returns `0`. Otherwise returns `1`.
+ *
+ * @param parser Parser state
+ * @param context Context masks
+ * @param token The type of token to consume
+ */
+export function optionalBit(parser: ParserState, context: Context, t: Token): 0 | 1 {
+ if (parser.token !== t) return 0;
+ nextToken(parser, context);
+ return 1;
+}
+
+/** Consumes the current token if the current token kind is
+ * the specified `kind` and returns `true`. Otherwise returns
+ * `false`.
+ *
+ * @param parser Parser state
+ * @param context Context masks
+ * @param token The type of token to consume
+ */
+export function consumeOpt(parser: ParserState, context: Context, t: Token): boolean {
+ if (parser.token !== t) return false;
+ nextToken(parser, context);
+ return true;
+}
+
+/**
+ * Consumes the current token. If the current token kind is not
+ * the specified `kind`, an error will be reported.
+ *
+ * @param parser Parser state
+ * @param context Context masks
+ * @param t The type of token to consume
+ */
+export function consume(parser: ParserState, context: Context, t: Token): void {
+ if (parser.token !== t) report(parser, Errors.ExpectedToken, KeywordDescTable[t & Token.Type]);
+ nextToken(parser, context);
+}
+
+/**
+ * Transforms a `LeftHandSideExpression` into a `AssignmentPattern` if possible,
+ * otherwise it returns the original tree.
+ *
+ * @param parser Parser state
+ * @param {*} node
+ */
+export function reinterpretToPattern(state: ParserState, node: any): void {
+ switch (node.type) {
+ case 'ArrayExpression':
+ node.type = 'ArrayPattern';
+ const elements = node.elements;
+ for (let i = 0, n = elements.length; i < n; ++i) {
+ const element = elements[i];
+ if (element) reinterpretToPattern(state, element);
+ }
+ return;
+ case 'ObjectExpression':
+ node.type = 'ObjectPattern';
+ const properties = node.properties;
+ for (let i = 0, n = properties.length; i < n; ++i) {
+ reinterpretToPattern(state, properties[i]);
+ }
+ return;
+ case 'AssignmentExpression':
+ node.type = 'AssignmentPattern';
+ if (node.operator !== '=') report(state, Errors.InvalidDestructuringTarget);
+ delete node.operator;
+ reinterpretToPattern(state, node.left);
+ return;
+ case 'Property':
+ reinterpretToPattern(state, node.value);
+ return;
+ case 'SpreadElement':
+ node.type = 'RestElement';
+ reinterpretToPattern(state, node.argument);
+ default: // ignore
+ }
+}
+
+/**
+ * Validates binding identifier
+ *
+ * @param parser Parser state
+ * @param context Context masks
+ * @param type Binding type
+ * @param token Token
+ */
+
+export function validateBindingIdentifier(
+ parser: ParserState,
+ context: Context,
+ kind: BindingKind,
+ t: Token,
+ skipEvalArgCheck: 0 | 1
+): void {
+
+ if (context & Context.Strict) {
+
+ if ((t & Token.FutureReserved) === Token.FutureReserved) {
+ report(parser, Errors.UnexpectedStrictReserved);
+ }
+
+ if (!skipEvalArgCheck && (t & Token.IsEvalOrArguments) === Token.IsEvalOrArguments) {
+ report(parser, Errors.StrictEvalArguments);
+ }
+ }
+
+ if ((t & Token.Reserved) === Token.Reserved) {
+ report(parser, Errors.KeywordNotId);
+ }
+
+ // The BoundNames of LexicalDeclaration and ForDeclaration must not
+ // contain 'let'. (CatchParameter is the only lexical binding form
+ // without this restriction.)
+ if (kind & (BindingKind.Let | BindingKind.Const) && t === Token.LetKeyword) {
+ report(parser, Errors.InvalidLetConstBinding);
+ }
+
+ if (context & (Context.InAwaitContext | Context.Module) && t === Token.AwaitKeyword) {
+ report(parser, Errors.AwaitOutsideAsync);
+ }
+
+ if (context & (Context.InYieldContext | Context.Strict) && t === Token.YieldKeyword) {
+ report(parser, Errors.DisallowedInContext, 'yield');
+ }
+}
+
+export function validateFunctionName(
+ parser: ParserState,
+ context: Context,
+ t: Token
+): void {
+
+ if (context & Context.Strict) {
+
+ if ((t & Token.FutureReserved) === Token.FutureReserved) {
+ report(parser, Errors.UnexpectedStrictReserved);
+ }
+
+ if ((t & Token.IsEvalOrArguments) === Token.IsEvalOrArguments) {
+ report(parser, Errors.StrictEvalArguments);
+ }
+
+ if (t === Token.EscapedFutureReserved) {
+ report(parser, Errors.InvalidEscapedKeyword);
+ }
+
+ if (t === Token.EscapedReserved) {
+ report(parser, Errors.InvalidEscapedKeyword);
+ }
+ }
+
+ if ((t & Token.Reserved) === Token.Reserved) {
+ report(parser, Errors.KeywordNotId);
+ }
+
+ if (context & (Context.InAwaitContext | Context.Module) && t === Token.AwaitKeyword) {
+ report(parser, Errors.AwaitOutsideAsync);
+ }
+
+ if (context & (Context.InYieldContext | Context.Strict) && t === Token.YieldKeyword) {
+ report(parser, Errors.DisallowedInContext, 'yield');
+ }
+}
+
+/**
+ * Validates binding identifier
+ *
+ * @param parser Parser state
+ * @param context Context masks
+ * @param t Token
+ */
+
+export function isStrictReservedWord(parser: ParserState, context: Context, t: Token): boolean {
+ if (t === Token.AwaitKeyword) {
+ if (context & (Context.InAwaitContext | Context.Module)) report(parser, Errors.AwaitOutsideAsync);
+ parser.destructible |= DestructuringKind.Await;
+ }
+
+ if (t === Token.YieldKeyword && context & Context.InYieldContext) report(parser, Errors.DisallowedInContext, 'yield');
+
+ return (
+ (t & Token.Reserved) === Token.Reserved ||
+ (t & Token.FutureReserved) === Token.FutureReserved ||
+ t == Token.EscapedFutureReserved
+ );
+}
+
+/**
+ * Checks if the property has any private field key
+ *
+ * @param parser Parser object
+ * @param context Context masks
+ */
+export function isPropertyWithPrivateFieldKey(expr: any): boolean {
+ return !expr.property ? false : expr.property.type === 'PrivateIdentifier';
+}
+
+/**
+ * Checks if a label in `LabelledStatement` are valid or not
+ *
+ * @param parser Parser state
+ * @param labels Object holding the labels
+ * @param name Current label
+ * @param isIterationStatement
+ */
+export function isValidLabel(parser: ParserState, labels: any, name: string, isIterationStatement: 0 | 1): 0 | 1 {
+ while (labels) {
+ if (labels['$' + name]) {
+ if (isIterationStatement) report(parser, Errors.InvalidNestedStatement);
+ return 1;
+ }
+ if (isIterationStatement && labels.loop) isIterationStatement = 0;
+ labels = labels['$'];
+ }
+
+ return 0;
+}
+
+/**
+ * Checks if current label already have been declrared, and if not
+ * declare it
+ *
+ * @param parser Parser state
+ * @param labels Object holding the labels
+ * @param name Current label
+ */
+export function validateAndDeclareLabel(parser: ParserState, labels: any, name: string): void {
+ let set = labels;
+ while (set) {
+ if (set['$' + name]) report(parser, Errors.LabelRedeclaration, name);
+ set = set['$'];
+ }
+
+ labels['$' + name] = 1;
+}
+
+export function finishNode<T extends Node>(
+ parser: ParserState,
+ context: Context,
+ start: number,
+ line: number,
+ column: number,
+ node: T
+): T {
+ if (context & Context.OptionsRanges) {
+ node.start = start;
+ node.end = parser.startPos;
+ node.range = [start, parser.startPos];
+ }
+
+ if (context & Context.OptionsLoc) {
+ node.loc = {
+ start: {
+ line,
+ column
+ },
+ end: {
+ line: parser.startLine,
+ column: parser.startColumn
+ }
+ };
+
+ if (parser.sourceFile) {
+ node.loc.source = parser.sourceFile;
+ }
+ }
+
+ return node;
+}
+
+/** @internal */
+export function isEqualTagName(elementName: any): any {
+ switch (elementName.type) {
+ case 'JSXIdentifier':
+ return elementName.name;
+ case 'JSXNamespacedName':
+ return elementName.namespace + ':' + elementName.name;
+ case 'JSXMemberExpression':
+ return isEqualTagName(elementName.object) + '.' + isEqualTagName(elementName.property);
+ /* istanbul ignore next */
+ default:
+ // ignore
+ }
+}
+
+/**
+ * Create a parsing scope for arrow head, and add lexical binding
+ *
+ * @param parser Parser state
+ * @param context Context masks
+ * @param value Binding name to be declared
+ */
+export function createArrowHeadParsingScope(parser: ParserState, context: Context, value: string): ScopeState {
+ const scope = addChildScope(createScope(), ScopeKind.ArrowParams);
+ addBlockName(parser, context, scope, value, BindingKind.ArgumentList, Origin.None);
+ return scope;
+}
+
+/**
+ * Record duplicate binding errors that may occur in a arrow head or function parameters
+*
+ * @param parser Parser state
+ * @param type Errors type
+ */
+export function recordScopeError(parser: ParserState, type: Errors, ...params: string[]): ScopeError {
+ const { index, line, column } = parser;
+ return {
+ type,
+ params,
+ index,
+ line,
+ column
+ };
+}
+
+/**
+ * Creates a block scope
+ */
+export function createScope(): ScopeState {
+ return {
+ parent: void 0,
+ type: ScopeKind.Block
+ };
+}
+
+/**
+ * Inherit scope
+ *
+ * @param scope Parser object
+ * @param type Scope kind
+ */
+export function addChildScope(parent: ScopeState | undefined, type: ScopeKind): ScopeState {
+ return {
+ parent,
+ type,
+ scopeError: void 0
+ };
+}
+
+/**
+ * Adds either a var binding or a block scoped binding.
+ *
+ * @param parser Parser state
+ * @param context Context masks
+ * @param scope Scope state
+ * @param name Binding name
+ * @param type Binding kind
+ * @param origin Binding Origin
+ */
+export function addVarOrBlock(
+ parser: ParserState,
+ context: Context,
+ scope: ScopeState,
+ name: string,
+ kind: BindingKind,
+ origin: Origin
+) {
+ if (kind & BindingKind.Variable) {
+ addVarName(parser, context, scope, name, kind);
+ } else {
+ addBlockName(parser, context, scope, name, kind, origin);
+ }
+ if (origin & Origin.Export) {
+ declareUnboundVariable(parser, name);
+ }
+}
+
+/**
+ * Adds block scoped binding
+ *
+ * @param parser Parser state
+ * @param context Context masks
+ * @param scope Scope state
+ * @param name Binding name
+ * @param type Binding kind
+ * @param origin Binding Origin
+ */
+export function addBlockName(
+ parser: ParserState,
+ context: Context,
+ scope: any,
+ name: string,
+ kind: BindingKind,
+ origin: Origin
+) {
+ const value = (scope as any)['#' + name];
+
+ if (value && (value & BindingKind.Empty) === 0) {
+ if (kind & BindingKind.ArgumentList) {
+ scope.scopeError = recordScopeError(parser, Errors.DuplicateBinding, name);
+ } else if (
+ context & Context.OptionsWebCompat &&
+ value & BindingKind.FunctionLexical &&
+ origin & Origin.BlockStatement
+ ) {
+ } else {
+ report(parser, Errors.DuplicateBinding, name);
+ }
+ }
+
+ if (
+ scope.type & ScopeKind.FunctionBody &&
+ ((scope as any).parent['#' + name] && ((scope as any).parent['#' + name] & BindingKind.Empty) === 0)
+ ) {
+ report(parser, Errors.DuplicateBinding, name);
+ }
+
+ if (scope.type & ScopeKind.ArrowParams && value && (value & BindingKind.Empty) === 0) {
+ if (kind & BindingKind.ArgumentList) {
+ scope.scopeError = recordScopeError(parser, Errors.DuplicateBinding, name);
+ }
+ }
+
+ if (scope.type & ScopeKind.CatchBlock) {
+ if ((scope as any).parent['#' + name] & BindingKind.CatchIdentifierOrPattern)
+ report(parser, Errors.ShadowedCatchClause, name);
+ }
+
+ (scope as any)['#' + name] = kind;
+}
+
+/**
+ * Adds a variable binding
+ *
+ * @param parser Parser state
+ * @param context Context masks
+ * @param scope Scope state
+ * @param name Binding name
+ * @param type Binding kind
+ */
+export function addVarName(
+ parser: ParserState,
+ context: Context,
+ scope: ScopeState,
+ name: string,
+ kind: BindingKind
+): void {
+ let currentScope: any = scope;
+
+ while (currentScope && (currentScope.type & ScopeKind.FunctionRoot) === 0) {
+ const value: ScopeKind = currentScope['#' + name];
+
+ if (value & BindingKind.LexicalBinding) {
+ if (
+ context & Context.OptionsWebCompat &&
+ (context & Context.Strict) === 0 &&
+ ((kind & BindingKind.FunctionStatement && value & BindingKind.LexicalOrFunction) ||
+ (value & BindingKind.FunctionStatement && kind & BindingKind.LexicalOrFunction))
+ ) {
+ } else {
+ report(parser, Errors.DuplicateBinding, name);
+ }
+ }
+ if (currentScope === scope) {
+ if (value & BindingKind.ArgumentList && kind & BindingKind.ArgumentList) {
+ currentScope.scopeError = recordScopeError(parser, Errors.DuplicateBinding, name);
+ }
+ }
+ if (value & (BindingKind.CatchIdentifier | BindingKind.CatchPattern)) {
+ if (
+ (value & BindingKind.CatchIdentifier) === 0 ||
+ (context & Context.OptionsWebCompat) === 0 ||
+ context & Context.Strict
+ ) {
+ report(parser, Errors.DuplicateBinding, name);
+ }
+ }
+
+ currentScope['#' + name] = kind;
+
+ currentScope = currentScope.parent;
+ }
+}
+
+/**
+ * Appends a name to the `ExportedNames` of the `ExportsList`, and checks
+ * for duplicates
+ *
+ * @see [Link](https://tc39.github.io/ecma262/$sec-exports-static-semantics-exportednames)
+ *
+ * @param parser Parser object
+ * @param name Exported name
+ */
+export function declareUnboundVariable(parser: ParserState, name: string): void {
+ if (parser.exportedNames !== void 0 && name !== '') {
+ if (parser.exportedNames['#' + name]) {
+ report(parser, Errors.DuplicateExportBinding, name);
+ }
+ parser.exportedNames['#' + name] = 1;
+ }
+}
+
+/**
+ * Appends a name to the `ExportedBindings` of the `ExportsList`,
+ *
+ * @see [Link](https://tc39.es/ecma262/$sec-exports-static-semantics-exportedbindings)
+ *
+ * @param parser Parser object
+ * @param name Exported binding name
+ */
+export function addBindingToExports(parser: ParserState, name: string): void {
+ if (parser.exportedBindings !== void 0 && name !== '') {
+ parser.exportedBindings['#' + name] = 1;
+ }
+}
+
+export function pushComment(context: Context, array: any[]): any {
+ return function(type: string, value: string, start: number, end: number, loc: SourceLocation) {
+ const comment: any = {
+ type,
+ value
+ };
+
+ if (context & Context.OptionsRanges) {
+ comment.start = start;
+ comment.end = end;
+ comment.range = [start, end];
+ }
+ if (context & Context.OptionsLoc) {
+ comment.loc = loc;
+ }
+ array.push(comment);
+ };
+}
+
+export function pushToken(context: Context, array: any[]): any {
+ return function(token: string, start: number, end: number, loc: SourceLocation) {
+ const tokens: any = {
+ token
+ };
+
+ if (context & Context.OptionsRanges) {
+ tokens.start = start;
+ tokens.end = end;
+ tokens.range = [start, end];
+ }
+ if (context & Context.OptionsLoc) {
+ tokens.loc = loc;
+ }
+ array.push(tokens);
+ };
+}
+
+export function isValidIdentifier(context: Context, t: Token): boolean {
+ if (context & (Context.Strict | Context.InYieldContext)) {
+ // Module code is also "strict mode code"
+ if (context & Context.Module && t === Token.AwaitKeyword) return false;
+ if (context & Context.InYieldContext && t === Token.YieldKeyword) return false;
+ return (t & Token.IsIdentifier) === Token.IsIdentifier || (t & Token.Contextual) === Token.Contextual;
+ }
+
+ return (
+ (t & Token.IsIdentifier) === Token.IsIdentifier ||
+ (t & Token.Contextual) === Token.Contextual ||
+ (t & Token.FutureReserved) === Token.FutureReserved
+ );
+}
+
+export function classifyIdentifier(
+ parser: ParserState,
+ context: Context,
+ t: Token,
+ isArrow: 0 | 1
+): any {
+ if ((t & Token.IsEvalOrArguments) === Token.IsEvalOrArguments) {
+ if (context & Context.Strict) report(parser, Errors.StrictEvalArguments);
+ if (isArrow) parser.flags |= Flags.StrictEvalArguments;
+ }
+
+ if (!isValidIdentifier(context, t)) report(parser, Errors.Unexpected);
+}