• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1import * as ts from "./_namespaces/ts";
2import {
3    AccessorDeclaration,
4    addRange,
5    addRelatedInfo,
6    AmdDependency,
7    AnnotationDeclaration,
8    AnnotationElement,
9    AnnotationPropertyDeclaration,
10    append,
11    ArrayBindingElement,
12    ArrayBindingPattern,
13    ArrayLiteralExpression,
14    ArrayTypeNode,
15    ArrowFunction,
16    AsExpression,
17    AssertClause,
18    AssertEntry,
19    AssertionLevel,
20    AsteriskToken,
21    attachFileToDiagnostics,
22    AwaitExpression,
23    BaseNodeFactory,
24    BinaryExpression,
25    BinaryOperatorToken,
26    BindingElement,
27    BindingName,
28    BindingPattern,
29    Block,
30    BooleanLiteral,
31    BreakOrContinueStatement,
32    BreakStatement,
33    CallExpression,
34    CallSignatureDeclaration,
35    canHaveModifiers,
36    CaseBlock,
37    CaseClause,
38    CaseOrDefaultClause,
39    CatchClause,
40    CharacterCodes,
41    CheckJsDirective,
42    ClassDeclaration,
43    ClassElement,
44    ClassExpression,
45    ClassLikeDeclaration,
46    ClassStaticBlockDeclaration,
47    CommaListExpression,
48    CommentDirective,
49    commentPragmas,
50    CommentRange,
51    CompilerOptions,
52    ComputedPropertyName,
53    concatenate,
54    ConditionalExpression,
55    ConditionalTypeNode,
56    ConstructorDeclaration,
57    ConstructorTypeNode,
58    ConstructSignatureDeclaration,
59    containsParseError,
60    ContinueStatement,
61    convertToObjectWorker,
62    createDetachedDiagnostic,
63    createNodeFactory,
64    createScanner,
65    createTextChangeRange,
66    createTextSpanFromBounds,
67    Debug,
68    Decorator,
69    DefaultClause,
70    defaultInitCompilerOptions,
71    DeleteExpression,
72    Diagnostic,
73    DiagnosticMessage,
74    Diagnostics,
75    DiagnosticWithDetachedLocation,
76    DoStatement,
77    DotDotDotToken,
78    ElementAccessExpression,
79    emptyArray,
80    emptyMap,
81    EndOfFileToken,
82    ensureScriptKind,
83    EntityName,
84    EnumDeclaration,
85    EnumMember,
86    ESMap,
87    EtsComponentExpression,
88    EtsFlags,
89    ExclamationToken,
90    ExportAssignment,
91    ExportDeclaration,
92    ExportSpecifier,
93    Expression,
94    ExpressionStatement,
95    ExpressionWithTypeArguments,
96    Extension,
97    ExternalModuleReference,
98    fileExtensionIsOneOf,
99    FileReference,
100    findIndex,
101    forEach,
102    ForEachChildNodes,
103    ForInOrOfStatement,
104    ForInStatement,
105    ForOfStatement,
106    ForStatement,
107    FunctionDeclaration,
108    FunctionExpression,
109    FunctionOrConstructorTypeNode,
110    FunctionTypeNode,
111    GetAccessorDeclaration,
112    getBinaryOperatorPrecedence,
113    getEtsExtendDecoratorsComponentNames,
114    getEtsStylesDecoratorComponentNames,
115    getFullWidth,
116    getJSDocCommentRanges,
117    getLanguageVariant,
118    getLastChild,
119    getLeadingCommentRanges,
120    getModifiers,
121    getPropertyNameForPropertyNameNode,
122    getRootComponent,
123    getSdkPath,
124    getSpellingSuggestion,
125    getTextOfNodeFromSourceText,
126    getTextOfPropertyName,
127    getVirtualEtsComponent,
128    hasEtsBuilderDecoratorNames,
129    hasEtsExtendDecoratorNames,
130    hasEtsStylesDecoratorNames,
131    HasJSDoc,
132    hasJSDocNodes,
133    HasModifiers,
134    HeritageClause,
135    Identifier,
136    idText,
137    IfStatement,
138    ImportClause,
139    ImportDeclaration,
140    ImportEqualsDeclaration,
141    ImportOrExportSpecifier,
142    ImportSpecifier,
143    ImportTypeAssertionContainer,
144    ImportTypeNode,
145    IndexedAccessTypeNode,
146    IndexSignatureDeclaration,
147    InferTypeNode,
148    InterfaceDeclaration,
149    IntersectionTypeNode,
150    isArray,
151    isAssignmentOperator,
152    isAsyncModifier,
153    isCallExpression,
154    isClassMemberModifier,
155    isExportAssignment,
156    isExportDeclaration,
157    isExportModifier,
158    isExpressionWithTypeArguments,
159    isExternalModuleReference,
160    isFunctionTypeNode,
161    isIdentifierText,
162    isImportDeclaration,
163    isImportEqualsDeclaration,
164    isJSDocFunctionType,
165    isJSDocNullableType,
166    isJSDocReturnTag,
167    isJSDocTypeTag,
168    isJsxOpeningElement,
169    isJsxOpeningFragment,
170    isKeyword,
171    isLeftHandSideExpression,
172    isLiteralKind,
173    isMetaProperty,
174    isModifierKind,
175    isNonNullExpression,
176    isPrivateIdentifier,
177    isPropertyAccessExpression,
178    isSetAccessorDeclaration,
179    isStringOrNumericLiteralLike,
180    isTaggedTemplateExpression,
181    isTemplateLiteralKind,
182    isTokenInsideBuilder,
183    isTypeReferenceNode,
184    IterationStatement,
185    JSDoc,
186    JSDocAllType,
187    JSDocAugmentsTag,
188    JSDocAuthorTag,
189    JSDocCallbackTag,
190    JSDocClassTag,
191    JSDocComment,
192    JSDocContainer,
193    JSDocDeprecatedTag,
194    JSDocEnumTag,
195    JSDocFunctionType,
196    JSDocImplementsTag,
197    JSDocLink,
198    JSDocLinkCode,
199    JSDocLinkPlain,
200    JSDocMemberName,
201    JSDocNameReference,
202    JSDocNamespaceDeclaration,
203    JSDocNonNullableType,
204    JSDocNullableType,
205    JSDocOptionalType,
206    JSDocOverrideTag,
207    JSDocParameterTag,
208    JSDocPrivateTag,
209    JSDocPropertyLikeTag,
210    JSDocPropertyTag,
211    JSDocProtectedTag,
212    JSDocPublicTag,
213    JSDocReadonlyTag,
214    JSDocReturnTag,
215    JSDocSeeTag,
216    JSDocSignature,
217    JSDocSyntaxKind,
218    JSDocTag,
219    JSDocTemplateTag,
220    JSDocText,
221    JSDocThisTag,
222    JSDocTypedefTag,
223    JSDocTypeExpression,
224    JSDocTypeLiteral,
225    JSDocTypeTag,
226    JSDocUnknownTag,
227    JSDocUnknownType,
228    JSDocVariadicType,
229    JsonMinusNumericLiteral,
230    JsonObjectExpressionStatement,
231    JsonSourceFile,
232    JsxAttribute,
233    JsxAttributes,
234    JsxAttributeValue,
235    JsxChild,
236    JsxClosingElement,
237    JsxClosingFragment,
238    JsxElement,
239    JsxExpression,
240    JsxFragment,
241    JsxOpeningElement,
242    JsxOpeningFragment,
243    JsxOpeningLikeElement,
244    JsxSelfClosingElement,
245    JsxSpreadAttribute,
246    JsxTagNameExpression,
247    JsxTagNamePropertyAccess,
248    JsxText,
249    JsxTokenSyntaxKind,
250    LabeledStatement,
251    LanguageVariant,
252    last,
253    lastOrUndefined,
254    LeftHandSideExpression,
255    LiteralExpression,
256    LiteralLikeNode,
257    LiteralTypeNode,
258    map,
259    Map,
260    mapDefined,
261    MappedTypeNode,
262    MemberExpression,
263    MemoryDotting,
264    MetaProperty,
265    MethodDeclaration,
266    MethodSignature,
267    MinusToken,
268    MissingDeclaration,
269    Modifier,
270    ModifierFlags,
271    ModifierLike,
272    ModifiersArray,
273    modifiersToFlags,
274    ModuleBlock,
275    ModuleDeclaration,
276    ModuleKind,
277    Mutable,
278    NamedExportBindings,
279    NamedExports,
280    NamedImports,
281    NamedImportsOrExports,
282    NamedTupleMember,
283    NamespaceDeclaration,
284    NamespaceExport,
285    NamespaceExportDeclaration,
286    NamespaceImport,
287    NewExpression,
288    Node,
289    NodeArray,
290    NodeFactoryFlags,
291    NodeFlags,
292    nodeIsMissing,
293    nodeIsPresent,
294    NonNullExpression,
295    noop,
296    normalizePath,
297    NoSubstitutionTemplateLiteral,
298    NullLiteral,
299    NumericLiteral,
300    objectAllocator,
301    ObjectBindingPattern,
302    ObjectLiteralElementLike,
303    ObjectLiteralExpression,
304    OperatorPrecedence,
305    OptionalTypeNode,
306    PackageJsonInfo,
307    ParameterDeclaration,
308    ParenthesizedExpression,
309    ParenthesizedTypeNode,
310    PartiallyEmittedExpression,
311    perfLogger,
312    PlusToken,
313    PostfixUnaryExpression,
314    PostfixUnaryOperator,
315    PragmaDefinition,
316    PragmaKindFlags,
317    PragmaMap,
318    PragmaPseudoMap,
319    PragmaPseudoMapEntry,
320    PrefixUnaryExpression,
321    PrefixUnaryOperator,
322    PrimaryExpression,
323    PrivateIdentifier,
324    processKit,
325    PropertyAccessEntityNameExpression,
326    PropertyAccessExpression,
327    PropertyAssignment,
328    PropertyDeclaration,
329    PropertyName,
330    PropertySignature,
331    QualifiedName,
332    QuestionDotToken,
333    QuestionToken,
334    ReadonlyKeyword,
335    ReadonlyPragmaMap,
336    ReadonlyTextRange,
337    RestTypeNode,
338    ReturnStatement,
339    SatisfiesExpression,
340    ScriptKind,
341    ScriptTarget,
342    Set,
343    SetAccessorDeclaration,
344    setParent,
345    setParentRecursive,
346    setTextRange,
347    setTextRangePos,
348    setTextRangePosEnd,
349    setTextRangePosWidth,
350    ShorthandPropertyAssignment,
351    skipTrivia,
352    some,
353    SourceFile,
354    SpreadAssignment,
355    SpreadElement,
356    startsWith,
357    Statement,
358    StringLiteral,
359    StructDeclaration,
360    supportedDeclarationExtensions,
361    SwitchStatement,
362    SyntaxKind,
363    TaggedTemplateExpression,
364    TemplateExpression,
365    TemplateHead,
366    TemplateLiteralToken,
367    TemplateLiteralTypeNode,
368    TemplateLiteralTypeSpan,
369    TemplateMiddle,
370    TemplateSpan,
371    TemplateTail,
372    TextChangeRange,
373    textChangeRangeIsUnchanged,
374    textChangeRangeNewSpan,
375    TextRange,
376    textSpanEnd,
377    textToKeywordObj,
378    ThisExpression,
379    ThisTypeNode,
380    ThrowStatement,
381    toArray,
382    Token,
383    TokenFlags,
384    tokenIsIdentifierOrKeyword,
385    tokenIsIdentifierOrKeywordOrGreaterThan,
386    tokenToString,
387    tracing,
388    TransformFlags,
389    trimString,
390    TryStatement,
391    TupleTypeNode,
392    TypeAliasDeclaration,
393    TypeAssertion,
394    TypeElement,
395    TypeLiteralNode,
396    TypeNode,
397    TypeOfExpression,
398    TypeOperatorNode,
399    TypeParameterDeclaration,
400    TypePredicateNode,
401    TypeQueryNode,
402    TypeReferenceNode,
403    UnaryExpression,
404    UnionOrIntersectionTypeNode,
405    UnionTypeNode,
406    UpdateExpression,
407    VariableDeclaration,
408    VariableDeclarationList,
409    VariableStatement,
410    VoidExpression,
411    WhileStatement,
412    WithStatement,
413    YieldExpression,
414} from "./_namespaces/ts";
415import * as performance from "./_namespaces/ts.performance";
416
417const enum SignatureFlags {
418    None = 0,
419    Yield = 1 << 0,
420    Await = 1 << 1,
421    Type  = 1 << 2,
422    IgnoreMissingOpenBrace = 1 << 4,
423    JSDoc = 1 << 5,
424}
425
426const enum SpeculationKind {
427    TryParse,
428    Lookahead,
429    Reparse
430}
431
432let NodeConstructor: new (kind: SyntaxKind, pos?: number, end?: number) => Node;
433let TokenConstructor: new (kind: SyntaxKind, pos?: number, end?: number) => Node;
434let IdentifierConstructor: new (kind: SyntaxKind, pos?: number, end?: number) => Node;
435let PrivateIdentifierConstructor: new (kind: SyntaxKind, pos?: number, end?: number) => Node;
436let SourceFileConstructor: new (kind: SyntaxKind, pos?: number, end?: number) => Node;
437
438/**
439 * NOTE: You should not use this, it is only exported to support `createNode` in `~/src/deprecatedCompat/deprecations.ts`.
440 *
441 * @internal
442 */
443export const parseBaseNodeFactory: BaseNodeFactory = {
444    createBaseSourceFileNode: kind => new (SourceFileConstructor || (SourceFileConstructor = objectAllocator.getSourceFileConstructor()))(kind, -1, -1),
445    createBaseIdentifierNode: kind => new (IdentifierConstructor || (IdentifierConstructor = objectAllocator.getIdentifierConstructor()))(kind, -1, -1),
446    createBasePrivateIdentifierNode: kind => new (PrivateIdentifierConstructor || (PrivateIdentifierConstructor = objectAllocator.getPrivateIdentifierConstructor()))(kind, -1, -1),
447    createBaseTokenNode: kind => new (TokenConstructor || (TokenConstructor = objectAllocator.getTokenConstructor()))(kind, -1, -1),
448    createBaseNode: kind => new (NodeConstructor || (NodeConstructor = objectAllocator.getNodeConstructor()))(kind, -1, -1),
449};
450
451/** @internal */
452export const parseNodeFactory = createNodeFactory(NodeFactoryFlags.NoParenthesizerRules, parseBaseNodeFactory);
453
454function visitNode<T>(cbNode: (node: Node) => T, node: Node | undefined): T | undefined {
455    return node && cbNode(node);
456}
457
458function visitNodes<T>(cbNode: (node: Node) => T, cbNodes: ((node: NodeArray<Node>) => T | undefined) | undefined, nodes: NodeArray<Node> | undefined): T | undefined {
459    if (nodes) {
460        if (cbNodes) {
461            return cbNodes(nodes);
462        }
463        for (const node of nodes) {
464            const result = cbNode(node);
465            if (result) {
466                return result;
467            }
468        }
469    }
470}
471
472/** @internal */
473export function isJSDocLikeText(text: string, start: number) {
474    return text.charCodeAt(start + 1) === CharacterCodes.asterisk &&
475        text.charCodeAt(start + 2) === CharacterCodes.asterisk &&
476        text.charCodeAt(start + 3) !== CharacterCodes.slash;
477}
478
479/** @internal */
480export function isFileProbablyExternalModule(sourceFile: SourceFile) {
481    // Try to use the first top-level import/export when available, then
482    // fall back to looking for an 'import.meta' somewhere in the tree if necessary.
483    return forEach(sourceFile.statements, isAnExternalModuleIndicatorNode) ||
484        getImportMetaIfNecessary(sourceFile);
485}
486
487function isAnExternalModuleIndicatorNode(node: Node) {
488    return canHaveModifiers(node) && hasModifierOfKind(node, SyntaxKind.ExportKeyword)
489        || isImportEqualsDeclaration(node) && isExternalModuleReference(node.moduleReference)
490        || isImportDeclaration(node)
491        || isExportAssignment(node)
492        || isExportDeclaration(node) ? node : undefined;
493}
494
495function getImportMetaIfNecessary(sourceFile: SourceFile) {
496    return sourceFile.flags & NodeFlags.PossiblyContainsImportMeta ?
497        walkTreeForImportMeta(sourceFile) :
498        undefined;
499}
500
501function walkTreeForImportMeta(node: Node): Node | undefined {
502    return isImportMeta(node) ? node : forEachChild(node, walkTreeForImportMeta);
503}
504
505/** Do not use hasModifier inside the parser; it relies on parent pointers. Use this instead. */
506function hasModifierOfKind(node: HasModifiers, kind: SyntaxKind) {
507    return some(node.modifiers, m => m.kind === kind);
508}
509
510function isImportMeta(node: Node): boolean {
511    return isMetaProperty(node) && node.keywordToken === SyntaxKind.ImportKeyword && node.name.escapedText === "meta";
512}
513
514type ForEachChildFunction<TNode> = <T>(node: TNode, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined) => T | undefined;
515type ForEachChildTable = { [TNode in ForEachChildNodes as TNode["kind"]]: ForEachChildFunction<TNode> };
516const forEachChildTable: ForEachChildTable = {
517    [SyntaxKind.QualifiedName]: function forEachChildInQualifiedName<T>(node: QualifiedName, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
518        return visitNode(cbNode, node.left) ||
519            visitNode(cbNode, node.right);
520    },
521    [SyntaxKind.TypeParameter]: function forEachChildInTypeParameter<T>(node: TypeParameterDeclaration, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
522        return visitNodes(cbNode, cbNodes, node.modifiers) ||
523            visitNode(cbNode, node.name) ||
524            visitNode(cbNode, node.constraint) ||
525            visitNode(cbNode, node.default) ||
526            visitNode(cbNode, node.expression);
527    },
528    [SyntaxKind.ShorthandPropertyAssignment]: function forEachChildInShorthandPropertyAssignment<T>(node: ShorthandPropertyAssignment, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
529        return visitNodes(cbNode, cbNodes, node.illegalDecorators) ||
530            visitNodes(cbNode, cbNodes, node.modifiers) ||
531            visitNode(cbNode, node.name) ||
532            visitNode(cbNode, node.questionToken) ||
533            visitNode(cbNode, node.exclamationToken) ||
534            visitNode(cbNode, node.equalsToken) ||
535            visitNode(cbNode, node.objectAssignmentInitializer);
536    },
537    [SyntaxKind.SpreadAssignment]: function forEachChildInSpreadAssignment<T>(node: SpreadAssignment, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
538        return visitNode(cbNode, node.expression);
539    },
540    [SyntaxKind.Parameter]: function forEachChildInParameter<T>(node: ParameterDeclaration, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
541        return visitNodes(cbNode, cbNodes, node.modifiers) ||
542            visitNode(cbNode, node.dotDotDotToken) ||
543            visitNode(cbNode, node.name) ||
544            visitNode(cbNode, node.questionToken) ||
545            visitNode(cbNode, node.type) ||
546            visitNode(cbNode, node.initializer);
547    },
548    [SyntaxKind.PropertyDeclaration]: function forEachChildInPropertyDeclaration<T>(node: PropertyDeclaration, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
549        return visitNodes(cbNode, cbNodes, node.modifiers) ||
550            visitNode(cbNode, node.name) ||
551            visitNode(cbNode, node.questionToken) ||
552            visitNode(cbNode, node.exclamationToken) ||
553            visitNode(cbNode, node.type) ||
554            visitNode(cbNode, node.initializer);
555    },
556    [SyntaxKind.AnnotationPropertyDeclaration]: function forEachChildInAnnotationPropertyDeclaration<T>(node: AnnotationPropertyDeclaration,
557        cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
558        return visitNode(cbNode, node.name) ||
559            visitNode(cbNode, node.type) ||
560            visitNode(cbNode, node.initializer);
561    },
562    [SyntaxKind.PropertySignature]: function forEachChildInPropertySignature<T>(node: PropertySignature, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
563        return visitNodes(cbNode, cbNodes, node.modifiers) ||
564            visitNode(cbNode, node.name) ||
565            visitNode(cbNode, node.questionToken) ||
566            visitNode(cbNode, node.type) ||
567            visitNode(cbNode, node.initializer);
568    },
569    [SyntaxKind.PropertyAssignment]: function forEachChildInPropertyAssignment<T>(node: PropertyAssignment, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
570        return visitNodes(cbNode, cbNodes, node.illegalDecorators) ||
571            visitNodes(cbNode, cbNodes, node.modifiers) ||
572            visitNode(cbNode, node.name) ||
573            visitNode(cbNode, node.questionToken) ||
574            visitNode(cbNode, node.exclamationToken) ||
575            visitNode(cbNode, node.initializer);
576    },
577    [SyntaxKind.VariableDeclaration]: function forEachChildInVariableDeclaration<T>(node: VariableDeclaration, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
578        return visitNode(cbNode, node.name) ||
579            visitNode(cbNode, node.exclamationToken) ||
580            visitNode(cbNode, node.type) ||
581            visitNode(cbNode, node.initializer);
582    },
583    [SyntaxKind.BindingElement]: function forEachChildInBindingElement<T>(node: BindingElement, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
584        return visitNode(cbNode, node.dotDotDotToken) ||
585            visitNode(cbNode, node.propertyName) ||
586            visitNode(cbNode, node.name) ||
587            visitNode(cbNode, node.initializer);
588    },
589    [SyntaxKind.IndexSignature]: function forEachChildInIndexSignature<T>(node: IndexSignatureDeclaration, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
590        return visitNodes(cbNode, cbNodes, node.illegalDecorators) ||
591            visitNodes(cbNode, cbNodes, node.modifiers) ||
592            visitNodes(cbNode, cbNodes, node.typeParameters) ||
593            visitNodes(cbNode, cbNodes, node.parameters) ||
594            visitNode(cbNode, node.type);
595    },
596    [SyntaxKind.ConstructorType]: function forEachChildInConstructorType<T>(node: ConstructorTypeNode, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
597        return visitNodes(cbNode, cbNodes, node.modifiers) ||
598            visitNodes(cbNode, cbNodes, node.typeParameters) ||
599            visitNodes(cbNode, cbNodes, node.parameters) ||
600            visitNode(cbNode, node.type);
601    },
602    [SyntaxKind.FunctionType]: function forEachChildInFunctionType<T>(node: FunctionTypeNode, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
603        return visitNodes(cbNode, cbNodes, node.modifiers) ||
604            visitNodes(cbNode, cbNodes, node.typeParameters) ||
605            visitNodes(cbNode, cbNodes, node.parameters) ||
606            visitNode(cbNode, node.type);
607    },
608    [SyntaxKind.CallSignature]: forEachChildInCallOrConstructSignature,
609    [SyntaxKind.ConstructSignature]: forEachChildInCallOrConstructSignature,
610    [SyntaxKind.EtsComponentExpression]: function forEachChildInEtsComponentExpression<T>(node: EtsComponentExpression, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
611        return visitNode(cbNode, node.expression) ||
612            visitNodes(cbNode, cbNodes, node.arguments) ||
613            visitNode(cbNode, node.body);
614    },
615    [SyntaxKind.MethodDeclaration]: function forEachChildInMethodDeclaration<T>(node: MethodDeclaration, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
616        return visitNodes(cbNode, cbNodes, node.modifiers) ||
617            visitNode(cbNode, node.asteriskToken) ||
618            visitNode(cbNode, node.name) ||
619            visitNode(cbNode, node.questionToken) ||
620            visitNode(cbNode, node.exclamationToken) ||
621            visitNodes(cbNode, cbNodes, node.typeParameters) ||
622            visitNodes(cbNode, cbNodes, node.parameters) ||
623            visitNode(cbNode, node.type) ||
624            visitNode(cbNode, node.body);
625    },
626    [SyntaxKind.MethodSignature]: function forEachChildInMethodSignature<T>(node: MethodSignature, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
627        return visitNodes(cbNode, cbNodes, node.modifiers) ||
628            visitNode(cbNode, node.name) ||
629            visitNode(cbNode, node.questionToken) ||
630            visitNodes(cbNode, cbNodes, node.typeParameters) ||
631            visitNodes(cbNode, cbNodes, node.parameters) ||
632            visitNode(cbNode, node.type);
633    },
634    [SyntaxKind.Constructor]: function forEachChildInConstructor<T>(node: ConstructorDeclaration, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
635        return visitNodes(cbNode, cbNodes, node.illegalDecorators) ||
636            visitNodes(cbNode, cbNodes, node.modifiers) ||
637            visitNode(cbNode, node.name) ||
638            visitNodes(cbNode, cbNodes, node.typeParameters) ||
639            visitNodes(cbNode, cbNodes, node.parameters) ||
640            visitNode(cbNode, node.type) ||
641            visitNode(cbNode, node.body);
642    },
643    [SyntaxKind.GetAccessor]: function forEachChildInGetAccessor<T>(node: GetAccessorDeclaration, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
644        return visitNodes(cbNode, cbNodes, node.modifiers) ||
645            visitNode(cbNode, node.name) ||
646            visitNodes(cbNode, cbNodes, node.typeParameters) ||
647            visitNodes(cbNode, cbNodes, node.parameters) ||
648            visitNode(cbNode, node.type) ||
649            visitNode(cbNode, node.body);
650    },
651    [SyntaxKind.SetAccessor]: function forEachChildInSetAccessor<T>(node: SetAccessorDeclaration, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
652        return visitNodes(cbNode, cbNodes, node.modifiers) ||
653            visitNode(cbNode, node.name) ||
654            visitNodes(cbNode, cbNodes, node.typeParameters) ||
655            visitNodes(cbNode, cbNodes, node.parameters) ||
656            visitNode(cbNode, node.type) ||
657            visitNode(cbNode, node.body);
658    },
659    [SyntaxKind.FunctionDeclaration]: function forEachChildInFunctionDeclaration<T>(node: FunctionDeclaration, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
660        return visitNodes(cbNode, cbNodes, node.illegalDecorators) ||
661            visitNodes(cbNode, cbNodes, node.modifiers) ||
662            visitNode(cbNode, node.asteriskToken) ||
663            visitNode(cbNode, node.name) ||
664            visitNodes(cbNode, cbNodes, node.typeParameters) ||
665            visitNodes(cbNode, cbNodes, node.parameters) ||
666            visitNode(cbNode, node.type) ||
667            visitNode(cbNode, node.body);
668    },
669    [SyntaxKind.FunctionExpression]: function forEachChildInFunctionExpression<T>(node: FunctionExpression, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
670        return visitNodes(cbNode, cbNodes, node.modifiers) ||
671            visitNode(cbNode, node.asteriskToken) ||
672            visitNode(cbNode, node.name) ||
673            visitNodes(cbNode, cbNodes, node.typeParameters) ||
674            visitNodes(cbNode, cbNodes, node.parameters) ||
675            visitNode(cbNode, node.type) ||
676            visitNode(cbNode, node.body);
677    },
678    [SyntaxKind.ArrowFunction]: function forEachChildInArrowFunction<T>(node: ArrowFunction, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
679        return visitNodes(cbNode, cbNodes, node.modifiers) ||
680            visitNodes(cbNode, cbNodes, node.typeParameters) ||
681            visitNodes(cbNode, cbNodes, node.parameters) ||
682            visitNode(cbNode, node.type) ||
683            visitNode(cbNode, node.equalsGreaterThanToken) ||
684            visitNode(cbNode, node.body);
685    },
686    [SyntaxKind.ClassStaticBlockDeclaration]: function forEachChildInClassStaticBlockDeclaration<T>(node: ClassStaticBlockDeclaration, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
687        return visitNodes(cbNode, cbNodes, node.illegalDecorators) ||
688            visitNodes(cbNode, cbNodes, node.modifiers) ||
689            visitNode(cbNode, node.body);
690    },
691    [SyntaxKind.TypeReference]: function forEachChildInTypeReference<T>(node: TypeReferenceNode, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
692        return visitNode(cbNode, node.typeName) ||
693            visitNodes(cbNode, cbNodes, node.typeArguments);
694    },
695    [SyntaxKind.TypePredicate]: function forEachChildInTypePredicate<T>(node: TypePredicateNode, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
696        return visitNode(cbNode, node.assertsModifier) ||
697            visitNode(cbNode, node.parameterName) ||
698            visitNode(cbNode, node.type);
699    },
700    [SyntaxKind.TypeQuery]: function forEachChildInTypeQuery<T>(node: TypeQueryNode, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
701        return visitNode(cbNode, node.exprName) ||
702            visitNodes(cbNode, cbNodes, node.typeArguments);
703    },
704    [SyntaxKind.TypeLiteral]: function forEachChildInTypeLiteral<T>(node: TypeLiteralNode, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
705        return visitNodes(cbNode, cbNodes, node.members);
706    },
707    [SyntaxKind.ArrayType]: function forEachChildInArrayType<T>(node: ArrayTypeNode, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
708        return visitNode(cbNode, node.elementType);
709    },
710    [SyntaxKind.TupleType]: function forEachChildInTupleType<T>(node: TupleTypeNode, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
711        return visitNodes(cbNode, cbNodes, node.elements);
712    },
713    [SyntaxKind.UnionType]: forEachChildInUnionOrIntersectionType,
714    [SyntaxKind.IntersectionType]: forEachChildInUnionOrIntersectionType,
715    [SyntaxKind.ConditionalType]: function forEachChildInConditionalType<T>(node: ConditionalTypeNode, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
716        return visitNode(cbNode, node.checkType) ||
717            visitNode(cbNode, node.extendsType) ||
718            visitNode(cbNode, node.trueType) ||
719            visitNode(cbNode, node.falseType);
720    },
721    [SyntaxKind.InferType]: function forEachChildInInferType<T>(node: InferTypeNode, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
722        return visitNode(cbNode, node.typeParameter);
723    },
724    [SyntaxKind.ImportType]: function forEachChildInImportType<T>(node: ImportTypeNode, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
725        return visitNode(cbNode, node.argument) ||
726            visitNode(cbNode, node.assertions) ||
727            visitNode(cbNode, node.qualifier) ||
728            visitNodes(cbNode, cbNodes, node.typeArguments);
729    },
730    [SyntaxKind.ImportTypeAssertionContainer]: function forEachChildInImportTypeAssertionContainer<T>(node: ImportTypeAssertionContainer, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
731        return visitNode(cbNode, node.assertClause);
732    },
733    [SyntaxKind.ParenthesizedType]: forEachChildInParenthesizedTypeOrTypeOperator,
734    [SyntaxKind.TypeOperator]: forEachChildInParenthesizedTypeOrTypeOperator,
735    [SyntaxKind.IndexedAccessType]: function forEachChildInIndexedAccessType<T>(node: IndexedAccessTypeNode, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
736        return visitNode(cbNode, node.objectType) ||
737            visitNode(cbNode, node.indexType);
738    },
739    [SyntaxKind.MappedType]: function forEachChildInMappedType<T>(node: MappedTypeNode, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
740        return visitNode(cbNode, node.readonlyToken) ||
741            visitNode(cbNode, node.typeParameter) ||
742            visitNode(cbNode, node.nameType) ||
743            visitNode(cbNode, node.questionToken) ||
744            visitNode(cbNode, node.type) ||
745            visitNodes(cbNode, cbNodes, node.members);
746    },
747    [SyntaxKind.LiteralType]: function forEachChildInLiteralType<T>(node: LiteralTypeNode, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
748        return visitNode(cbNode, node.literal);
749    },
750    [SyntaxKind.NamedTupleMember]: function forEachChildInNamedTupleMember<T>(node: NamedTupleMember, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
751        return visitNode(cbNode, node.dotDotDotToken) ||
752            visitNode(cbNode, node.name) ||
753            visitNode(cbNode, node.questionToken) ||
754            visitNode(cbNode, node.type);
755    },
756    [SyntaxKind.ObjectBindingPattern]: forEachChildInObjectOrArrayBindingPattern,
757    [SyntaxKind.ArrayBindingPattern]: forEachChildInObjectOrArrayBindingPattern,
758    [SyntaxKind.ArrayLiteralExpression]: function forEachChildInArrayLiteralExpression<T>(node: ArrayLiteralExpression, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
759        return visitNodes(cbNode, cbNodes, node.elements);
760    },
761    [SyntaxKind.ObjectLiteralExpression]: function forEachChildInObjectLiteralExpression<T>(node: ObjectLiteralExpression, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
762        return visitNodes(cbNode, cbNodes, node.properties);
763    },
764    [SyntaxKind.PropertyAccessExpression]: function forEachChildInPropertyAccessExpression<T>(node: PropertyAccessExpression, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
765        return visitNode(cbNode, node.expression) ||
766            visitNode(cbNode, node.questionDotToken) ||
767            visitNode(cbNode, node.name);
768    },
769    [SyntaxKind.ElementAccessExpression]: function forEachChildInElementAccessExpression<T>(node: ElementAccessExpression, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
770        return visitNode(cbNode, node.expression) ||
771            visitNode(cbNode, node.questionDotToken) ||
772            visitNode(cbNode, node.argumentExpression);
773    },
774    [SyntaxKind.CallExpression]: forEachChildInCallOrNewExpression,
775    [SyntaxKind.NewExpression]: forEachChildInCallOrNewExpression,
776    [SyntaxKind.TaggedTemplateExpression]: function forEachChildInTaggedTemplateExpression<T>(node: TaggedTemplateExpression, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
777        return visitNode(cbNode, node.tag) ||
778            visitNode(cbNode, node.questionDotToken) ||
779            visitNodes(cbNode, cbNodes, node.typeArguments) ||
780            visitNode(cbNode, node.template);
781    },
782    [SyntaxKind.TypeAssertionExpression]: function forEachChildInTypeAssertionExpression<T>(node: TypeAssertion, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
783        return visitNode(cbNode, node.type) ||
784            visitNode(cbNode, node.expression);
785    },
786    [SyntaxKind.ParenthesizedExpression]: function forEachChildInParenthesizedExpression<T>(node: ParenthesizedExpression, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
787        return visitNode(cbNode, node.expression);
788    },
789    [SyntaxKind.DeleteExpression]: function forEachChildInDeleteExpression<T>(node: DeleteExpression, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
790        return visitNode(cbNode, node.expression);
791    },
792    [SyntaxKind.TypeOfExpression]: function forEachChildInTypeOfExpression<T>(node: TypeOfExpression, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
793        return visitNode(cbNode, node.expression);
794    },
795    [SyntaxKind.VoidExpression]: function forEachChildInVoidExpression<T>(node: VoidExpression, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
796        return visitNode(cbNode, node.expression);
797    },
798    [SyntaxKind.PrefixUnaryExpression]: function forEachChildInPrefixUnaryExpression<T>(node: PrefixUnaryExpression, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
799        return visitNode(cbNode, node.operand);
800    },
801    [SyntaxKind.YieldExpression]: function forEachChildInYieldExpression<T>(node: YieldExpression, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
802        return visitNode(cbNode, node.asteriskToken) ||
803            visitNode(cbNode, node.expression);
804    },
805    [SyntaxKind.AwaitExpression]: function forEachChildInAwaitExpression<T>(node: AwaitExpression, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
806        return visitNode(cbNode, node.expression);
807    },
808    [SyntaxKind.PostfixUnaryExpression]: function forEachChildInPostfixUnaryExpression<T>(node: PostfixUnaryExpression, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
809        return visitNode(cbNode, node.operand);
810    },
811    [SyntaxKind.BinaryExpression]: function forEachChildInBinaryExpression<T>(node: BinaryExpression, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
812        return visitNode(cbNode, node.left) ||
813            visitNode(cbNode, node.operatorToken) ||
814            visitNode(cbNode, node.right);
815    },
816    [SyntaxKind.AsExpression]: function forEachChildInAsExpression<T>(node: AsExpression, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
817        return visitNode(cbNode, node.expression) ||
818            visitNode(cbNode, node.type);
819    },
820    [SyntaxKind.NonNullExpression]: function forEachChildInNonNullExpression<T>(node: NonNullExpression, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
821        return visitNode(cbNode, node.expression);
822    },
823    [SyntaxKind.SatisfiesExpression]: function forEachChildInSatisfiesExpression<T>(node: SatisfiesExpression, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
824        return visitNode(cbNode, node.expression) || visitNode(cbNode, node.type);
825    },
826    [SyntaxKind.MetaProperty]: function forEachChildInMetaProperty<T>(node: MetaProperty, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
827        return visitNode(cbNode, node.name);
828    },
829    [SyntaxKind.ConditionalExpression]: function forEachChildInConditionalExpression<T>(node: ConditionalExpression, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
830        return visitNode(cbNode, node.condition) ||
831            visitNode(cbNode, node.questionToken) ||
832            visitNode(cbNode, node.whenTrue) ||
833            visitNode(cbNode, node.colonToken) ||
834            visitNode(cbNode, node.whenFalse);
835    },
836    [SyntaxKind.SpreadElement]: function forEachChildInSpreadElement<T>(node: SpreadElement, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
837        return visitNode(cbNode, node.expression);
838    },
839    [SyntaxKind.Block]: forEachChildInBlock,
840    [SyntaxKind.ModuleBlock]: forEachChildInBlock,
841    [SyntaxKind.SourceFile]: function forEachChildInSourceFile<T>(node: SourceFile, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
842        return visitNodes(cbNode, cbNodes, node.statements) ||
843            visitNode(cbNode, node.endOfFileToken);
844    },
845    [SyntaxKind.VariableStatement]: function forEachChildInVariableStatement<T>(node: VariableStatement, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
846        return visitNodes(cbNode, cbNodes, node.illegalDecorators) ||
847            visitNodes(cbNode, cbNodes, node.modifiers) ||
848            visitNode(cbNode, node.declarationList);
849    },
850    [SyntaxKind.VariableDeclarationList]: function forEachChildInVariableDeclarationList<T>(node: VariableDeclarationList, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
851        return visitNodes(cbNode, cbNodes, node.declarations);
852    },
853    [SyntaxKind.ExpressionStatement]: function forEachChildInExpressionStatement<T>(node: ExpressionStatement, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
854        return visitNode(cbNode, node.expression);
855    },
856    [SyntaxKind.IfStatement]: function forEachChildInIfStatement<T>(node: IfStatement, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
857        return visitNode(cbNode, node.expression) ||
858            visitNode(cbNode, node.thenStatement) ||
859            visitNode(cbNode, node.elseStatement);
860    },
861    [SyntaxKind.DoStatement]: function forEachChildInDoStatement<T>(node: DoStatement, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
862        return visitNode(cbNode, node.statement) ||
863            visitNode(cbNode, node.expression);
864    },
865    [SyntaxKind.WhileStatement]: function forEachChildInWhileStatement<T>(node: WhileStatement, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
866        return visitNode(cbNode, node.expression) ||
867            visitNode(cbNode, node.statement);
868    },
869    [SyntaxKind.ForStatement]: function forEachChildInForStatement<T>(node: ForStatement, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
870        return visitNode(cbNode, node.initializer) ||
871            visitNode(cbNode, node.condition) ||
872            visitNode(cbNode, node.incrementor) ||
873            visitNode(cbNode, node.statement);
874    },
875    [SyntaxKind.ForInStatement]: function forEachChildInForInStatement<T>(node: ForInStatement, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
876        return visitNode(cbNode, node.initializer) ||
877            visitNode(cbNode, node.expression) ||
878            visitNode(cbNode, node.statement);
879    },
880    [SyntaxKind.ForOfStatement]: function forEachChildInForOfStatement<T>(node: ForOfStatement, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
881        return visitNode(cbNode, node.awaitModifier) ||
882            visitNode(cbNode, node.initializer) ||
883            visitNode(cbNode, node.expression) ||
884            visitNode(cbNode, node.statement);
885    },
886    [SyntaxKind.ContinueStatement]: forEachChildInContinueOrBreakStatement,
887    [SyntaxKind.BreakStatement]: forEachChildInContinueOrBreakStatement,
888    [SyntaxKind.ReturnStatement]: function forEachChildInReturnStatement<T>(node: ReturnStatement, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
889        return visitNode(cbNode, node.expression);
890    },
891    [SyntaxKind.WithStatement]: function forEachChildInWithStatement<T>(node: WithStatement, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
892        return visitNode(cbNode, node.expression) ||
893            visitNode(cbNode, node.statement);
894    },
895    [SyntaxKind.SwitchStatement]: function forEachChildInSwitchStatement<T>(node: SwitchStatement, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
896        return visitNode(cbNode, node.expression) ||
897            visitNode(cbNode, node.caseBlock);
898    },
899    [SyntaxKind.CaseBlock]: function forEachChildInCaseBlock<T>(node: CaseBlock, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
900        return visitNodes(cbNode, cbNodes, node.clauses);
901    },
902    [SyntaxKind.CaseClause]: function forEachChildInCaseClause<T>(node: CaseClause, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
903        return visitNode(cbNode, node.expression) ||
904            visitNodes(cbNode, cbNodes, node.statements);
905    },
906    [SyntaxKind.DefaultClause]: function forEachChildInDefaultClause<T>(node: DefaultClause, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
907        return visitNodes(cbNode, cbNodes, node.statements);
908    },
909    [SyntaxKind.LabeledStatement]: function forEachChildInLabeledStatement<T>(node: LabeledStatement, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
910        return visitNode(cbNode, node.label) ||
911            visitNode(cbNode, node.statement);
912    },
913    [SyntaxKind.ThrowStatement]: function forEachChildInThrowStatement<T>(node: ThrowStatement, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
914        return visitNode(cbNode, node.expression);
915    },
916    [SyntaxKind.TryStatement]: function forEachChildInTryStatement<T>(node: TryStatement, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
917        return visitNode(cbNode, node.tryBlock) ||
918            visitNode(cbNode, node.catchClause) ||
919            visitNode(cbNode, node.finallyBlock);
920    },
921    [SyntaxKind.CatchClause]: function forEachChildInCatchClause<T>(node: CatchClause, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
922        return visitNode(cbNode, node.variableDeclaration) ||
923            visitNode(cbNode, node.block);
924    },
925    [SyntaxKind.Decorator]: function forEachChildInDecorator<T>(node: Decorator, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
926        return visitNode(cbNode, node.expression);
927    },
928    [SyntaxKind.ClassDeclaration]: forEachChildInClassDeclarationOrExpression,
929    [SyntaxKind.ClassExpression]: forEachChildInClassDeclarationOrExpression,
930    [SyntaxKind.StructDeclaration]: forEachChildInClassDeclarationOrExpression,
931    [SyntaxKind.AnnotationDeclaration]: forEachChildInAnnotationDeclaration,
932    [SyntaxKind.InterfaceDeclaration]: function forEachChildInInterfaceDeclaration<T>(node: InterfaceDeclaration, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
933        return visitNodes(cbNode, cbNodes, node.illegalDecorators) ||
934            visitNodes(cbNode, cbNodes, node.modifiers) ||
935            visitNode(cbNode, node.name) ||
936            visitNodes(cbNode, cbNodes, node.typeParameters) ||
937            visitNodes(cbNode, cbNodes, node.heritageClauses) ||
938            visitNodes(cbNode, cbNodes, node.members);
939    },
940    [SyntaxKind.TypeAliasDeclaration]: function forEachChildInTypeAliasDeclaration<T>(node: TypeAliasDeclaration, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
941        return visitNodes(cbNode, cbNodes, node.illegalDecorators) ||
942            visitNodes(cbNode, cbNodes, node.modifiers) ||
943            visitNode(cbNode, node.name) ||
944            visitNodes(cbNode, cbNodes, node.typeParameters) ||
945            visitNode(cbNode, node.type);
946    },
947    [SyntaxKind.EnumDeclaration]: function forEachChildInEnumDeclaration<T>(node: EnumDeclaration, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
948        return visitNodes(cbNode, cbNodes, node.illegalDecorators) ||
949            visitNodes(cbNode, cbNodes, node.modifiers) ||
950            visitNode(cbNode, node.name) ||
951            visitNodes(cbNode, cbNodes, node.members);
952    },
953    [SyntaxKind.EnumMember]: function forEachChildInEnumMember<T>(node: EnumMember, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
954        return visitNode(cbNode, node.name) ||
955            visitNode(cbNode, node.initializer);
956    },
957    [SyntaxKind.ModuleDeclaration]: function forEachChildInModuleDeclaration<T>(node: ModuleDeclaration, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
958        return visitNodes(cbNode, cbNodes, node.illegalDecorators) ||
959            visitNodes(cbNode, cbNodes, node.modifiers) ||
960            visitNode(cbNode, node.name) ||
961            visitNode(cbNode, node.body);
962    },
963    [SyntaxKind.ImportEqualsDeclaration]: function forEachChildInImportEqualsDeclaration<T>(node: ImportEqualsDeclaration, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
964        return visitNodes(cbNode, cbNodes, node.illegalDecorators) ||
965            visitNodes(cbNode, cbNodes, node.modifiers) ||
966            visitNode(cbNode, node.name) ||
967            visitNode(cbNode, node.moduleReference);
968    },
969    [SyntaxKind.ImportDeclaration]: function forEachChildInImportDeclaration<T>(node: ImportDeclaration, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
970        return visitNodes(cbNode, cbNodes, node.illegalDecorators) ||
971            visitNodes(cbNode, cbNodes, node.modifiers) ||
972            visitNode(cbNode, node.importClause) ||
973            visitNode(cbNode, node.moduleSpecifier) ||
974            visitNode(cbNode, node.assertClause);
975    },
976    [SyntaxKind.ImportClause]: function forEachChildInImportClause<T>(node: ImportClause, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
977        return visitNode(cbNode, node.name) ||
978            visitNode(cbNode, node.namedBindings);
979    },
980    [SyntaxKind.AssertClause]: function forEachChildInAssertClause<T>(node: AssertClause, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
981        return visitNodes(cbNode, cbNodes, node.elements);
982    },
983    [SyntaxKind.AssertEntry]: function forEachChildInAssertEntry<T>(node: AssertEntry, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
984        return visitNode(cbNode, node.name) ||
985            visitNode(cbNode, node.value);
986    },
987    [SyntaxKind.NamespaceExportDeclaration]: function forEachChildInNamespaceExportDeclaration<T>(node: NamespaceExportDeclaration, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
988        return visitNodes(cbNode, cbNodes, node.illegalDecorators) ||
989            visitNode(cbNode, node.name);
990    },
991    [SyntaxKind.NamespaceImport]: function forEachChildInNamespaceImport<T>(node: NamespaceImport, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
992        return visitNode(cbNode, node.name);
993    },
994    [SyntaxKind.NamespaceExport]: function forEachChildInNamespaceExport<T>(node: NamespaceExport, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
995        return visitNode(cbNode, node.name);
996    },
997    [SyntaxKind.NamedImports]: forEachChildInNamedImportsOrExports,
998    [SyntaxKind.NamedExports]: forEachChildInNamedImportsOrExports,
999    [SyntaxKind.ExportDeclaration]: function forEachChildInExportDeclaration<T>(node: ExportDeclaration, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
1000        return visitNodes(cbNode, cbNodes, node.illegalDecorators) ||
1001            visitNodes(cbNode, cbNodes, node.modifiers) ||
1002            visitNode(cbNode, node.exportClause) ||
1003            visitNode(cbNode, node.moduleSpecifier) ||
1004            visitNode(cbNode, node.assertClause);
1005    },
1006    [SyntaxKind.ImportSpecifier]: forEachChildInImportOrExportSpecifier,
1007    [SyntaxKind.ExportSpecifier]: forEachChildInImportOrExportSpecifier,
1008    [SyntaxKind.ExportAssignment]: function forEachChildInExportAssignment<T>(node: ExportAssignment, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
1009        return visitNodes(cbNode, cbNodes, node.illegalDecorators) ||
1010            visitNodes(cbNode, cbNodes, node.modifiers) ||
1011            visitNode(cbNode, node.expression);
1012    },
1013    [SyntaxKind.TemplateExpression]: function forEachChildInTemplateExpression<T>(node: TemplateExpression, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
1014        return visitNode(cbNode, node.head) ||
1015            visitNodes(cbNode, cbNodes, node.templateSpans);
1016    },
1017    [SyntaxKind.TemplateSpan]: function forEachChildInTemplateSpan<T>(node: TemplateSpan, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
1018        return visitNode(cbNode, node.expression) ||
1019            visitNode(cbNode, node.literal);
1020    },
1021    [SyntaxKind.TemplateLiteralType]: function forEachChildInTemplateLiteralType<T>(node: TemplateLiteralTypeNode, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
1022        return visitNode(cbNode, node.head) ||
1023            visitNodes(cbNode, cbNodes, node.templateSpans);
1024    },
1025    [SyntaxKind.TemplateLiteralTypeSpan]: function forEachChildInTemplateLiteralTypeSpan<T>(node: TemplateLiteralTypeSpan, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
1026        return visitNode(cbNode, node.type) ||
1027            visitNode(cbNode, node.literal);
1028    },
1029    [SyntaxKind.ComputedPropertyName]: function forEachChildInComputedPropertyName<T>(node: ComputedPropertyName, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
1030        return visitNode(cbNode, node.expression);
1031    },
1032    [SyntaxKind.HeritageClause]: function forEachChildInHeritageClause<T>(node: HeritageClause, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
1033        return visitNodes(cbNode, cbNodes, node.types);
1034    },
1035    [SyntaxKind.ExpressionWithTypeArguments]: function forEachChildInExpressionWithTypeArguments<T>(node: ExpressionWithTypeArguments, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
1036        return visitNode(cbNode, node.expression) ||
1037            visitNodes(cbNode, cbNodes, node.typeArguments);
1038    },
1039    [SyntaxKind.ExternalModuleReference]: function forEachChildInExternalModuleReference<T>(node: ExternalModuleReference, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
1040        return visitNode(cbNode, node.expression);
1041    },
1042    [SyntaxKind.MissingDeclaration]: function forEachChildInMissingDeclaration<T>(node: MissingDeclaration, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
1043        return visitNodes(cbNode, cbNodes, node.illegalDecorators) ||
1044            visitNodes(cbNode, cbNodes, node.modifiers);
1045    },
1046    [SyntaxKind.CommaListExpression]: function forEachChildInCommaListExpression<T>(node: CommaListExpression, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
1047        return visitNodes(cbNode, cbNodes, node.elements);
1048    },
1049    [SyntaxKind.JsxElement]: function forEachChildInJsxElement<T>(node: JsxElement, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
1050        return visitNode(cbNode, node.openingElement) ||
1051            visitNodes(cbNode, cbNodes, node.children) ||
1052            visitNode(cbNode, node.closingElement);
1053    },
1054    [SyntaxKind.JsxFragment]: function forEachChildInJsxFragment<T>(node: JsxFragment, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
1055        return visitNode(cbNode, node.openingFragment) ||
1056            visitNodes(cbNode, cbNodes, node.children) ||
1057            visitNode(cbNode, node.closingFragment);
1058    },
1059    [SyntaxKind.JsxSelfClosingElement]: forEachChildInJsxOpeningOrSelfClosingElement,
1060    [SyntaxKind.JsxOpeningElement]: forEachChildInJsxOpeningOrSelfClosingElement,
1061    [SyntaxKind.JsxAttributes]: function forEachChildInJsxAttributes<T>(node: JsxAttributes, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
1062        return visitNodes(cbNode, cbNodes, node.properties);
1063    },
1064    [SyntaxKind.JsxAttribute]: function forEachChildInJsxAttribute<T>(node: JsxAttribute, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
1065        return visitNode(cbNode, node.name) ||
1066            visitNode(cbNode, node.initializer);
1067    },
1068    [SyntaxKind.JsxSpreadAttribute]: function forEachChildInJsxSpreadAttribute<T>(node: JsxSpreadAttribute, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
1069        return visitNode(cbNode, node.expression);
1070    },
1071    [SyntaxKind.JsxExpression]: function forEachChildInJsxExpression<T>(node: JsxExpression, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
1072        return visitNode(cbNode, node.dotDotDotToken) ||
1073            visitNode(cbNode, node.expression);
1074    },
1075    [SyntaxKind.JsxClosingElement]: function forEachChildInJsxClosingElement<T>(node: JsxClosingElement, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
1076        return visitNode(cbNode, node.tagName);
1077    },
1078    [SyntaxKind.OptionalType]: forEachChildInOptionalRestOrJSDocParameterModifier,
1079    [SyntaxKind.RestType]: forEachChildInOptionalRestOrJSDocParameterModifier,
1080    [SyntaxKind.JSDocTypeExpression]: forEachChildInOptionalRestOrJSDocParameterModifier,
1081    [SyntaxKind.JSDocNonNullableType]: forEachChildInOptionalRestOrJSDocParameterModifier,
1082    [SyntaxKind.JSDocNullableType]: forEachChildInOptionalRestOrJSDocParameterModifier,
1083    [SyntaxKind.JSDocOptionalType]: forEachChildInOptionalRestOrJSDocParameterModifier,
1084    [SyntaxKind.JSDocVariadicType]: forEachChildInOptionalRestOrJSDocParameterModifier,
1085    [SyntaxKind.JSDocFunctionType]: function forEachChildInJSDocFunctionType<T>(node: JSDocFunctionType, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
1086        return visitNodes(cbNode, cbNodes, node.parameters) ||
1087            visitNode(cbNode, node.type);
1088    },
1089    [SyntaxKind.JSDoc]: function forEachChildInJSDoc<T>(node: JSDoc, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
1090        return (typeof node.comment === "string" ? undefined : visitNodes(cbNode, cbNodes, node.comment))
1091            || visitNodes(cbNode, cbNodes, node.tags);
1092    },
1093    [SyntaxKind.JSDocSeeTag]: function forEachChildInJSDocSeeTag<T>(node: JSDocSeeTag, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
1094        return visitNode(cbNode, node.tagName) ||
1095            visitNode(cbNode, node.name) ||
1096            (typeof node.comment === "string" ? undefined : visitNodes(cbNode, cbNodes, node.comment));
1097    },
1098    [SyntaxKind.JSDocNameReference]: function forEachChildInJSDocNameReference<T>(node: JSDocNameReference, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
1099        return visitNode(cbNode, node.name);
1100    },
1101    [SyntaxKind.JSDocMemberName]: function forEachChildInJSDocMemberName<T>(node: JSDocMemberName, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
1102        return visitNode(cbNode, node.left) ||
1103            visitNode(cbNode, node.right);
1104    },
1105    [SyntaxKind.JSDocParameterTag]: forEachChildInJSDocParameterOrPropertyTag,
1106    [SyntaxKind.JSDocPropertyTag]: forEachChildInJSDocParameterOrPropertyTag,
1107    [SyntaxKind.JSDocAuthorTag]: function forEachChildInJSDocAuthorTag<T>(node: JSDocAuthorTag, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
1108        return visitNode(cbNode, node.tagName) ||
1109            (typeof node.comment === "string" ? undefined : visitNodes(cbNode, cbNodes, node.comment));
1110    },
1111    [SyntaxKind.JSDocImplementsTag]: function forEachChildInJSDocImplementsTag<T>(node: JSDocImplementsTag, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
1112        return visitNode(cbNode, node.tagName) ||
1113            visitNode(cbNode, node.class) ||
1114            (typeof node.comment === "string" ? undefined : visitNodes(cbNode, cbNodes, node.comment));
1115    },
1116    [SyntaxKind.JSDocAugmentsTag]: function forEachChildInJSDocAugmentsTag<T>(node: JSDocAugmentsTag, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
1117        return visitNode(cbNode, node.tagName) ||
1118            visitNode(cbNode, node.class) ||
1119            (typeof node.comment === "string" ? undefined : visitNodes(cbNode, cbNodes, node.comment));
1120    },
1121    [SyntaxKind.JSDocTemplateTag]: function forEachChildInJSDocTemplateTag<T>(node: JSDocTemplateTag, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
1122        return visitNode(cbNode, node.tagName) ||
1123            visitNode(cbNode, node.constraint) ||
1124            visitNodes(cbNode, cbNodes, node.typeParameters) ||
1125            (typeof node.comment === "string" ? undefined : visitNodes(cbNode, cbNodes, node.comment));
1126    },
1127    [SyntaxKind.JSDocTypedefTag]: function forEachChildInJSDocTypedefTag<T>(node: JSDocTypedefTag, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
1128        return visitNode(cbNode, node.tagName) ||
1129            (node.typeExpression &&
1130                node.typeExpression.kind === SyntaxKind.JSDocTypeExpression
1131                ? visitNode(cbNode, node.typeExpression) ||
1132                visitNode(cbNode, node.fullName) ||
1133                (typeof node.comment === "string" ? undefined : visitNodes(cbNode, cbNodes, node.comment))
1134                : visitNode(cbNode, node.fullName) ||
1135                visitNode(cbNode, node.typeExpression) ||
1136                (typeof node.comment === "string" ? undefined : visitNodes(cbNode, cbNodes, node.comment)));
1137    },
1138    [SyntaxKind.JSDocCallbackTag]: function forEachChildInJSDocCallbackTag<T>(node: JSDocCallbackTag, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
1139        return visitNode(cbNode, node.tagName) ||
1140            visitNode(cbNode, node.fullName) ||
1141            visitNode(cbNode, node.typeExpression) ||
1142            (typeof node.comment === "string" ? undefined : visitNodes(cbNode, cbNodes, node.comment));
1143    },
1144    [SyntaxKind.JSDocReturnTag]: forEachChildInJSDocReturnTag,
1145    [SyntaxKind.JSDocTypeTag]: forEachChildInJSDocReturnTag,
1146    [SyntaxKind.JSDocThisTag]: forEachChildInJSDocReturnTag,
1147    [SyntaxKind.JSDocEnumTag]: forEachChildInJSDocReturnTag,
1148    [SyntaxKind.JSDocSignature]: function forEachChildInJSDocSignature<T>(node: JSDocSignature, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
1149        return forEach(node.typeParameters, cbNode) ||
1150            forEach(node.parameters, cbNode) ||
1151            visitNode(cbNode, node.type);
1152    },
1153    [SyntaxKind.JSDocLink]: forEachChildInJSDocLinkCodeOrPlain,
1154    [SyntaxKind.JSDocLinkCode]: forEachChildInJSDocLinkCodeOrPlain,
1155    [SyntaxKind.JSDocLinkPlain]: forEachChildInJSDocLinkCodeOrPlain,
1156    [SyntaxKind.JSDocTypeLiteral]: function forEachChildInJSDocTypeLiteral<T>(node: JSDocTypeLiteral, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
1157        return forEach(node.jsDocPropertyTags, cbNode);
1158    },
1159    [SyntaxKind.JSDocTag]: forEachChildInJSDocTag,
1160    [SyntaxKind.JSDocClassTag]: forEachChildInJSDocTag,
1161    [SyntaxKind.JSDocPublicTag]: forEachChildInJSDocTag,
1162    [SyntaxKind.JSDocPrivateTag]: forEachChildInJSDocTag,
1163    [SyntaxKind.JSDocProtectedTag]: forEachChildInJSDocTag,
1164    [SyntaxKind.JSDocReadonlyTag]: forEachChildInJSDocTag,
1165    [SyntaxKind.JSDocDeprecatedTag]: forEachChildInJSDocTag,
1166    [SyntaxKind.JSDocOverrideTag]: forEachChildInJSDocTag,
1167    [SyntaxKind.PartiallyEmittedExpression]: forEachChildInPartiallyEmittedExpression,
1168};
1169
1170// shared
1171
1172function forEachChildInCallOrConstructSignature<T>(node: CallSignatureDeclaration | ConstructSignatureDeclaration, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
1173    return visitNodes(cbNode, cbNodes, node.typeParameters) ||
1174        visitNodes(cbNode, cbNodes, node.parameters) ||
1175        visitNode(cbNode, node.type);
1176}
1177
1178function forEachChildInUnionOrIntersectionType<T>(node: UnionTypeNode | IntersectionTypeNode, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
1179    return visitNodes(cbNode, cbNodes, node.types);
1180}
1181
1182function forEachChildInParenthesizedTypeOrTypeOperator<T>(node: ParenthesizedTypeNode | TypeOperatorNode, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
1183    return visitNode(cbNode, node.type);
1184}
1185
1186function forEachChildInObjectOrArrayBindingPattern<T>(node: BindingPattern, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
1187    return visitNodes(cbNode, cbNodes, node.elements);
1188}
1189
1190function forEachChildInCallOrNewExpression<T>(node: CallExpression | NewExpression, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
1191    return visitNode(cbNode, node.expression) ||
1192        // TODO: should we separate these branches out?
1193        visitNode(cbNode, (node as CallExpression).questionDotToken) ||
1194        visitNodes(cbNode, cbNodes, node.typeArguments) ||
1195        visitNodes(cbNode, cbNodes, node.arguments);
1196}
1197
1198function forEachChildInBlock<T>(node: Block | ModuleBlock, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
1199    return visitNodes(cbNode, cbNodes, node.statements);
1200}
1201
1202function forEachChildInContinueOrBreakStatement<T>(node: ContinueStatement | BreakStatement, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
1203    return visitNode(cbNode, node.label);
1204}
1205
1206function forEachChildInClassDeclarationOrExpression<T>(node: ClassDeclaration | ClassExpression | StructDeclaration, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
1207    return visitNodes(cbNode, cbNodes, node.modifiers) ||
1208        visitNode(cbNode, node.name) ||
1209        visitNodes(cbNode, cbNodes, node.typeParameters) ||
1210        visitNodes(cbNode, cbNodes, node.heritageClauses) ||
1211        visitNodes(cbNode, cbNodes, node.members);
1212}
1213
1214function forEachChildInAnnotationDeclaration<T>(node: AnnotationDeclaration, cbNode: (node: Node) => T | undefined,
1215    cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
1216    return visitNodes(cbNode, cbNodes, node.modifiers) ||
1217        visitNode(cbNode, node.name) ||
1218        visitNodes(cbNode, cbNodes, node.members);
1219}
1220
1221function forEachChildInNamedImportsOrExports<T>(node: NamedImports | NamedExports, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
1222    return visitNodes(cbNode, cbNodes, node.elements);
1223}
1224
1225function forEachChildInImportOrExportSpecifier<T>(node: ImportSpecifier | ExportSpecifier, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
1226    return visitNode(cbNode, node.propertyName) ||
1227        visitNode(cbNode, node.name);
1228}
1229
1230function forEachChildInJsxOpeningOrSelfClosingElement<T>(node: JsxOpeningLikeElement, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
1231    return visitNode(cbNode, node.tagName) ||
1232        visitNodes(cbNode, cbNodes, node.typeArguments) ||
1233        visitNode(cbNode, node.attributes);
1234}
1235
1236function forEachChildInOptionalRestOrJSDocParameterModifier<T>(node: OptionalTypeNode | RestTypeNode | JSDocTypeExpression | JSDocNullableType | JSDocNonNullableType | JSDocOptionalType | JSDocVariadicType, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
1237    return visitNode(cbNode, node.type);
1238}
1239
1240function forEachChildInJSDocParameterOrPropertyTag<T>(node: JSDocParameterTag | JSDocPropertyTag, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
1241    return visitNode(cbNode, node.tagName) ||
1242        (node.isNameFirst
1243            ? visitNode(cbNode, node.name) || visitNode(cbNode, node.typeExpression)
1244            : visitNode(cbNode, node.typeExpression) || visitNode(cbNode, node.name)) ||
1245        (typeof node.comment === "string" ? undefined : visitNodes(cbNode, cbNodes, node.comment));
1246}
1247
1248function forEachChildInJSDocReturnTag<T>(node: JSDocReturnTag | JSDocTypeTag | JSDocThisTag | JSDocEnumTag, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
1249    return visitNode(cbNode, node.tagName) ||
1250        visitNode(cbNode, node.typeExpression) ||
1251        (typeof node.comment === "string" ? undefined : visitNodes(cbNode, cbNodes, node.comment));
1252}
1253
1254function forEachChildInJSDocLinkCodeOrPlain<T>(node: JSDocLink | JSDocLinkCode | JSDocLinkPlain, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
1255    return visitNode(cbNode, node.name);
1256}
1257
1258function forEachChildInJSDocTag<T>(node: JSDocUnknownTag | JSDocClassTag | JSDocPublicTag | JSDocPrivateTag | JSDocProtectedTag | JSDocReadonlyTag | JSDocDeprecatedTag | JSDocOverrideTag, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
1259    return visitNode(cbNode, node.tagName)
1260        || (typeof node.comment === "string" ? undefined : visitNodes(cbNode, cbNodes, node.comment));
1261}
1262
1263function forEachChildInPartiallyEmittedExpression<T>(node: PartiallyEmittedExpression, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
1264    return visitNode(cbNode, node.expression);
1265}
1266
1267/**
1268 * Invokes a callback for each child of the given node. The 'cbNode' callback is invoked for all child nodes
1269 * stored in properties. If a 'cbNodes' callback is specified, it is invoked for embedded arrays; otherwise,
1270 * embedded arrays are flattened and the 'cbNode' callback is invoked for each element. If a callback returns
1271 * a truthy value, iteration stops and that value is returned. Otherwise, undefined is returned.
1272 *
1273 * @param node a given node to visit its children
1274 * @param cbNode a callback to be invoked for all child nodes
1275 * @param cbNodes a callback to be invoked for embedded array
1276 *
1277 * @remarks `forEachChild` must visit the children of a node in the order
1278 * that they appear in the source code. The language service depends on this property to locate nodes by position.
1279 */
1280export function forEachChild<T>(node: Node, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
1281    if (node === undefined || node.kind <= SyntaxKind.LastToken) {
1282        return;
1283    }
1284    const fn = (forEachChildTable as Record<SyntaxKind, ForEachChildFunction<any>>)[node.kind];
1285    return fn === undefined ? undefined : fn(node, cbNode, cbNodes);
1286}
1287
1288/**
1289 * Invokes a callback for each child of the given node. The 'cbNode' callback is invoked for all child nodes
1290 * stored in properties. If a 'cbNodes' callback is specified, it is invoked for embedded arrays; additionally,
1291 * unlike `forEachChild`, embedded arrays are flattened and the 'cbNode' callback is invoked for each element.
1292 *  If a callback returns a truthy value, iteration stops and that value is returned. Otherwise, undefined is returned.
1293 *
1294 * @param node a given node to visit its children
1295 * @param cbNode a callback to be invoked for all child nodes
1296 * @param cbNodes a callback to be invoked for embedded array
1297 *
1298 * @remarks Unlike `forEachChild`, `forEachChildRecursively` handles recursively invoking the traversal on each child node found,
1299 * and while doing so, handles traversing the structure without relying on the callstack to encode the tree structure.
1300 * @internal
1301 */
1302export function forEachChildRecursively<T>(rootNode: Node, cbNode: (node: Node, parent: Node) => T | "skip" | undefined, cbNodes?: (nodes: NodeArray<Node>, parent: Node) => T | "skip" | undefined): T | undefined {
1303    const queue: (Node | NodeArray<Node>)[] = gatherPossibleChildren(rootNode);
1304    const parents: Node[] = []; // tracks parent references for elements in queue
1305    while (parents.length < queue.length) {
1306        parents.push(rootNode);
1307    }
1308    while (queue.length !== 0) {
1309        const current = queue.pop()!;
1310        const parent = parents.pop()!;
1311        if (isArray(current)) {
1312            if (cbNodes) {
1313                const res = cbNodes(current, parent);
1314                if (res) {
1315                    if (res === "skip") continue;
1316                    return res;
1317                }
1318            }
1319            for (let i = current.length - 1; i >= 0; --i) {
1320                queue.push(current[i]);
1321                parents.push(parent);
1322            }
1323        }
1324        else {
1325            const res = cbNode(current, parent);
1326            if (res) {
1327                if (res === "skip") continue;
1328                return res;
1329            }
1330            if (current.kind >= SyntaxKind.FirstNode) {
1331                // add children in reverse order to the queue, so popping gives the first child
1332                for (const child of gatherPossibleChildren(current)) {
1333                    queue.push(child);
1334                    parents.push(current);
1335                }
1336            }
1337        }
1338    }
1339}
1340
1341function gatherPossibleChildren(node: Node) {
1342    const children: (Node | NodeArray<Node>)[] = [];
1343    forEachChild(node, addWorkItem, addWorkItem); // By using a stack above and `unshift` here, we emulate a depth-first preorder traversal
1344    return children;
1345
1346    function addWorkItem(n: Node | NodeArray<Node>) {
1347        children.unshift(n);
1348    }
1349}
1350
1351export interface CreateSourceFileOptions {
1352    languageVersion: ScriptTarget;
1353    /**
1354     * Controls the format the file is detected as - this can be derived from only the path
1355     * and files on disk, but needs to be done with a module resolution cache in scope to be performant.
1356     * This is usually `undefined` for compilations that do not have `moduleResolution` values of `node16` or `nodenext`.
1357     */
1358    impliedNodeFormat?: ModuleKind.ESNext | ModuleKind.CommonJS;
1359    /**
1360     * Controls how module-y-ness is set for the given file. Usually the result of calling
1361     * `getSetExternalModuleIndicator` on a valid `CompilerOptions` object. If not present, the default
1362     * check specified by `isFileProbablyExternalModule` will be used to set the field.
1363     */
1364    setExternalModuleIndicator?: (file: SourceFile) => void;
1365    /** @internal */ packageJsonLocations?: readonly string[];
1366    /** @internal */ packageJsonScope?: PackageJsonInfo;
1367}
1368
1369function setExternalModuleIndicator(sourceFile: SourceFile) {
1370    sourceFile.externalModuleIndicator = isFileProbablyExternalModule(sourceFile);
1371}
1372
1373let sourceFileCompilerOptions: CompilerOptions;
1374let isArkguardInputSourceFile: boolean = false;
1375export function createSourceFile(fileName: string, sourceText: string, languageVersionOrOptions: ScriptTarget | CreateSourceFileOptions, setParentNodes = false, scriptKind?: ScriptKind, options?: CompilerOptions, isArkguardInput?: boolean): SourceFile {
1376    tracing?.push(tracing.Phase.Parse, "createSourceFile", { path: fileName }, /*separateBeginAndEnd*/ true);
1377    const recordInfo = MemoryDotting.recordStage(MemoryDotting.CREATE_SORUCE_FILE_PARSE);
1378    performance.mark("beforeParse");
1379    let result: SourceFile;
1380    sourceFileCompilerOptions = options ?? defaultInitCompilerOptions;
1381    isArkguardInputSourceFile = isArkguardInput ?? false;
1382    perfLogger.logStartParseSourceFile(fileName);
1383    const {
1384        languageVersion,
1385        setExternalModuleIndicator: overrideSetExternalModuleIndicator,
1386        impliedNodeFormat: format
1387    } = typeof languageVersionOrOptions === "object" ? languageVersionOrOptions : ({ languageVersion: languageVersionOrOptions } as CreateSourceFileOptions);
1388    if (languageVersion === ScriptTarget.JSON) {
1389        result = Parser.parseSourceFile(fileName, sourceText, languageVersion, /*syntaxCursor*/ undefined, setParentNodes, ScriptKind.JSON, noop);
1390    }
1391    else {
1392        const setIndicator = format === undefined ? overrideSetExternalModuleIndicator : (file: SourceFile) => {
1393            file.impliedNodeFormat = format;
1394            return (overrideSetExternalModuleIndicator || setExternalModuleIndicator)(file);
1395        };
1396        result = Parser.parseSourceFile(fileName, sourceText, languageVersion, /*syntaxCursor*/ undefined, setParentNodes, scriptKind, setIndicator);
1397    }
1398    perfLogger.logStopParseSourceFile();
1399
1400    performance.mark("afterParse");
1401    MemoryDotting.stopRecordStage(recordInfo);
1402    performance.measure("Parse", "beforeParse", "afterParse");
1403    tracing?.pop();
1404    return result;
1405}
1406
1407export function parseIsolatedEntityName(text: string, languageVersion: ScriptTarget): EntityName | undefined {
1408    return Parser.parseIsolatedEntityName(text, languageVersion);
1409}
1410
1411/**
1412 * Parse json text into SyntaxTree and return node and parse errors if any
1413 * @param fileName
1414 * @param sourceText
1415 */
1416export function parseJsonText(fileName: string, sourceText: string): JsonSourceFile {
1417    return Parser.parseJsonText(fileName, sourceText);
1418}
1419
1420// See also `isExternalOrCommonJsModule` in utilities.ts
1421export function isExternalModule(file: SourceFile): boolean {
1422    return file.externalModuleIndicator !== undefined;
1423}
1424
1425// Produces a new SourceFile for the 'newText' provided. The 'textChangeRange' parameter
1426// indicates what changed between the 'text' that this SourceFile has and the 'newText'.
1427// The SourceFile will be created with the compiler attempting to reuse as many nodes from
1428// this file as possible.
1429//
1430// Note: this function mutates nodes from this SourceFile. That means any existing nodes
1431// from this SourceFile that are being held onto may change as a result (including
1432// becoming detached from any SourceFile).  It is recommended that this SourceFile not
1433// be used once 'update' is called on it.
1434export function updateSourceFile(sourceFile: SourceFile, newText: string, textChangeRange: TextChangeRange, aggressiveChecks = false, option?: CompilerOptions): SourceFile {
1435    sourceFileCompilerOptions = option ?? defaultInitCompilerOptions;
1436    const newSourceFile = IncrementalParser.updateSourceFile(sourceFile, newText, textChangeRange, aggressiveChecks);
1437    // Because new source file node is created, it may not have the flag PossiblyContainDynamicImport. This is the case if there is no new edit to add dynamic import.
1438    // We will manually port the flag to the new source file.
1439    (newSourceFile as Mutable<SourceFile>).flags |= (sourceFile.flags & NodeFlags.PermanentlySetIncrementalFlags);
1440    return newSourceFile;
1441}
1442
1443/** @internal */
1444export function parseIsolatedJSDocComment(content: string, start?: number, length?: number) {
1445    const result = Parser.JSDocParser.parseIsolatedJSDocComment(content, start, length);
1446    if (result && result.jsDoc) {
1447        // because the jsDocComment was parsed out of the source file, it might
1448        // not be covered by the fixupParentReferences.
1449        Parser.fixupParentReferences(result.jsDoc);
1450    }
1451
1452    return result;
1453}
1454
1455/** @internal */
1456// Exposed only for testing.
1457export function parseJSDocTypeExpressionForTests(content: string, start?: number, length?: number) {
1458    return Parser.JSDocParser.parseJSDocTypeExpressionForTests(content, start, length);
1459}
1460
1461// Set language version: ArkTS 1.1、1.2
1462let languageVersionCallBack: ((filePath: string) => boolean) | undefined;
1463export function setLanguageVersionByFilePath(getLanguageVersion: ((filePath: string) => boolean) | undefined): void {
1464    languageVersionCallBack = getLanguageVersion;
1465}
1466
1467// Implement the parser as a singleton module.  We do this for perf reasons because creating
1468// parser instances can actually be expensive enough to impact us on projects with many source
1469// files.
1470namespace Parser {
1471    /* eslint-disable no-var */
1472
1473    // Share a single scanner across all calls to parse a source file.  This helps speed things
1474    // up by avoiding the cost of creating/compiling scanners over and over again.
1475    var scanner = createScanner(ScriptTarget.Latest, /*skipTrivia*/ true);
1476
1477    var disallowInAndDecoratorContext = NodeFlags.DisallowInContext | NodeFlags.DecoratorContext;
1478
1479    // capture constructors in 'initializeState' to avoid null checks
1480    var NodeConstructor: new (kind: SyntaxKind, pos: number, end: number) => Node;
1481    var TokenConstructor: new (kind: SyntaxKind, pos: number, end: number) => Node;
1482    var IdentifierConstructor: new (kind: SyntaxKind, pos: number, end: number) => Node;
1483    var PrivateIdentifierConstructor: new (kind: SyntaxKind, pos: number, end: number) => Node;
1484    var SourceFileConstructor: new (kind: SyntaxKind, pos: number, end: number) => Node;
1485
1486    function countNode(node: Node) {
1487        nodeCount++;
1488        return node;
1489    }
1490
1491    // Rather than using `createBaseNodeFactory` here, we establish a `BaseNodeFactory` that closes over the
1492    // constructors above, which are reset each time `initializeState` is called.
1493    var baseNodeFactory: BaseNodeFactory = {
1494        createBaseSourceFileNode: kind => countNode(new SourceFileConstructor(kind, /*pos*/ 0, /*end*/ 0)),
1495        createBaseIdentifierNode: kind => countNode(new IdentifierConstructor(kind, /*pos*/ 0, /*end*/ 0)),
1496        createBasePrivateIdentifierNode: kind => countNode(new PrivateIdentifierConstructor(kind, /*pos*/ 0, /*end*/ 0)),
1497        createBaseTokenNode: kind => countNode(new TokenConstructor(kind, /*pos*/ 0, /*end*/ 0)),
1498        createBaseNode: kind => countNode(new NodeConstructor(kind, /*pos*/ 0, /*end*/ 0))
1499    };
1500
1501    var factory = createNodeFactory(NodeFactoryFlags.NoParenthesizerRules | NodeFactoryFlags.NoNodeConverters | NodeFactoryFlags.NoOriginalNode, baseNodeFactory);
1502
1503    var fileName: string;
1504    var sourceFlags: NodeFlags;
1505    var sourceText: string;
1506    var languageVersion: ScriptTarget;
1507    var scriptKind: ScriptKind;
1508    var languageVariant: LanguageVariant;
1509    var parseDiagnostics: DiagnosticWithDetachedLocation[];
1510    var jsDocDiagnostics: DiagnosticWithDetachedLocation[];
1511    var syntaxCursor: IncrementalParser.SyntaxCursor | undefined;
1512
1513    var currentToken: SyntaxKind;
1514    var nodeCount: number;
1515    var identifiers: ESMap<string, string>;
1516    var privateIdentifiers: ESMap<string, string>;
1517    var identifierCount: number;
1518
1519    var parsingContext: ParsingContext;
1520
1521    var notParenthesizedArrow: Set<number> | undefined;
1522
1523    // Flags that dictate what parsing context we're in.  For example:
1524    // Whether or not we are in strict parsing mode.  All that changes in strict parsing mode is
1525    // that some tokens that would be considered identifiers may be considered keywords.
1526    //
1527    // When adding more parser context flags, consider which is the more common case that the
1528    // flag will be in.  This should be the 'false' state for that flag.  The reason for this is
1529    // that we don't store data in our nodes unless the value is in the *non-default* state.  So,
1530    // for example, more often than code 'allows-in' (or doesn't 'disallow-in').  We opt for
1531    // 'disallow-in' set to 'false'.  Otherwise, if we had 'allowsIn' set to 'true', then almost
1532    // all nodes would need extra state on them to store this info.
1533    //
1534    // Note: 'allowIn' and 'allowYield' track 1:1 with the [in] and [yield] concepts in the ES6
1535    // grammar specification.
1536    //
1537    // An important thing about these context concepts.  By default they are effectively inherited
1538    // while parsing through every grammar production.  i.e. if you don't change them, then when
1539    // you parse a sub-production, it will have the same context values as the parent production.
1540    // This is great most of the time.  After all, consider all the 'expression' grammar productions
1541    // and how nearly all of them pass along the 'in' and 'yield' context values:
1542    //
1543    // EqualityExpression[In, Yield] :
1544    //      RelationalExpression[?In, ?Yield]
1545    //      EqualityExpression[?In, ?Yield] == RelationalExpression[?In, ?Yield]
1546    //      EqualityExpression[?In, ?Yield] != RelationalExpression[?In, ?Yield]
1547    //      EqualityExpression[?In, ?Yield] === RelationalExpression[?In, ?Yield]
1548    //      EqualityExpression[?In, ?Yield] !== RelationalExpression[?In, ?Yield]
1549    //
1550    // Where you have to be careful is then understanding what the points are in the grammar
1551    // where the values are *not* passed along.  For example:
1552    //
1553    // SingleNameBinding[Yield,GeneratorParameter]
1554    //      [+GeneratorParameter]BindingIdentifier[Yield] Initializer[In]opt
1555    //      [~GeneratorParameter]BindingIdentifier[?Yield]Initializer[In, ?Yield]opt
1556    //
1557    // Here this is saying that if the GeneratorParameter context flag is set, that we should
1558    // explicitly set the 'yield' context flag to false before calling into the BindingIdentifier
1559    // and we should explicitly unset the 'yield' context flag before calling into the Initializer.
1560    // production.  Conversely, if the GeneratorParameter context flag is not set, then we
1561    // should leave the 'yield' context flag alone.
1562    //
1563    // Getting this all correct is tricky and requires careful reading of the grammar to
1564    // understand when these values should be changed versus when they should be inherited.
1565    //
1566    // Note: it should not be necessary to save/restore these flags during speculative/lookahead
1567    // parsing.  These context flags are naturally stored and restored through normal recursive
1568    // descent parsing and unwinding.
1569    var contextFlags: NodeFlags;
1570
1571    var etsFlags: EtsFlags;
1572
1573    // Indicates whether we are currently parsing top-level statements.
1574    var topLevel = true;
1575
1576    // Whether or not we've had a parse error since creating the last AST node.  If we have
1577    // encountered an error, it will be stored on the next AST node we create.  Parse errors
1578    // can be broken down into three categories:
1579    //
1580    // 1) An error that occurred during scanning.  For example, an unterminated literal, or a
1581    //    character that was completely not understood.
1582    //
1583    // 2) A token was expected, but was not present.  This type of error is commonly produced
1584    //    by the 'parseExpected' function.
1585    //
1586    // 3) A token was present that no parsing function was able to consume.  This type of error
1587    //    only occurs in the 'abortParsingListOrMoveToNextToken' function when the parser
1588    //    decides to skip the token.
1589    //
1590    // In all of these cases, we want to mark the next node as having had an error before it.
1591    // With this mark, we can know in incremental settings if this node can be reused, or if
1592    // we have to reparse it.  If we don't keep this information around, we may just reuse the
1593    // node.  in that event we would then not produce the same errors as we did before, causing
1594    // significant confusion problems.
1595    //
1596    // Note: it is necessary that this value be saved/restored during speculative/lookahead
1597    // parsing.  During lookahead parsing, we will often create a node.  That node will have
1598    // this value attached, and then this value will be set back to 'false'.  If we decide to
1599    // rewind, we must get back to the same value we had prior to the lookahead.
1600    //
1601    // Note: any errors at the end of the file that do not precede a regular node, should get
1602    // attached to the EOF token.
1603    var parseErrorBeforeNextFinishedNode = false;
1604
1605    var extendEtsComponentDeclaration: { name: string, type: string, instance: string } | undefined;
1606
1607    var stylesEtsComponentDeclaration: { name: string, type: string, instance: string } | undefined;
1608
1609    // A map to record file scope '@styles' function name
1610    var fileStylesComponents = new Map<string, SyntaxKind>();
1611
1612    var currentStructName: string | undefined;
1613
1614    var stateStylesRootNode: string | undefined;
1615
1616    // A map to record struct scope '@styles' method name
1617    var structStylesComponents = new Map<string, { structName: string, kind: SyntaxKind }>();
1618    /* eslint-enable no-var */
1619
1620    export function parseSourceFile(fileName: string, sourceText: string, languageVersion: ScriptTarget, syntaxCursor: IncrementalParser.SyntaxCursor | undefined, setParentNodes = false, scriptKind?: ScriptKind, setExternalModuleIndicatorOverride?: (file: SourceFile) => void): SourceFile {
1621        scriptKind = ensureScriptKind(fileName, scriptKind);
1622        if (scriptKind === ScriptKind.JSON) {
1623            const result = parseJsonText(fileName, sourceText, languageVersion, syntaxCursor, setParentNodes);
1624            convertToObjectWorker(result, result.statements[0]?.expression, result.parseDiagnostics, /*returnValue*/ false, /*knownRootOptions*/ undefined, /*jsonConversionNotifier*/ undefined);
1625            result.referencedFiles = emptyArray;
1626            result.typeReferenceDirectives = emptyArray;
1627            result.libReferenceDirectives = emptyArray;
1628            result.amdDependencies = emptyArray;
1629            result.hasNoDefaultLib = false;
1630            result.pragmas = emptyMap as ReadonlyPragmaMap;
1631            return result;
1632        }
1633
1634        initializeState(fileName, sourceText, languageVersion, syntaxCursor, scriptKind);
1635
1636        const result = parseSourceFileWorker(languageVersion, setParentNodes, scriptKind, setExternalModuleIndicatorOverride || setExternalModuleIndicator);
1637
1638        clearState();
1639
1640        return result;
1641    }
1642
1643    export function parseIsolatedEntityName(content: string, languageVersion: ScriptTarget): EntityName | undefined {
1644        // Choice of `isDeclarationFile` should be arbitrary
1645        initializeState("", content, languageVersion, /*syntaxCursor*/ undefined, ScriptKind.JS);
1646        // Prime the scanner.
1647        nextToken();
1648        const entityName = parseEntityName(/*allowReservedWords*/ true);
1649        const isInvalid = token() === SyntaxKind.EndOfFileToken && !parseDiagnostics.length;
1650        clearState();
1651        return isInvalid ? entityName : undefined;
1652    }
1653
1654    export function parseJsonText(fileName: string, sourceText: string, languageVersion: ScriptTarget = ScriptTarget.ES2015, syntaxCursor?: IncrementalParser.SyntaxCursor, setParentNodes = false): JsonSourceFile {
1655        initializeState(fileName, sourceText, languageVersion, syntaxCursor, ScriptKind.JSON);
1656        sourceFlags = contextFlags;
1657
1658        // Prime the scanner.
1659        nextToken();
1660        const pos = getNodePos();
1661        let statements, endOfFileToken;
1662        if (token() === SyntaxKind.EndOfFileToken) {
1663            statements = createNodeArray([], pos, pos);
1664            endOfFileToken = parseTokenNode<EndOfFileToken>();
1665        }
1666        else {
1667            // Loop and synthesize an ArrayLiteralExpression if there are more than
1668            // one top-level expressions to ensure all input text is consumed.
1669            let expressions: Expression[] | Expression | undefined;
1670            while (token() !== SyntaxKind.EndOfFileToken) {
1671                let expression;
1672                switch (token()) {
1673                    case SyntaxKind.OpenBracketToken:
1674                        expression = parseArrayLiteralExpression();
1675                        break;
1676                    case SyntaxKind.TrueKeyword:
1677                    case SyntaxKind.FalseKeyword:
1678                    case SyntaxKind.NullKeyword:
1679                        expression = parseTokenNode<BooleanLiteral | NullLiteral>();
1680                        break;
1681                    case SyntaxKind.MinusToken:
1682                        if (lookAhead(() => nextToken() === SyntaxKind.NumericLiteral && nextToken() !== SyntaxKind.ColonToken)) {
1683                            expression = parsePrefixUnaryExpression() as JsonMinusNumericLiteral;
1684                        }
1685                        else {
1686                            expression = parseObjectLiteralExpression();
1687                        }
1688                        break;
1689                    case SyntaxKind.NumericLiteral:
1690                    case SyntaxKind.StringLiteral:
1691                        if (lookAhead(() => nextToken() !== SyntaxKind.ColonToken)) {
1692                            expression = parseLiteralNode() as StringLiteral | NumericLiteral;
1693                            break;
1694                        }
1695                        // falls through
1696                    default:
1697                        expression = parseObjectLiteralExpression();
1698                        break;
1699                }
1700
1701                // Error recovery: collect multiple top-level expressions
1702                if (expressions && isArray(expressions)) {
1703                    expressions.push(expression);
1704                }
1705                else if (expressions) {
1706                    expressions = [expressions, expression];
1707                }
1708                else {
1709                    expressions = expression;
1710                    if (token() !== SyntaxKind.EndOfFileToken) {
1711                        parseErrorAtCurrentToken(Diagnostics.Unexpected_token);
1712                    }
1713                }
1714            }
1715
1716            const expression = isArray(expressions) ? finishNode(factory.createArrayLiteralExpression(expressions), pos) : Debug.checkDefined(expressions);
1717            const statement = factory.createExpressionStatement(expression) as JsonObjectExpressionStatement;
1718            finishNode(statement, pos);
1719            statements = createNodeArray([statement], pos);
1720            endOfFileToken = parseExpectedToken(SyntaxKind.EndOfFileToken, Diagnostics.Unexpected_token);
1721        }
1722
1723        // Set source file so that errors will be reported with this file name
1724        const sourceFile = createSourceFile(fileName, ScriptTarget.ES2015, ScriptKind.JSON, /*isDeclaration*/ false, statements, endOfFileToken, sourceFlags, noop);
1725
1726        if (setParentNodes) {
1727            fixupParentReferences(sourceFile);
1728        }
1729
1730        sourceFile.nodeCount = nodeCount;
1731        sourceFile.identifierCount = identifierCount;
1732        sourceFile.identifiers = identifiers;
1733        sourceFile.parseDiagnostics = attachFileToDiagnostics(parseDiagnostics, sourceFile);
1734        if (jsDocDiagnostics) {
1735            sourceFile.jsDocDiagnostics = attachFileToDiagnostics(jsDocDiagnostics, sourceFile);
1736        }
1737
1738        const result = sourceFile as JsonSourceFile;
1739        clearState();
1740        return result;
1741    }
1742
1743    function initializeState(_fileName: string, _sourceText: string, _languageVersion: ScriptTarget, _syntaxCursor: IncrementalParser.SyntaxCursor | undefined, _scriptKind: ScriptKind) {
1744        NodeConstructor = objectAllocator.getNodeConstructor();
1745        TokenConstructor = objectAllocator.getTokenConstructor();
1746        IdentifierConstructor = objectAllocator.getIdentifierConstructor();
1747        PrivateIdentifierConstructor = objectAllocator.getPrivateIdentifierConstructor();
1748        SourceFileConstructor = objectAllocator.getSourceFileConstructor();
1749
1750        fileName = normalizePath(_fileName);
1751        sourceText = _sourceText;
1752        languageVersion = _languageVersion;
1753        syntaxCursor = _syntaxCursor;
1754        scriptKind = _scriptKind;
1755        languageVariant = getLanguageVariant(_scriptKind);
1756
1757        parseDiagnostics = [];
1758        parsingContext = 0;
1759        identifiers = new Map<string, string>();
1760        privateIdentifiers = new Map<string, string>();
1761        identifierCount = 0;
1762        nodeCount = 0;
1763        sourceFlags = 0;
1764        topLevel = true;
1765
1766        switch (scriptKind) {
1767            case ScriptKind.JS:
1768            case ScriptKind.JSX:
1769                contextFlags = NodeFlags.JavaScriptFile;
1770                break;
1771            case ScriptKind.JSON:
1772                contextFlags = NodeFlags.JavaScriptFile | NodeFlags.JsonFile;
1773                break;
1774            case ScriptKind.ETS:
1775                contextFlags = NodeFlags.EtsContext;
1776                break;
1777            default:
1778                contextFlags = NodeFlags.None;
1779                break;
1780        }
1781        if (fileName.endsWith(Extension.Ets)) {
1782            contextFlags = NodeFlags.EtsContext;
1783        }
1784        parseErrorBeforeNextFinishedNode = false;
1785
1786        // Initialize and prime the scanner before parsing the source elements.
1787        scanner.setText(sourceText);
1788        scanner.setOnError(scanError);
1789        scanner.setScriptTarget(languageVersion);
1790        scanner.setLanguageVariant(languageVariant);
1791        scanner.setEtsContext(inEtsContext());
1792    }
1793
1794    function clearState() {
1795        // Clear out the text the scanner is pointing at, so it doesn't keep anything alive unnecessarily.
1796        scanner.clearCommentDirectives();
1797        scanner.setText("");
1798        scanner.setOnError(undefined);
1799        scanner.setEtsContext(false);
1800        // Clear any data.  We don't want to accidentally hold onto it for too long.
1801        sourceText = undefined!;
1802        languageVersion = undefined!;
1803        syntaxCursor = undefined;
1804        scriptKind = undefined!;
1805        languageVariant = undefined!;
1806        sourceFlags = 0;
1807        parseDiagnostics = undefined!;
1808        jsDocDiagnostics = undefined!;
1809        parsingContext = 0;
1810        identifiers = undefined!;
1811        notParenthesizedArrow = undefined;
1812        topLevel = true;
1813        extendEtsComponentDeclaration = undefined;
1814        stylesEtsComponentDeclaration = undefined;
1815        stateStylesRootNode = undefined;
1816        fileStylesComponents.clear();
1817        structStylesComponents.clear();
1818    }
1819
1820    function parseSourceFileWorker(languageVersion: ScriptTarget, setParentNodes: boolean, scriptKind: ScriptKind, setExternalModuleIndicator: (file: SourceFile) => void): SourceFile {
1821        const isDeclarationFile = isDeclarationFileName(fileName);
1822        if (isDeclarationFile) {
1823            contextFlags |= NodeFlags.Ambient;
1824        }
1825
1826        sourceFlags = contextFlags;
1827
1828        // Prime the scanner.
1829        nextToken();
1830
1831        let statements = parseList(ParsingContext.SourceElements, parseStatement);
1832        const markedkitImportRanges = new Array<TextRange>();
1833        const sdkPath = getSdkPath(sourceFileCompilerOptions);
1834        // When the language version is 1.2, skip processKit
1835        statements = (!!sourceFileCompilerOptions.noTransformedKitInParser || !sdkPath || parseDiagnostics.length || languageVersionCallBack?.(fileName)) ?
1836            statements :
1837            createNodeArray(processKit(factory, statements, sdkPath, markedkitImportRanges, inEtsContext(), sourceFileCompilerOptions), statements.pos);
1838        Debug.assert(token() === SyntaxKind.EndOfFileToken);
1839        const endOfFileToken = addJSDocComment(parseTokenNode<EndOfFileToken>());
1840
1841        const sourceFile = createSourceFile(fileName, languageVersion, scriptKind, isDeclarationFile, statements, endOfFileToken, sourceFlags, setExternalModuleIndicator);
1842        if (markedkitImportRanges.length > 0) {
1843            sourceFile.markedKitImportRange = markedkitImportRanges;
1844        }
1845
1846        // A member of ReadonlyArray<T> isn't assignable to a member of T[] (and prevents a direct cast) - but this is where we set up those members so they can be readonly in the future
1847        processCommentPragmas(sourceFile as {} as PragmaContext, sourceText);
1848        processPragmasIntoFields(sourceFile as {} as PragmaContext, reportPragmaDiagnostic);
1849
1850        sourceFile.commentDirectives = scanner.getCommentDirectives();
1851        sourceFile.nodeCount = nodeCount;
1852        sourceFile.identifierCount = identifierCount;
1853        sourceFile.identifiers = identifiers;
1854        sourceFile.parseDiagnostics = attachFileToDiagnostics(parseDiagnostics, sourceFile);
1855        if (jsDocDiagnostics) {
1856            sourceFile.jsDocDiagnostics = attachFileToDiagnostics(jsDocDiagnostics, sourceFile);
1857        }
1858
1859        if (setParentNodes) {
1860            fixupParentReferences(sourceFile);
1861        }
1862
1863        return sourceFile;
1864
1865        function reportPragmaDiagnostic(pos: number, end: number, diagnostic: DiagnosticMessage) {
1866            parseDiagnostics.push(createDetachedDiagnostic(fileName, pos, end, diagnostic));
1867        }
1868    }
1869
1870    function withJSDoc<T extends HasJSDoc>(node: T, hasJSDoc: boolean): T {
1871        return hasJSDoc ? addJSDocComment(node) : node;
1872    }
1873
1874    let hasDeprecatedTag = false;
1875    function addJSDocComment<T extends HasJSDoc>(node: T): T {
1876        Debug.assert(!node.jsDoc); // Should only be called once per node
1877        const jsDoc = mapDefined(getJSDocCommentRanges(node, sourceText), comment => JSDocParser.parseJSDocComment(node, comment.pos, comment.end - comment.pos));
1878        if (jsDoc.length) node.jsDoc = jsDoc;
1879        if (hasDeprecatedTag) {
1880            hasDeprecatedTag = false;
1881            (node as Mutable<T>).flags |= NodeFlags.Deprecated;
1882        }
1883        return node;
1884    }
1885
1886    function reparseTopLevelAwait(sourceFile: SourceFile) {
1887        const savedSyntaxCursor = syntaxCursor;
1888        const baseSyntaxCursor = IncrementalParser.createSyntaxCursor(sourceFile);
1889        syntaxCursor = { currentNode };
1890
1891        const statements: Statement[] = [];
1892        const savedParseDiagnostics = parseDiagnostics;
1893
1894        parseDiagnostics = [];
1895
1896        let pos = 0;
1897        let start = findNextStatementWithAwait(sourceFile.statements, 0);
1898        while (start !== -1) {
1899            // append all statements between pos and start
1900            const prevStatement = sourceFile.statements[pos];
1901            const nextStatement = sourceFile.statements[start];
1902            addRange(statements, sourceFile.statements, pos, start);
1903            pos = findNextStatementWithoutAwait(sourceFile.statements, start);
1904
1905            // append all diagnostics associated with the copied range
1906            const diagnosticStart = findIndex(savedParseDiagnostics, diagnostic => diagnostic.start >= prevStatement.pos);
1907            const diagnosticEnd = diagnosticStart >= 0 ? findIndex(savedParseDiagnostics, diagnostic => diagnostic.start >= nextStatement.pos, diagnosticStart) : -1;
1908            if (diagnosticStart >= 0) {
1909                addRange(parseDiagnostics, savedParseDiagnostics, diagnosticStart, diagnosticEnd >= 0 ? diagnosticEnd : undefined);
1910            }
1911
1912            // reparse all statements between start and pos. We skip existing diagnostics for the same range and allow the parser to generate new ones.
1913            speculationHelper(() => {
1914                const savedContextFlags = contextFlags;
1915                contextFlags |= NodeFlags.AwaitContext;
1916                scanner.setTextPos(nextStatement.pos);
1917                nextToken();
1918
1919                while (token() !== SyntaxKind.EndOfFileToken) {
1920                    const startPos = scanner.getStartPos();
1921                    const statement = parseListElement(ParsingContext.SourceElements, parseStatement);
1922                    statements.push(statement);
1923                    if (startPos === scanner.getStartPos()) {
1924                        nextToken();
1925                    }
1926
1927                    if (pos >= 0) {
1928                        const nonAwaitStatement = sourceFile.statements[pos];
1929                        if (statement.end === nonAwaitStatement.pos) {
1930                            // done reparsing this section
1931                            break;
1932                        }
1933                        if (statement.end > nonAwaitStatement.pos) {
1934                            // we ate into the next statement, so we must reparse it.
1935                            pos = findNextStatementWithoutAwait(sourceFile.statements, pos + 1);
1936                        }
1937                    }
1938                }
1939
1940                contextFlags = savedContextFlags;
1941            }, SpeculationKind.Reparse);
1942
1943            // find the next statement containing an `await`
1944            start = pos >= 0 ? findNextStatementWithAwait(sourceFile.statements, pos) : -1;
1945        }
1946
1947        // append all statements between pos and the end of the list
1948        if (pos >= 0) {
1949            const prevStatement = sourceFile.statements[pos];
1950            addRange(statements, sourceFile.statements, pos);
1951
1952            // append all diagnostics associated with the copied range
1953            const diagnosticStart = findIndex(savedParseDiagnostics, diagnostic => diagnostic.start >= prevStatement.pos);
1954            if (diagnosticStart >= 0) {
1955                addRange(parseDiagnostics, savedParseDiagnostics, diagnosticStart);
1956            }
1957        }
1958
1959        syntaxCursor = savedSyntaxCursor;
1960        return factory.updateSourceFile(sourceFile, setTextRange(factory.createNodeArray(statements), sourceFile.statements));
1961
1962        function containsPossibleTopLevelAwait(node: Node) {
1963            return !(node.flags & NodeFlags.AwaitContext)
1964                && !!(node.transformFlags & TransformFlags.ContainsPossibleTopLevelAwait);
1965        }
1966
1967        function findNextStatementWithAwait(statements: NodeArray<Statement>, start: number) {
1968            for (let i = start; i < statements.length; i++) {
1969                if (containsPossibleTopLevelAwait(statements[i])) {
1970                    return i;
1971                }
1972            }
1973            return -1;
1974        }
1975
1976        function findNextStatementWithoutAwait(statements: NodeArray<Statement>, start: number) {
1977            for (let i = start; i < statements.length; i++) {
1978                if (!containsPossibleTopLevelAwait(statements[i])) {
1979                    return i;
1980                }
1981            }
1982            return -1;
1983        }
1984
1985        function currentNode(position: number) {
1986            const node = baseSyntaxCursor.currentNode(position);
1987            if (topLevel && node && containsPossibleTopLevelAwait(node)) {
1988                node.intersectsChange = true;
1989            }
1990            return node;
1991        }
1992
1993    }
1994
1995    export function fixupParentReferences(rootNode: Node) {
1996        // normally parent references are set during binding. However, for clients that only need
1997        // a syntax tree, and no semantic features, then the binding process is an unnecessary
1998        // overhead.  This functions allows us to set all the parents, without all the expense of
1999        // binding.
2000        setParentRecursive(rootNode, /*incremental*/ true);
2001    }
2002
2003    function createSourceFile(
2004        fileName: string,
2005        languageVersion: ScriptTarget,
2006        scriptKind: ScriptKind,
2007        isDeclarationFile: boolean,
2008        statements: readonly Statement[],
2009        endOfFileToken: EndOfFileToken,
2010        flags: NodeFlags,
2011        setExternalModuleIndicator: (sourceFile: SourceFile) => void): SourceFile {
2012        // code from createNode is inlined here so createNode won't have to deal with special case of creating source files
2013        // this is quite rare comparing to other nodes and createNode should be as fast as possible
2014        let sourceFile = factory.createSourceFile(statements, endOfFileToken, flags);
2015        setTextRangePosWidth(sourceFile, 0, sourceText.length);
2016        setFields(sourceFile);
2017
2018        // If we parsed this as an external module, it may contain top-level await
2019        if (!isDeclarationFile && isExternalModule(sourceFile) && sourceFile.transformFlags & TransformFlags.ContainsPossibleTopLevelAwait) {
2020            sourceFile = reparseTopLevelAwait(sourceFile);
2021            setFields(sourceFile);
2022        }
2023
2024        return sourceFile;
2025
2026        function setFields(sourceFile: SourceFile) {
2027            sourceFile.text = sourceText;
2028            sourceFile.bindDiagnostics = [];
2029            sourceFile.bindSuggestionDiagnostics = undefined;
2030            sourceFile.languageVersion = languageVersion;
2031            sourceFile.fileName = fileName;
2032            sourceFile.languageVariant = getLanguageVariant(scriptKind);
2033            sourceFile.isDeclarationFile = isDeclarationFile;
2034            sourceFile.scriptKind = scriptKind;
2035
2036            setExternalModuleIndicator(sourceFile);
2037            sourceFile.setExternalModuleIndicator = setExternalModuleIndicator;
2038        }
2039    }
2040
2041    function setContextFlag(val: boolean, flag: NodeFlags) {
2042        if (val) {
2043            contextFlags |= flag;
2044        }
2045        else {
2046            contextFlags &= ~flag;
2047        }
2048    }
2049
2050    function setEtsFlag(val: boolean, flag: EtsFlags) {
2051        if (val) {
2052            etsFlags |= flag;
2053        }
2054        else {
2055            etsFlags &= ~flag;
2056        }
2057    }
2058
2059    function setDisallowInContext(val: boolean) {
2060        setContextFlag(val, NodeFlags.DisallowInContext);
2061    }
2062
2063    function setYieldContext(val: boolean) {
2064        setContextFlag(val, NodeFlags.YieldContext);
2065    }
2066
2067    function setDecoratorContext(val: boolean) {
2068        setContextFlag(val, NodeFlags.DecoratorContext);
2069    }
2070
2071    function setAwaitContext(val: boolean) {
2072        setContextFlag(val, NodeFlags.AwaitContext);
2073    }
2074
2075    function setStructContext(val: boolean) {
2076        setEtsFlag(val, EtsFlags.StructContext);
2077    }
2078
2079    function setEtsComponentsContext(val: boolean) {
2080        setEtsFlag(val, EtsFlags.EtsComponentsContext);
2081    }
2082
2083    function setEtsNewExpressionContext(val: boolean) {
2084        setEtsFlag(val, EtsFlags.EtsNewExpressionContext);
2085    }
2086
2087    function setEtsExtendComponentsContext(val: boolean) {
2088        setEtsFlag(val, EtsFlags.EtsExtendComponentsContext);
2089    }
2090
2091    function setEtsStylesComponentsContext(val: boolean) {
2092        setEtsFlag(val, EtsFlags.EtsStylesComponentsContext);
2093    }
2094
2095    function setEtsBuildContext(val: boolean) {
2096        setEtsFlag(val, EtsFlags.EtsBuildContext);
2097    }
2098
2099    function setEtsBuilderContext(val: boolean) {
2100        setEtsFlag(val, EtsFlags.EtsBuilderContext);
2101    }
2102
2103    function setEtsStateStylesContext(val: boolean) {
2104        setEtsFlag(val, EtsFlags.EtsStateStylesContext);
2105    }
2106
2107    function setUICallbackContext(val: boolean) {
2108        setEtsFlag(val, EtsFlags.UICallbackContext);
2109    }
2110
2111    function setSyntaxComponentContext(val: boolean) {
2112        setEtsFlag(val, EtsFlags.SyntaxComponentContext);
2113    }
2114
2115    function setSyntaxDataSourceContext(val: boolean) {
2116        setEtsFlag(val, EtsFlags.SyntaxDataSourceContext);
2117    }
2118
2119    function setNoEtsComponentContext(val: boolean) {
2120        setEtsFlag(val, EtsFlags.NoEtsComponentContext);
2121    }
2122
2123    let firstArgumentExpression: boolean = false;
2124
2125    function setFirstArgumentExpression(val: boolean): void {
2126        firstArgumentExpression = val;
2127    }
2128
2129    function getFirstArgumentExpression(): boolean {
2130        return firstArgumentExpression;
2131    }
2132
2133    let repeatEachRest: boolean = false;
2134
2135    function setRepeatEachRest(val: boolean): void {
2136        repeatEachRest = val;
2137    }
2138
2139    function getRepeatEachRest(): boolean {
2140        return repeatEachRest;
2141    }
2142
2143    function doOutsideOfContext<T>(context: NodeFlags, func: () => T): T {
2144        // contextFlagsToClear will contain only the context flags that are
2145        // currently set that we need to temporarily clear
2146        // We don't just blindly reset to the previous flags to ensure
2147        // that we do not mutate cached flags for the incremental
2148        // parser (ThisNodeHasError, ThisNodeOrAnySubNodesHasError, and
2149        // HasAggregatedChildData).
2150        const contextFlagsToClear = context & contextFlags;
2151        if (contextFlagsToClear) {
2152            // clear the requested context flags
2153            setContextFlag(/*val*/ false, contextFlagsToClear);
2154            const result = func();
2155            // restore the context flags we just cleared
2156            setContextFlag(/*val*/ true, contextFlagsToClear);
2157            return result;
2158        }
2159
2160        // no need to do anything special as we are not in any of the requested contexts
2161        return func();
2162    }
2163
2164    function doInsideOfContext<T>(context: NodeFlags, func: () => T): T {
2165        // contextFlagsToSet will contain only the context flags that
2166        // are not currently set that we need to temporarily enable.
2167        // We don't just blindly reset to the previous flags to ensure
2168        // that we do not mutate cached flags for the incremental
2169        // parser (ThisNodeHasError, ThisNodeOrAnySubNodesHasError, and
2170        // HasAggregatedChildData).
2171        const contextFlagsToSet = context & ~contextFlags;
2172        if (contextFlagsToSet) {
2173            // set the requested context flags
2174            setContextFlag(/*val*/ true, contextFlagsToSet);
2175            const result = func();
2176            // reset the context flags we just set
2177            setContextFlag(/*val*/ false, contextFlagsToSet);
2178            return result;
2179        }
2180
2181        // no need to do anything special as we are already in all of the requested contexts
2182        return func();
2183    }
2184
2185    function allowInAnd<T>(func: () => T): T {
2186        return doOutsideOfContext(NodeFlags.DisallowInContext, func);
2187    }
2188
2189    function disallowInAnd<T>(func: () => T): T {
2190        return doInsideOfContext(NodeFlags.DisallowInContext, func);
2191    }
2192
2193    function allowConditionalTypesAnd<T>(func: () => T): T {
2194        return doOutsideOfContext(NodeFlags.DisallowConditionalTypesContext, func);
2195    }
2196
2197    function disallowConditionalTypesAnd<T>(func: () => T): T {
2198        return doInsideOfContext(NodeFlags.DisallowConditionalTypesContext, func);
2199    }
2200
2201    function doInYieldContext<T>(func: () => T): T {
2202        return doInsideOfContext(NodeFlags.YieldContext, func);
2203    }
2204
2205    function doInDecoratorContext<T>(func: () => T): T {
2206        // setting Ets Extend Components
2207        const extendDecorator = sourceFileCompilerOptions.ets?.extend?.decorator ?? "Extend";
2208        if (token() === SyntaxKind.Identifier && scanner.getTokenText() === extendDecorator) {
2209            setEtsFlag(true, EtsFlags.EtsExtendComponentsContext);
2210        }
2211        // setting Ets Styles Components
2212        const stylesDecorator = sourceFileCompilerOptions.ets?.styles?.decorator ?? "Styles";
2213        if (token() === SyntaxKind.Identifier && scanner.getTokenText() === stylesDecorator) {
2214            setEtsFlag(true, EtsFlags.EtsStylesComponentsContext);
2215        }
2216        return doInsideOfContext(NodeFlags.DecoratorContext, func);
2217    }
2218
2219    function doInAwaitContext<T>(func: () => T): T {
2220        return doInsideOfContext(NodeFlags.AwaitContext, func);
2221    }
2222
2223    function doOutsideOfAwaitContext<T>(func: () => T): T {
2224        return doOutsideOfContext(NodeFlags.AwaitContext, func);
2225    }
2226
2227    function doInYieldAndAwaitContext<T>(func: () => T): T {
2228        return doInsideOfContext(NodeFlags.YieldContext | NodeFlags.AwaitContext, func);
2229    }
2230
2231    function doOutsideOfYieldAndAwaitContext<T>(func: () => T): T {
2232        return doOutsideOfContext(NodeFlags.YieldContext | NodeFlags.AwaitContext, func);
2233    }
2234
2235    function inContext(flags: NodeFlags) {
2236        return (contextFlags & flags) !== 0;
2237    }
2238
2239    function inEtsFlagsContext(flags: EtsFlags) {
2240        return (etsFlags & flags) !== 0;
2241    }
2242
2243    function inYieldContext() {
2244        return inContext(NodeFlags.YieldContext);
2245    }
2246
2247    function inDisallowInContext() {
2248        return inContext(NodeFlags.DisallowInContext);
2249    }
2250
2251    function inDisallowConditionalTypesContext() {
2252        return inContext(NodeFlags.DisallowConditionalTypesContext);
2253    }
2254
2255    function inDecoratorContext() {
2256        return inContext(NodeFlags.DecoratorContext);
2257    }
2258
2259    function inAwaitContext() {
2260        return inContext(NodeFlags.AwaitContext);
2261    }
2262
2263    function parseErrorAtCurrentToken(message: DiagnosticMessage, arg0?: any): DiagnosticWithDetachedLocation | undefined {
2264        return parseErrorAt(scanner.getTokenPos(), scanner.getTextPos(), message, arg0);
2265    }
2266
2267    function inEtsContext() {
2268        return inContext(NodeFlags.EtsContext);
2269    }
2270
2271    function inStructContext() {
2272        return inEtsContext() && inEtsFlagsContext(EtsFlags.StructContext);
2273    }
2274
2275    function inEtsComponentsContext() {
2276        return inEtsContext() && inEtsFlagsContext(EtsFlags.EtsComponentsContext);
2277    }
2278
2279    function inEtsNewExpressionContext() {
2280        return inEtsContext() && inEtsFlagsContext(EtsFlags.EtsNewExpressionContext);
2281    }
2282
2283    function inEtsExtendComponentsContext() {
2284        return inEtsContext() && inEtsFlagsContext(EtsFlags.EtsExtendComponentsContext);
2285    }
2286
2287    function inEtsStylesComponentsContext() {
2288        return inEtsContext() && inEtsFlagsContext(EtsFlags.EtsStylesComponentsContext);
2289    }
2290
2291    function inBuildContext() {
2292        return inEtsContext() && inStructContext() && inEtsFlagsContext(EtsFlags.EtsBuildContext);
2293    }
2294
2295    function inBuilderContext() {
2296        return inEtsContext() && inEtsFlagsContext(EtsFlags.EtsBuilderContext);
2297    }
2298
2299    function inEtsStateStylesContext() {
2300        return inEtsContext() && (inBuildContext() || inBuilderContext() || inEtsExtendComponentsContext() || inEtsStylesComponentsContext()) && inEtsFlagsContext(EtsFlags.EtsStateStylesContext);
2301    }
2302
2303    function inUICallbackContext() {
2304        return inEtsContext() && (inBuildContext() || inBuilderContext()) && inEtsFlagsContext(EtsFlags.UICallbackContext);
2305    }
2306
2307    function inSyntaxComponentContext() {
2308        return inEtsContext() && (inBuildContext() || inBuilderContext()) && inEtsFlagsContext(EtsFlags.SyntaxComponentContext);
2309    }
2310
2311    function inSyntaxDataSourceContext() {
2312        return inEtsContext() && (inBuildContext() || inBuilderContext()) && inEtsFlagsContext(EtsFlags.SyntaxDataSourceContext);
2313    }
2314
2315    function inNoEtsComponentContext() {
2316        return inEtsContext() && (inBuildContext() || inBuilderContext()) && inEtsFlagsContext(EtsFlags.NoEtsComponentContext);
2317    }
2318
2319        function inAllowAnnotationContext() {
2320            return (inEtsContext() || isArkguardInputSourceFile) && sourceFileCompilerOptions?.etsAnnotationsEnable === true;
2321        }
2322
2323    function parseErrorAtPosition(start: number, length: number, message: DiagnosticMessage, arg0?: any): DiagnosticWithDetachedLocation | undefined {
2324        // Don't report another error if it would just be at the same position as the last error.
2325        const lastError = lastOrUndefined(parseDiagnostics);
2326        let result: DiagnosticWithDetachedLocation | undefined;
2327        if (!lastError || start !== lastError.start) {
2328            result = createDetachedDiagnostic(fileName, start, length, message, arg0);
2329            parseDiagnostics.push(result);
2330        }
2331
2332        // Mark that we've encountered an error.  We'll set an appropriate bit on the next
2333        // node we finish so that it can't be reused incrementally.
2334        parseErrorBeforeNextFinishedNode = true;
2335        return result;
2336    }
2337
2338    function parseErrorAt(start: number, end: number, message: DiagnosticMessage, arg0?: any): DiagnosticWithDetachedLocation | undefined {
2339        return parseErrorAtPosition(start, end - start, message, arg0);
2340    }
2341
2342    function parseErrorAtRange(range: TextRange, message: DiagnosticMessage, arg0?: any): void {
2343        parseErrorAt(range.pos, range.end, message, arg0);
2344    }
2345
2346    function scanError(message: DiagnosticMessage, length: number): void {
2347        parseErrorAtPosition(scanner.getTextPos(), length, message);
2348    }
2349
2350    function getNodePos(): number {
2351        return scanner.getStartPos();
2352    }
2353
2354    function hasPrecedingJSDocComment() {
2355        return scanner.hasPrecedingJSDocComment();
2356    }
2357
2358    // Use this function to access the current token instead of reading the currentToken
2359    // variable. Since function results aren't narrowed in control flow analysis, this ensures
2360    // that the type checker doesn't make wrong assumptions about the type of the current
2361    // token (e.g. a call to nextToken() changes the current token but the checker doesn't
2362    // reason about this side effect).  Mainstream VMs inline simple functions like this, so
2363    // there is no performance penalty.
2364    function token(): SyntaxKind {
2365        return currentToken;
2366    }
2367
2368    function nextTokenWithoutCheck() {
2369        return currentToken = scanner.scan();
2370    }
2371
2372    function nextTokenAnd<T>(func: () => T): T {
2373        nextToken();
2374        return func();
2375    }
2376
2377    function nextToken(): SyntaxKind {
2378        // if the keyword had an escape
2379        if (isKeyword(currentToken) && (scanner.hasUnicodeEscape() || scanner.hasExtendedUnicodeEscape())) {
2380            // issue a parse error for the escape
2381            parseErrorAt(scanner.getTokenPos(), scanner.getTextPos(), Diagnostics.Keywords_cannot_contain_escape_characters);
2382        }
2383        return nextTokenWithoutCheck();
2384    }
2385
2386    function nextTokenJSDoc(): JSDocSyntaxKind {
2387        return currentToken = scanner.scanJsDocToken();
2388    }
2389
2390    function reScanGreaterToken(): SyntaxKind {
2391        return currentToken = scanner.reScanGreaterToken();
2392    }
2393
2394    function reScanSlashToken(): SyntaxKind {
2395        return currentToken = scanner.reScanSlashToken();
2396    }
2397
2398    function reScanTemplateToken(isTaggedTemplate: boolean): SyntaxKind {
2399        return currentToken = scanner.reScanTemplateToken(isTaggedTemplate);
2400    }
2401
2402    function reScanTemplateHeadOrNoSubstitutionTemplate(): SyntaxKind {
2403        return currentToken = scanner.reScanTemplateHeadOrNoSubstitutionTemplate();
2404    }
2405
2406    function reScanLessThanToken(): SyntaxKind {
2407        return currentToken = scanner.reScanLessThanToken();
2408    }
2409
2410    function reScanHashToken(): SyntaxKind {
2411        return currentToken = scanner.reScanHashToken();
2412    }
2413
2414    function scanJsxIdentifier(): SyntaxKind {
2415        return currentToken = scanner.scanJsxIdentifier();
2416    }
2417
2418    function scanJsxText(): SyntaxKind {
2419        return currentToken = scanner.scanJsxToken();
2420    }
2421
2422    function scanJsxAttributeValue(): SyntaxKind {
2423        return currentToken = scanner.scanJsxAttributeValue();
2424    }
2425
2426    function speculationHelper<T>(callback: () => T, speculationKind: SpeculationKind): T {
2427        // Keep track of the state we'll need to rollback to if lookahead fails (or if the
2428        // caller asked us to always reset our state).
2429        const saveToken = currentToken;
2430        const saveParseDiagnosticsLength = parseDiagnostics.length;
2431        const saveParseErrorBeforeNextFinishedNode = parseErrorBeforeNextFinishedNode;
2432
2433        // Note: it is not actually necessary to save/restore the context flags here.  That's
2434        // because the saving/restoring of these flags happens naturally through the recursive
2435        // descent nature of our parser.  However, we still store this here just so we can
2436        // assert that invariant holds.
2437        const saveContextFlags = contextFlags;
2438
2439        // If we're only looking ahead, then tell the scanner to only lookahead as well.
2440        // Otherwise, if we're actually speculatively parsing, then tell the scanner to do the
2441        // same.
2442        const result = speculationKind !== SpeculationKind.TryParse
2443            ? scanner.lookAhead(callback)
2444            : scanner.tryScan(callback);
2445
2446        Debug.assert(saveContextFlags === contextFlags);
2447
2448        // If our callback returned something 'falsy' or we're just looking ahead,
2449        // then unconditionally restore us to where we were.
2450        if (!result || speculationKind !== SpeculationKind.TryParse) {
2451            currentToken = saveToken;
2452            if (speculationKind !== SpeculationKind.Reparse) {
2453                parseDiagnostics.length = saveParseDiagnosticsLength;
2454            }
2455            parseErrorBeforeNextFinishedNode = saveParseErrorBeforeNextFinishedNode;
2456        }
2457
2458        return result;
2459    }
2460
2461    /** Invokes the provided callback then unconditionally restores the parser to the state it
2462     * was in immediately prior to invoking the callback.  The result of invoking the callback
2463     * is returned from this function.
2464     */
2465    function lookAhead<T>(callback: () => T): T {
2466        return speculationHelper(callback, SpeculationKind.Lookahead);
2467    }
2468
2469    /** Invokes the provided callback.  If the callback returns something falsy, then it restores
2470     * the parser to the state it was in immediately prior to invoking the callback.  If the
2471     * callback returns something truthy, then the parser state is not rolled back.  The result
2472     * of invoking the callback is returned from this function.
2473     */
2474    function tryParse<T>(callback: () => T): T {
2475        return speculationHelper(callback, SpeculationKind.TryParse);
2476    }
2477
2478    function isBindingIdentifier(): boolean {
2479        if (token() === SyntaxKind.Identifier) {
2480            return true;
2481        }
2482
2483        // `let await`/`let yield` in [Yield] or [Await] are allowed here and disallowed in the binder.
2484        return token() > SyntaxKind.LastReservedWord;
2485    }
2486
2487    // Ignore strict mode flag because we will report an error in type checker instead.
2488    function isIdentifier(): boolean {
2489        if (token() === SyntaxKind.Identifier) {
2490            return true;
2491        }
2492
2493        // If we have a 'yield' keyword, and we're in the [yield] context, then 'yield' is
2494        // considered a keyword and is not an identifier.
2495        if (token() === SyntaxKind.YieldKeyword && inYieldContext()) {
2496            return false;
2497        }
2498
2499        // If we have a 'await' keyword, and we're in the [Await] context, then 'await' is
2500        // considered a keyword and is not an identifier.
2501        if (token() === SyntaxKind.AwaitKeyword && inAwaitContext()) {
2502            return false;
2503        }
2504
2505        return token() > SyntaxKind.LastReservedWord;
2506    }
2507
2508    function parseExpected(kind: SyntaxKind, diagnosticMessage?: DiagnosticMessage, shouldAdvance = true): boolean {
2509        if (token() === kind) {
2510            if (shouldAdvance) {
2511                nextToken();
2512            }
2513            return true;
2514        }
2515
2516        if (token() !== kind && stateStylesRootNode && inEtsStateStylesContext()) {
2517            return true;
2518        }
2519
2520        // Report specific message if provided with one.  Otherwise, report generic fallback message.
2521        if (diagnosticMessage) {
2522            parseErrorAtCurrentToken(diagnosticMessage);
2523        }
2524        else {
2525            parseErrorAtCurrentToken(Diagnostics._0_expected, tokenToString(kind));
2526        }
2527        return false;
2528    }
2529
2530    const viableKeywordSuggestions = Object.keys(textToKeywordObj).filter(keyword => keyword.length > 2);
2531
2532    /**
2533     * Provides a better error message than the generic "';' expected" if possible for
2534     * known common variants of a missing semicolon, such as from a mispelled names.
2535     *
2536     * @param node Node preceding the expected semicolon location.
2537     */
2538    function parseErrorForMissingSemicolonAfter(node: Expression | PropertyName): void {
2539        // Tagged template literals are sometimes used in places where only simple strings are allowed, i.e.:
2540        //   module `M1` {
2541        //   ^^^^^^^^^^^ This block is parsed as a template literal like module`M1`.
2542        if (isTaggedTemplateExpression(node)) {
2543            parseErrorAt(skipTrivia(sourceText, node.template.pos), node.template.end, Diagnostics.Module_declaration_names_may_only_use_or_quoted_strings);
2544            return;
2545        }
2546
2547        // Otherwise, if this isn't a well-known keyword-like identifier, give the generic fallback message.
2548        const expressionText = ts.isIdentifier(node) ? idText(node) : undefined;
2549        if (!expressionText || !isIdentifierText(expressionText, languageVersion)) {
2550            parseErrorAtCurrentToken(Diagnostics._0_expected, tokenToString(SyntaxKind.SemicolonToken));
2551            return;
2552        }
2553
2554        const pos = skipTrivia(sourceText, node.pos);
2555
2556        // Some known keywords are likely signs of syntax being used improperly.
2557        switch (expressionText) {
2558            case "const":
2559            case "let":
2560            case "var":
2561                parseErrorAt(pos, node.end, Diagnostics.Variable_declaration_not_allowed_at_this_location);
2562                return;
2563
2564            case "declare":
2565                // If a declared node failed to parse, it would have emitted a diagnostic already.
2566                return;
2567
2568            case "interface":
2569                parseErrorForInvalidName(Diagnostics.Interface_name_cannot_be_0, Diagnostics.Interface_must_be_given_a_name, SyntaxKind.OpenBraceToken);
2570                return;
2571
2572            case "is":
2573                parseErrorAt(pos, scanner.getTextPos(), Diagnostics.A_type_predicate_is_only_allowed_in_return_type_position_for_functions_and_methods);
2574                return;
2575
2576            case "module":
2577            case "namespace":
2578                parseErrorForInvalidName(Diagnostics.Namespace_name_cannot_be_0, Diagnostics.Namespace_must_be_given_a_name, SyntaxKind.OpenBraceToken);
2579                return;
2580
2581            case "type":
2582                parseErrorForInvalidName(Diagnostics.Type_alias_name_cannot_be_0, Diagnostics.Type_alias_must_be_given_a_name, SyntaxKind.EqualsToken);
2583                return;
2584        }
2585
2586        // The user alternatively might have misspelled or forgotten to add a space after a common keyword.
2587        const suggestion = getSpellingSuggestion(expressionText, viableKeywordSuggestions, n => n) ?? getSpaceSuggestion(expressionText);
2588        if (suggestion) {
2589            parseErrorAt(pos, node.end, Diagnostics.Unknown_keyword_or_identifier_Did_you_mean_0, suggestion);
2590            return;
2591        }
2592
2593        // Unknown tokens are handled with their own errors in the scanner
2594        if (token() === SyntaxKind.Unknown) {
2595            return;
2596        }
2597
2598        // Otherwise, we know this some kind of unknown word, not just a missing expected semicolon.
2599        parseErrorAt(pos, node.end, Diagnostics.Unexpected_keyword_or_identifier);
2600    }
2601
2602    /**
2603     * Reports a diagnostic error for the current token being an invalid name.
2604     *
2605     * @param blankDiagnostic Diagnostic to report for the case of the name being blank (matched tokenIfBlankName).
2606     * @param nameDiagnostic Diagnostic to report for all other cases.
2607     * @param tokenIfBlankName Current token if the name was invalid for being blank (not provided / skipped).
2608     */
2609    function parseErrorForInvalidName(nameDiagnostic: DiagnosticMessage, blankDiagnostic: DiagnosticMessage, tokenIfBlankName: SyntaxKind) {
2610        if (token() === tokenIfBlankName) {
2611            parseErrorAtCurrentToken(blankDiagnostic);
2612        }
2613        else {
2614            parseErrorAtCurrentToken(nameDiagnostic, scanner.getTokenValue());
2615        }
2616    }
2617
2618    function getSpaceSuggestion(expressionText: string) {
2619        for (const keyword of viableKeywordSuggestions) {
2620            if (expressionText.length > keyword.length + 2 && startsWith(expressionText, keyword)) {
2621                return `${keyword} ${expressionText.slice(keyword.length)}`;
2622            }
2623        }
2624
2625        return undefined;
2626    }
2627
2628    function parseSemicolonAfterPropertyName(name: PropertyName, type: TypeNode | undefined, initializer: Expression | undefined) {
2629        if (token() === SyntaxKind.AtToken && !scanner.hasPrecedingLineBreak()) {
2630            parseErrorAtCurrentToken(Diagnostics.Decorators_must_precede_the_name_and_all_keywords_of_property_declarations);
2631            return;
2632        }
2633
2634        if (token() === SyntaxKind.OpenParenToken) {
2635            parseErrorAtCurrentToken(Diagnostics.Cannot_start_a_function_call_in_a_type_annotation);
2636            nextToken();
2637            return;
2638        }
2639
2640        if (type && !canParseSemicolon()) {
2641            if (initializer) {
2642                parseErrorAtCurrentToken(Diagnostics._0_expected, tokenToString(SyntaxKind.SemicolonToken));
2643            }
2644            else {
2645                parseErrorAtCurrentToken(Diagnostics.Expected_for_property_initializer);
2646            }
2647            return;
2648        }
2649
2650        if (tryParseSemicolon()) {
2651            return;
2652        }
2653
2654        if (initializer) {
2655            parseErrorAtCurrentToken(Diagnostics._0_expected, tokenToString(SyntaxKind.SemicolonToken));
2656            return;
2657        }
2658
2659        parseErrorForMissingSemicolonAfter(name);
2660    }
2661
2662    function parseExpectedJSDoc(kind: JSDocSyntaxKind) {
2663        if (token() === kind) {
2664            nextTokenJSDoc();
2665            return true;
2666        }
2667        parseErrorAtCurrentToken(Diagnostics._0_expected, tokenToString(kind));
2668        return false;
2669    }
2670
2671    function parseExpectedMatchingBrackets(openKind: SyntaxKind, closeKind: SyntaxKind, openParsed: boolean, openPosition: number) {
2672        if (token() === closeKind) {
2673            nextToken();
2674            return;
2675        }
2676        const lastError = parseErrorAtCurrentToken(Diagnostics._0_expected, tokenToString(closeKind));
2677        if (!openParsed) {
2678            return;
2679        }
2680        if (lastError) {
2681            addRelatedInfo(
2682                lastError,
2683                createDetachedDiagnostic(fileName, openPosition, 1, Diagnostics.The_parser_expected_to_find_a_1_to_match_the_0_token_here, tokenToString(openKind), tokenToString(closeKind))
2684            );
2685        }
2686    }
2687
2688    function parseOptional(t: SyntaxKind): boolean {
2689        if (token() === t) {
2690            nextToken();
2691            return true;
2692        }
2693        return false;
2694    }
2695
2696    function parseOptionalToken<TKind extends SyntaxKind>(t: TKind): Token<TKind>;
2697    function parseOptionalToken(t: SyntaxKind): Node | undefined {
2698        if (token() === t) {
2699            return parseTokenNode();
2700        }
2701        return undefined;
2702    }
2703
2704    function parseOptionalTokenJSDoc<TKind extends JSDocSyntaxKind>(t: TKind): Token<TKind>;
2705    function parseOptionalTokenJSDoc(t: JSDocSyntaxKind): Node | undefined {
2706        if (token() === t) {
2707            return parseTokenNodeJSDoc();
2708        }
2709        return undefined;
2710    }
2711
2712    function parseExpectedToken<TKind extends SyntaxKind>(t: TKind, diagnosticMessage?: DiagnosticMessage, arg0?: any): Token<TKind>;
2713    function parseExpectedToken(t: SyntaxKind, diagnosticMessage?: DiagnosticMessage, arg0?: any): Node {
2714        return parseOptionalToken(t) ||
2715            createMissingNode(t, /*reportAtCurrentPosition*/ false, diagnosticMessage || Diagnostics._0_expected, arg0 || tokenToString(t));
2716    }
2717
2718    function parseExpectedTokenJSDoc<TKind extends JSDocSyntaxKind>(t: TKind): Token<TKind>;
2719    function parseExpectedTokenJSDoc(t: JSDocSyntaxKind): Node {
2720        return parseOptionalTokenJSDoc(t) ||
2721            createMissingNode(t, /*reportAtCurrentPosition*/ false, Diagnostics._0_expected, tokenToString(t));
2722    }
2723
2724    function parseTokenNode<T extends Node>(): T {
2725        const pos = getNodePos();
2726        const kind = token();
2727        nextToken();
2728        return finishNode(factory.createToken(kind), pos) as T;
2729    }
2730
2731    function parseTokenNodeJSDoc<T extends Node>(): T {
2732        const pos = getNodePos();
2733        const kind = token();
2734        nextTokenJSDoc();
2735        return finishNode(factory.createToken(kind), pos) as T;
2736    }
2737
2738    function canParseSemicolon() {
2739        // If there's a real semicolon, then we can always parse it out.
2740        if (token() === SyntaxKind.SemicolonToken) {
2741            return true;
2742        }
2743
2744        // We can parse out an optional semicolon in ASI cases in the following cases.
2745        return token() === SyntaxKind.CloseBraceToken || token() === SyntaxKind.EndOfFileToken || scanner.hasPrecedingLineBreak();
2746    }
2747
2748    function tryParseSemicolon() {
2749        if (!canParseSemicolon()) {
2750            return false;
2751        }
2752
2753        if (token() === SyntaxKind.SemicolonToken) {
2754            // consume the semicolon if it was explicitly provided.
2755            nextToken();
2756        }
2757
2758        return true;
2759    }
2760
2761    function parseSemicolon(): boolean {
2762        return tryParseSemicolon() || parseExpected(SyntaxKind.SemicolonToken);
2763    }
2764
2765    function createNodeArray<T extends Node>(elements: T[], pos: number, end?: number, hasTrailingComma?: boolean): NodeArray<T> {
2766        const array = factory.createNodeArray(elements, hasTrailingComma);
2767        setTextRangePosEnd(array, pos, end ?? scanner.getStartPos());
2768        return array;
2769    }
2770
2771    function finishNode<T extends Node>(node: T, pos: number, end?: number, virtual?: boolean): T {
2772        setTextRangePosEnd(node, pos, end ?? scanner.getStartPos());
2773        if (contextFlags) {
2774            (node as Mutable<T>).flags |= contextFlags;
2775        }
2776
2777        // Keep track on the node if we encountered an error while parsing it.  If we did, then
2778        // we cannot reuse the node incrementally.  Once we've marked this node, clear out the
2779        // flag so that we don't mark any subsequent nodes.
2780        if (parseErrorBeforeNextFinishedNode) {
2781            parseErrorBeforeNextFinishedNode = false;
2782            (node as Mutable<T>).flags |= NodeFlags.ThisNodeHasError;
2783        }
2784
2785        if (virtual) {
2786            node.virtual = true;
2787        }
2788
2789        return node;
2790    }
2791
2792    function createMissingNode<T extends Node>(kind: T["kind"], reportAtCurrentPosition: false, diagnosticMessage?: DiagnosticMessage, arg0?: any): T;
2793    function createMissingNode<T extends Node>(kind: T["kind"], reportAtCurrentPosition: boolean, diagnosticMessage: DiagnosticMessage, arg0?: any): T;
2794    function createMissingNode<T extends Node>(kind: T["kind"], reportAtCurrentPosition: boolean, diagnosticMessage: DiagnosticMessage, arg0?: any): T {
2795        if (reportAtCurrentPosition) {
2796            parseErrorAtPosition(scanner.getStartPos(), 0, diagnosticMessage, arg0);
2797        }
2798        else if (diagnosticMessage) {
2799            parseErrorAtCurrentToken(diagnosticMessage, arg0);
2800        }
2801
2802        const pos = getNodePos();
2803        const result =
2804            kind === SyntaxKind.Identifier ? factory.createIdentifier("", /*typeArguments*/ undefined, /*originalKeywordKind*/ undefined) :
2805            isTemplateLiteralKind(kind) ? factory.createTemplateLiteralLikeNode(kind, "", "", /*templateFlags*/ undefined) :
2806            kind === SyntaxKind.NumericLiteral ? factory.createNumericLiteral("", /*numericLiteralFlags*/ undefined) :
2807            kind === SyntaxKind.StringLiteral ? factory.createStringLiteral("", /*isSingleQuote*/ undefined) :
2808            kind === SyntaxKind.MissingDeclaration ? factory.createMissingDeclaration() :
2809            factory.createToken(kind);
2810        return finishNode(result, pos) as T;
2811    }
2812
2813    function internIdentifier(text: string): string {
2814        let identifier = identifiers.get(text);
2815        if (identifier === undefined) {
2816            identifiers.set(text, identifier = text);
2817        }
2818        return identifier;
2819    }
2820
2821    // An identifier that starts with two underscores has an extra underscore character prepended to it to avoid issues
2822    // with magic property names like '__proto__'. The 'identifiers' object is used to share a single string instance for
2823    // each identifier in order to reduce memory consumption.
2824    function createIdentifier(isIdentifier: boolean, diagnosticMessage?: DiagnosticMessage, privateIdentifierDiagnosticMessage?: DiagnosticMessage): Identifier {
2825        if (isIdentifier) {
2826            identifierCount++;
2827            const pos = getNodePos();
2828            // Store original token kind if it is not just an Identifier so we can report appropriate error later in type checker
2829            const originalKeywordKind = token();
2830            const text = internIdentifier(scanner.getTokenValue());
2831            const hasExtendedUnicodeEscape = scanner.hasExtendedUnicodeEscape();
2832            nextTokenWithoutCheck();
2833            return finishNode(factory.createIdentifier(text, /*typeArguments*/ undefined, originalKeywordKind, hasExtendedUnicodeEscape), pos);
2834        }
2835
2836        if (token() === SyntaxKind.PrivateIdentifier) {
2837            parseErrorAtCurrentToken(privateIdentifierDiagnosticMessage || Diagnostics.Private_identifiers_are_not_allowed_outside_class_bodies);
2838            return createIdentifier(/*isIdentifier*/ true);
2839        }
2840
2841        if (token() === SyntaxKind.Unknown && scanner.tryScan(() => scanner.reScanInvalidIdentifier() === SyntaxKind.Identifier)) {
2842            // Scanner has already recorded an 'Invalid character' error, so no need to add another from the parser.
2843            return createIdentifier(/*isIdentifier*/ true);
2844        }
2845
2846        if (stateStylesRootNode && inEtsStateStylesContext() && token() === SyntaxKind.DotToken) {
2847            identifierCount++;
2848            const pos = getNodePos();
2849            return finishVirtualNode(
2850                factory.createIdentifier(`${stateStylesRootNode}Instance`, /*typeArguments*/ undefined, SyntaxKind.Identifier),
2851                pos,
2852                pos
2853            );
2854        }
2855
2856        identifierCount++;
2857        // Only for end of file because the error gets reported incorrectly on embedded script tags.
2858        const reportAtCurrentPosition = token() === SyntaxKind.EndOfFileToken;
2859
2860        const isReservedWord = scanner.isReservedWord();
2861        const msgArg = scanner.getTokenText();
2862
2863        const defaultMessage = isReservedWord ?
2864            Diagnostics.Identifier_expected_0_is_a_reserved_word_that_cannot_be_used_here :
2865            Diagnostics.Identifier_expected;
2866
2867        return createMissingNode<Identifier>(SyntaxKind.Identifier, reportAtCurrentPosition, diagnosticMessage || defaultMessage, msgArg);
2868    }
2869
2870    function parseBindingIdentifier(privateIdentifierDiagnosticMessage?: DiagnosticMessage) {
2871        return createIdentifier(isBindingIdentifier(), /*diagnosticMessage*/ undefined, privateIdentifierDiagnosticMessage);
2872    }
2873
2874    function parseIdentifier(diagnosticMessage?: DiagnosticMessage, privateIdentifierDiagnosticMessage?: DiagnosticMessage): Identifier {
2875        return createIdentifier(isIdentifier(), diagnosticMessage, privateIdentifierDiagnosticMessage);
2876    }
2877
2878    function parseEtsIdentifier(pos: number): Identifier {
2879        identifierCount++;
2880        const text = internIdentifier(stylesEtsComponentDeclaration!.type);
2881        return finishVirtualNode(factory.createIdentifier(text), pos, pos);
2882    }
2883
2884    function parseIdentifierName(diagnosticMessage?: DiagnosticMessage): Identifier {
2885        return createIdentifier(tokenIsIdentifierOrKeyword(token()), diagnosticMessage);
2886    }
2887
2888    function isLiteralPropertyName(): boolean {
2889        return tokenIsIdentifierOrKeyword(token()) ||
2890            token() === SyntaxKind.StringLiteral ||
2891            token() === SyntaxKind.NumericLiteral;
2892    }
2893
2894    function isAssertionKey(): boolean {
2895        return tokenIsIdentifierOrKeyword(token()) ||
2896            token() === SyntaxKind.StringLiteral;
2897    }
2898
2899    function parsePropertyNameWorker(allowComputedPropertyNames: boolean): PropertyName {
2900        if (token() === SyntaxKind.StringLiteral || token() === SyntaxKind.NumericLiteral) {
2901            const node = parseLiteralNode() as StringLiteral | NumericLiteral;
2902            node.text = internIdentifier(node.text);
2903            return node;
2904        }
2905        if (allowComputedPropertyNames && token() === SyntaxKind.OpenBracketToken) {
2906            return parseComputedPropertyName();
2907        }
2908        if (token() === SyntaxKind.PrivateIdentifier) {
2909            return parsePrivateIdentifier();
2910        }
2911        return parseIdentifierName();
2912    }
2913
2914    function parsePropertyName(): PropertyName {
2915        return parsePropertyNameWorker(/*allowComputedPropertyNames*/ true);
2916    }
2917
2918    function parseComputedPropertyName(): ComputedPropertyName {
2919        // PropertyName [Yield]:
2920        //      LiteralPropertyName
2921        //      ComputedPropertyName[?Yield]
2922        const pos = getNodePos();
2923        parseExpected(SyntaxKind.OpenBracketToken);
2924        // We parse any expression (including a comma expression). But the grammar
2925        // says that only an assignment expression is allowed, so the grammar checker
2926        // will error if it sees a comma expression.
2927        const expression = allowInAnd(parseExpression);
2928        parseExpected(SyntaxKind.CloseBracketToken);
2929        return finishNode(factory.createComputedPropertyName(expression), pos);
2930    }
2931
2932    function internPrivateIdentifier(text: string): string {
2933        let privateIdentifier = privateIdentifiers.get(text);
2934        if (privateIdentifier === undefined) {
2935            privateIdentifiers.set(text, privateIdentifier = text);
2936        }
2937        return privateIdentifier;
2938    }
2939
2940    function parsePrivateIdentifier(): PrivateIdentifier {
2941        const pos = getNodePos();
2942        const node = factory.createPrivateIdentifier(internPrivateIdentifier(scanner.getTokenValue()));
2943        nextToken();
2944        return finishNode(node, pos);
2945    }
2946
2947    function parseContextualModifier(t: SyntaxKind): boolean {
2948        return token() === t && tryParse(nextTokenCanFollowModifier);
2949    }
2950
2951    function nextTokenIsOnSameLineAndCanFollowModifier() {
2952        nextToken();
2953        if (scanner.hasPrecedingLineBreak()) {
2954            return false;
2955        }
2956        return canFollowModifier();
2957    }
2958
2959    function nextTokenCanFollowModifier() {
2960        switch (token()) {
2961            case SyntaxKind.ConstKeyword:
2962                // 'const' is only a modifier if followed by 'enum'.
2963                return nextToken() === SyntaxKind.EnumKeyword;
2964            case SyntaxKind.ExportKeyword:
2965                nextToken();
2966                if (token() === SyntaxKind.DefaultKeyword) {
2967                    return lookAhead(nextTokenCanFollowDefaultKeyword);
2968                }
2969                if (token() === SyntaxKind.TypeKeyword) {
2970                    return lookAhead(nextTokenCanFollowExportModifier);
2971                }
2972                if (inAllowAnnotationContext() && token() === SyntaxKind.AtToken) {
2973                    return lookAhead(() => nextToken() === SyntaxKind.InterfaceKeyword);
2974                }
2975                return canFollowExportModifier();
2976            case SyntaxKind.DefaultKeyword:
2977                return nextTokenCanFollowDefaultKeyword();
2978            case SyntaxKind.AccessorKeyword:
2979            case SyntaxKind.StaticKeyword:
2980            case SyntaxKind.GetKeyword:
2981            case SyntaxKind.SetKeyword:
2982                nextToken();
2983                return canFollowModifier();
2984            default:
2985                return nextTokenIsOnSameLineAndCanFollowModifier();
2986        }
2987    }
2988
2989    function canFollowExportModifier(): boolean {
2990        return token() !== SyntaxKind.AsteriskToken
2991            && token() !== SyntaxKind.AsKeyword
2992            && token() !== SyntaxKind.OpenBraceToken
2993            && canFollowModifier();
2994    }
2995
2996    function nextTokenCanFollowExportModifier(): boolean {
2997        nextToken();
2998        return canFollowExportModifier();
2999    }
3000
3001    function parseAnyContextualModifier(): boolean {
3002        return isModifierKind(token()) && tryParse(nextTokenCanFollowModifier);
3003    }
3004
3005    function canFollowModifier(): boolean {
3006        return token() === SyntaxKind.OpenBracketToken
3007            || token() === SyntaxKind.OpenBraceToken
3008            || token() === SyntaxKind.AsteriskToken
3009            || token() === SyntaxKind.DotDotDotToken
3010            || token() === SyntaxKind.AtToken && inAllowAnnotationContext() && lookAhead(() => nextToken() === SyntaxKind.InterfaceKeyword)
3011            || isLiteralPropertyName();
3012    }
3013
3014    function nextTokenCanFollowDefaultKeyword(): boolean {
3015        nextToken();
3016        return token() === SyntaxKind.ClassKeyword || (inEtsContext() && token() === SyntaxKind.StructKeyword) ||
3017            token() === SyntaxKind.FunctionKeyword || token() === SyntaxKind.InterfaceKeyword ||
3018            (token() === SyntaxKind.AbstractKeyword && lookAhead(nextTokenIsClassKeywordOnSameLine)) ||
3019            (token() === SyntaxKind.AsyncKeyword && lookAhead(nextTokenIsFunctionKeywordOnSameLine));
3020    }
3021
3022    // True if positioned at the start of a list element
3023    function isListElement(parsingContext: ParsingContext, inErrorRecovery: boolean): boolean {
3024        const node = currentNode(parsingContext);
3025        if (node) {
3026            return true;
3027        }
3028
3029        switch (parsingContext) {
3030            case ParsingContext.SourceElements:
3031            case ParsingContext.BlockStatements:
3032            case ParsingContext.SwitchClauseStatements:
3033                // If we're in error recovery, then we don't want to treat ';' as an empty statement.
3034                // The problem is that ';' can show up in far too many contexts, and if we see one
3035                // and assume it's a statement, then we may bail out inappropriately from whatever
3036                // we're parsing.  For example, if we have a semicolon in the middle of a class, then
3037                // we really don't want to assume the class is over and we're on a statement in the
3038                // outer module.  We just want to consume and move on.
3039                return !(token() === SyntaxKind.SemicolonToken && inErrorRecovery) && isStartOfStatement();
3040            case ParsingContext.SwitchClauses:
3041                return token() === SyntaxKind.CaseKeyword || token() === SyntaxKind.DefaultKeyword;
3042            case ParsingContext.TypeMembers:
3043                return lookAhead(isTypeMemberStart);
3044            case ParsingContext.ClassMembers:
3045                // We allow semicolons as class elements (as specified by ES6) as long as we're
3046                // not in error recovery.  If we're in error recovery, we don't want an errant
3047                // semicolon to be treated as a class member (since they're almost always used
3048                // for statements.
3049                return lookAhead(isClassMemberStart) || (token() === SyntaxKind.SemicolonToken && !inErrorRecovery);
3050            case ParsingContext.AnnotationMembers:
3051                return lookAhead(isAnnotationMemberStart);
3052            case ParsingContext.EnumMembers:
3053                // Include open bracket computed properties. This technically also lets in indexers,
3054                // which would be a candidate for improved error reporting.
3055                return token() === SyntaxKind.OpenBracketToken || isLiteralPropertyName();
3056            case ParsingContext.ObjectLiteralMembers:
3057                switch (token()) {
3058                    case SyntaxKind.OpenBracketToken:
3059                    case SyntaxKind.AsteriskToken:
3060                    case SyntaxKind.DotDotDotToken:
3061                    case SyntaxKind.DotToken: // Not an object literal member, but don't want to close the object (see `tests/cases/fourslash/completionsDotInObjectLiteral.ts`)
3062                        return true;
3063                    default:
3064                        return isLiteralPropertyName();
3065                }
3066            case ParsingContext.RestProperties:
3067                return isLiteralPropertyName();
3068            case ParsingContext.ObjectBindingElements:
3069                return token() === SyntaxKind.OpenBracketToken || token() === SyntaxKind.DotDotDotToken || isLiteralPropertyName();
3070            case ParsingContext.AssertEntries:
3071                return isAssertionKey();
3072            case ParsingContext.HeritageClauseElement:
3073                // If we see `{ ... }` then only consume it as an expression if it is followed by `,` or `{`
3074                // That way we won't consume the body of a class in its heritage clause.
3075                if (token() === SyntaxKind.OpenBraceToken) {
3076                    return lookAhead(isValidHeritageClauseObjectLiteral);
3077                }
3078
3079                if (!inErrorRecovery) {
3080                    return isStartOfLeftHandSideExpression() && !isHeritageClauseExtendsOrImplementsKeyword();
3081                }
3082                else {
3083                    // If we're in error recovery we tighten up what we're willing to match.
3084                    // That way we don't treat something like "this" as a valid heritage clause
3085                    // element during recovery.
3086                    return isIdentifier() && !isHeritageClauseExtendsOrImplementsKeyword();
3087                }
3088            case ParsingContext.VariableDeclarations:
3089                return isBindingIdentifierOrPrivateIdentifierOrPattern();
3090            case ParsingContext.ArrayBindingElements:
3091                return token() === SyntaxKind.CommaToken || token() === SyntaxKind.DotDotDotToken || isBindingIdentifierOrPrivateIdentifierOrPattern();
3092            case ParsingContext.TypeParameters:
3093                return token() === SyntaxKind.InKeyword || isIdentifier();
3094            case ParsingContext.ArrayLiteralMembers:
3095                switch (token()) {
3096                    case SyntaxKind.CommaToken:
3097                    case SyntaxKind.DotToken: // Not an array literal member, but don't want to close the array (see `tests/cases/fourslash/completionsDotInArrayLiteralInObjectLiteral.ts`)
3098                        return true;
3099                }
3100                // falls through
3101            case ParsingContext.ArgumentExpressions:
3102                return token() === SyntaxKind.DotDotDotToken || isStartOfExpression();
3103            case ParsingContext.Parameters:
3104                return isStartOfParameter(/*isJSDocParameter*/ false);
3105            case ParsingContext.JSDocParameters:
3106                return isStartOfParameter(/*isJSDocParameter*/ true);
3107            case ParsingContext.TypeArguments:
3108            case ParsingContext.TupleElementTypes:
3109                return token() === SyntaxKind.CommaToken || isStartOfType();
3110            case ParsingContext.HeritageClauses:
3111                return isHeritageClause();
3112            case ParsingContext.ImportOrExportSpecifiers:
3113                return tokenIsIdentifierOrKeyword(token());
3114            case ParsingContext.JsxAttributes:
3115                return tokenIsIdentifierOrKeyword(token()) || token() === SyntaxKind.OpenBraceToken;
3116            case ParsingContext.JsxChildren:
3117                return true;
3118        }
3119
3120        return Debug.fail("Non-exhaustive case in 'isListElement'.");
3121    }
3122
3123    function isValidHeritageClauseObjectLiteral() {
3124        Debug.assert(token() === SyntaxKind.OpenBraceToken);
3125        if (nextToken() === SyntaxKind.CloseBraceToken) {
3126            // if we see "extends {}" then only treat the {} as what we're extending (and not
3127            // the class body) if we have:
3128            //
3129            //      extends {} {
3130            //      extends {},
3131            //      extends {} extends
3132            //      extends {} implements
3133
3134            const next = nextToken();
3135            return next === SyntaxKind.CommaToken || next === SyntaxKind.OpenBraceToken || next === SyntaxKind.ExtendsKeyword || next === SyntaxKind.ImplementsKeyword;
3136        }
3137
3138        return true;
3139    }
3140
3141    function nextTokenIsIdentifier() {
3142        nextToken();
3143        return isIdentifier();
3144    }
3145
3146    function nextTokenIsIdentifierOrKeyword() {
3147        nextToken();
3148        return tokenIsIdentifierOrKeyword(token());
3149    }
3150
3151    function nextTokenIsIdentifierOrKeywordOrGreaterThan() {
3152        nextToken();
3153        return tokenIsIdentifierOrKeywordOrGreaterThan(token());
3154    }
3155
3156    function isHeritageClauseExtendsOrImplementsKeyword(): boolean {
3157        if (token() === SyntaxKind.ImplementsKeyword ||
3158            token() === SyntaxKind.ExtendsKeyword) {
3159
3160            return lookAhead(nextTokenIsStartOfExpression);
3161        }
3162
3163        return false;
3164    }
3165
3166    function nextTokenIsStartOfExpression() {
3167        nextToken();
3168        return isStartOfExpression();
3169    }
3170
3171    function nextTokenIsStartOfType() {
3172        nextToken();
3173        return isStartOfType();
3174    }
3175
3176    // True if positioned at a list terminator
3177    function isListTerminator(kind: ParsingContext): boolean {
3178        if (token() === SyntaxKind.EndOfFileToken) {
3179            // Being at the end of the file ends all lists.
3180            return true;
3181        }
3182
3183        switch (kind) {
3184            case ParsingContext.BlockStatements:
3185            case ParsingContext.SwitchClauses:
3186            case ParsingContext.TypeMembers:
3187            case ParsingContext.ClassMembers:
3188            case ParsingContext.AnnotationMembers:
3189            case ParsingContext.EnumMembers:
3190            case ParsingContext.ObjectLiteralMembers:
3191            case ParsingContext.ObjectBindingElements:
3192            case ParsingContext.ImportOrExportSpecifiers:
3193            case ParsingContext.AssertEntries:
3194                return token() === SyntaxKind.CloseBraceToken;
3195            case ParsingContext.SwitchClauseStatements:
3196                return token() === SyntaxKind.CloseBraceToken || token() === SyntaxKind.CaseKeyword || token() === SyntaxKind.DefaultKeyword;
3197            case ParsingContext.HeritageClauseElement:
3198                return token() === SyntaxKind.OpenBraceToken || token() === SyntaxKind.ExtendsKeyword || token() === SyntaxKind.ImplementsKeyword;
3199            case ParsingContext.VariableDeclarations:
3200                return isVariableDeclaratorListTerminator();
3201            case ParsingContext.TypeParameters:
3202                // Tokens other than '>' are here for better error recovery
3203                return token() === SyntaxKind.GreaterThanToken || token() === SyntaxKind.OpenParenToken || token() === SyntaxKind.OpenBraceToken || token() === SyntaxKind.ExtendsKeyword || token() === SyntaxKind.ImplementsKeyword;
3204            case ParsingContext.ArgumentExpressions:
3205                // Tokens other than ')' are here for better error recovery
3206                return token() === SyntaxKind.CloseParenToken || token() === SyntaxKind.SemicolonToken;
3207            case ParsingContext.ArrayLiteralMembers:
3208            case ParsingContext.TupleElementTypes:
3209            case ParsingContext.ArrayBindingElements:
3210                return token() === SyntaxKind.CloseBracketToken;
3211            case ParsingContext.JSDocParameters:
3212            case ParsingContext.Parameters:
3213            case ParsingContext.RestProperties:
3214                // Tokens other than ')' and ']' (the latter for index signatures) are here for better error recovery
3215                return token() === SyntaxKind.CloseParenToken || token() === SyntaxKind.CloseBracketToken /*|| token === SyntaxKind.OpenBraceToken*/;
3216            case ParsingContext.TypeArguments:
3217                // All other tokens should cause the type-argument to terminate except comma token
3218                return token() !== SyntaxKind.CommaToken;
3219            case ParsingContext.HeritageClauses:
3220                return token() === SyntaxKind.OpenBraceToken || token() === SyntaxKind.CloseBraceToken;
3221            case ParsingContext.JsxAttributes:
3222                return token() === SyntaxKind.GreaterThanToken || token() === SyntaxKind.SlashToken;
3223            case ParsingContext.JsxChildren:
3224                return token() === SyntaxKind.LessThanToken && lookAhead(nextTokenIsSlash);
3225            default:
3226                return false;
3227        }
3228    }
3229
3230    function isVariableDeclaratorListTerminator(): boolean {
3231        // If we can consume a semicolon (either explicitly, or with ASI), then consider us done
3232        // with parsing the list of variable declarators.
3233        if (canParseSemicolon()) {
3234            return true;
3235        }
3236
3237        // in the case where we're parsing the variable declarator of a 'for-in' statement, we
3238        // are done if we see an 'in' keyword in front of us. Same with for-of
3239        if (isInOrOfKeyword(token())) {
3240            return true;
3241        }
3242
3243        // ERROR RECOVERY TWEAK:
3244        // For better error recovery, if we see an '=>' then we just stop immediately.  We've got an
3245        // arrow function here and it's going to be very unlikely that we'll resynchronize and get
3246        // another variable declaration.
3247        if (token() === SyntaxKind.EqualsGreaterThanToken) {
3248            return true;
3249        }
3250
3251        // Keep trying to parse out variable declarators.
3252        return false;
3253    }
3254
3255    // True if positioned at element or terminator of the current list or any enclosing list
3256    function isInSomeParsingContext(): boolean {
3257        for (let kind = 0; kind < ParsingContext.Count; kind++) {
3258            if (parsingContext & (1 << kind)) {
3259                if (isListElement(kind, /*inErrorRecovery*/ true) || isListTerminator(kind)) {
3260                    return true;
3261                }
3262            }
3263        }
3264
3265        return false;
3266    }
3267
3268    // Parses a list of elements
3269    function parseList<T extends Node>(kind: ParsingContext, parseElement: () => T): NodeArray<T> {
3270        const saveParsingContext = parsingContext;
3271        parsingContext |= 1 << kind;
3272        const list = [];
3273        const listPos = getNodePos();
3274
3275        while (!isListTerminator(kind)) {
3276            if (isListElement(kind, /*inErrorRecovery*/ false)) {
3277                list.push(parseListElement(kind, parseElement));
3278                continue;
3279            }
3280
3281            if (abortParsingListOrMoveToNextToken(kind)) {
3282                break;
3283            }
3284        }
3285
3286        parsingContext = saveParsingContext;
3287        return createNodeArray(list, listPos);
3288    }
3289
3290    function parseListElement<T extends Node | undefined>(parsingContext: ParsingContext, parseElement: () => T): T {
3291        const node = currentNode(parsingContext);
3292        if (node) {
3293            return consumeNode(node) as T;
3294        }
3295
3296        return parseElement();
3297    }
3298
3299    function currentNode(parsingContext: ParsingContext, pos?: number): Node | undefined {
3300        // If we don't have a cursor or the parsing context isn't reusable, there's nothing to reuse.
3301        //
3302        // If there is an outstanding parse error that we've encountered, but not attached to
3303        // some node, then we cannot get a node from the old source tree.  This is because we
3304        // want to mark the next node we encounter as being unusable.
3305        //
3306        // Note: This may be too conservative.  Perhaps we could reuse the node and set the bit
3307        // on it (or its leftmost child) as having the error.  For now though, being conservative
3308        // is nice and likely won't ever affect perf.
3309        if (!syntaxCursor || !isReusableParsingContext(parsingContext) || parseErrorBeforeNextFinishedNode) {
3310            return undefined;
3311        }
3312
3313        const node = syntaxCursor.currentNode(pos ?? scanner.getStartPos());
3314
3315        // Can't reuse a missing node.
3316        // Can't reuse a node that intersected the change range.
3317        // Can't reuse a node that contains a parse error.  This is necessary so that we
3318        // produce the same set of errors again.
3319        if (nodeIsMissing(node) || node.intersectsChange || containsParseError(node)) {
3320            return undefined;
3321        }
3322
3323        // We can only reuse a node if it was parsed under the same strict mode that we're
3324        // currently in.  i.e. if we originally parsed a node in non-strict mode, but then
3325        // the user added 'using strict' at the top of the file, then we can't use that node
3326        // again as the presence of strict mode may cause us to parse the tokens in the file
3327        // differently.
3328        //
3329        // Note: we *can* reuse tokens when the strict mode changes.  That's because tokens
3330        // are unaffected by strict mode.  It's just the parser will decide what to do with it
3331        // differently depending on what mode it is in.
3332        //
3333        // This also applies to all our other context flags as well.
3334        const nodeContextFlags = node.flags & NodeFlags.ContextFlags;
3335        if (nodeContextFlags !== contextFlags) {
3336            return undefined;
3337        }
3338
3339        // Ok, we have a node that looks like it could be reused.  Now verify that it is valid
3340        // in the current list parsing context that we're currently at.
3341        if (!canReuseNode(node, parsingContext)) {
3342            return undefined;
3343        }
3344
3345        if ((node as JSDocContainer).jsDocCache) {
3346            // jsDocCache may include tags from parent nodes, which might have been modified.
3347            (node as JSDocContainer).jsDocCache = undefined;
3348        }
3349
3350        return node;
3351    }
3352
3353    function consumeNode(node: Node) {
3354        // Move the scanner so it is after the node we just consumed.
3355        scanner.setTextPos(node.end);
3356        nextToken();
3357        return node;
3358    }
3359
3360    function isReusableParsingContext(parsingContext: ParsingContext): boolean {
3361        switch (parsingContext) {
3362            case ParsingContext.ClassMembers:
3363            case ParsingContext.SwitchClauses:
3364            case ParsingContext.SourceElements:
3365            case ParsingContext.BlockStatements:
3366            case ParsingContext.SwitchClauseStatements:
3367            case ParsingContext.EnumMembers:
3368            case ParsingContext.TypeMembers:
3369            case ParsingContext.VariableDeclarations:
3370            case ParsingContext.JSDocParameters:
3371            case ParsingContext.Parameters:
3372                return true;
3373        }
3374        return false;
3375    }
3376
3377    function canReuseNode(node: Node, parsingContext: ParsingContext): boolean {
3378        switch (parsingContext) {
3379            case ParsingContext.ClassMembers:
3380                return isReusableClassMember(node);
3381
3382            case ParsingContext.SwitchClauses:
3383                return isReusableSwitchClause(node);
3384
3385            case ParsingContext.SourceElements:
3386            case ParsingContext.BlockStatements:
3387            case ParsingContext.SwitchClauseStatements:
3388                return isReusableStatement(node);
3389
3390            case ParsingContext.EnumMembers:
3391                return isReusableEnumMember(node);
3392
3393            case ParsingContext.TypeMembers:
3394                return isReusableTypeMember(node);
3395
3396            case ParsingContext.VariableDeclarations:
3397                return isReusableVariableDeclaration(node);
3398
3399            case ParsingContext.JSDocParameters:
3400            case ParsingContext.Parameters:
3401                return isReusableParameter(node);
3402
3403            // Any other lists we do not care about reusing nodes in.  But feel free to add if
3404            // you can do so safely.  Danger areas involve nodes that may involve speculative
3405            // parsing.  If speculative parsing is involved with the node, then the range the
3406            // parser reached while looking ahead might be in the edited range (see the example
3407            // in canReuseVariableDeclaratorNode for a good case of this).
3408
3409            // case ParsingContext.HeritageClauses:
3410            // This would probably be safe to reuse.  There is no speculative parsing with
3411            // heritage clauses.
3412
3413            // case ParsingContext.TypeParameters:
3414            // This would probably be safe to reuse.  There is no speculative parsing with
3415            // type parameters.  Note that that's because type *parameters* only occur in
3416            // unambiguous *type* contexts.  While type *arguments* occur in very ambiguous
3417            // *expression* contexts.
3418
3419            // case ParsingContext.TupleElementTypes:
3420            // This would probably be safe to reuse.  There is no speculative parsing with
3421            // tuple types.
3422
3423            // Technically, type argument list types are probably safe to reuse.  While
3424            // speculative parsing is involved with them (since type argument lists are only
3425            // produced from speculative parsing a < as a type argument list), we only have
3426            // the types because speculative parsing succeeded.  Thus, the lookahead never
3427            // went past the end of the list and rewound.
3428            // case ParsingContext.TypeArguments:
3429
3430            // Note: these are almost certainly not safe to ever reuse.  Expressions commonly
3431            // need a large amount of lookahead, and we should not reuse them as they may
3432            // have actually intersected the edit.
3433            // case ParsingContext.ArgumentExpressions:
3434
3435            // This is not safe to reuse for the same reason as the 'AssignmentExpression'
3436            // cases.  i.e. a property assignment may end with an expression, and thus might
3437            // have lookahead far beyond it's old node.
3438            // case ParsingContext.ObjectLiteralMembers:
3439
3440            // This is probably not safe to reuse.  There can be speculative parsing with
3441            // type names in a heritage clause.  There can be generic names in the type
3442            // name list, and there can be left hand side expressions (which can have type
3443            // arguments.)
3444            // case ParsingContext.HeritageClauseElement:
3445
3446            // Perhaps safe to reuse, but it's unlikely we'd see more than a dozen attributes
3447            // on any given element. Same for children.
3448            // case ParsingContext.JsxAttributes:
3449            // case ParsingContext.JsxChildren:
3450
3451        }
3452
3453        return false;
3454    }
3455
3456    function isReusableClassMember(node: Node) {
3457        if (node) {
3458            switch (node.kind) {
3459                case SyntaxKind.Constructor:
3460                case SyntaxKind.IndexSignature:
3461                case SyntaxKind.GetAccessor:
3462                case SyntaxKind.SetAccessor:
3463                case SyntaxKind.SemicolonClassElement:
3464                    return true;
3465                case SyntaxKind.PropertyDeclaration:
3466                    return !inStructContext();
3467                case SyntaxKind.MethodDeclaration:
3468                    // Method declarations are not necessarily reusable.  An object-literal
3469                    // may have a method calls "constructor(...)" and we must reparse that
3470                    // into an actual .ConstructorDeclaration.
3471                    const methodDeclaration = node as MethodDeclaration;
3472                    const nameIsConstructor = methodDeclaration.name.kind === SyntaxKind.Identifier &&
3473                        methodDeclaration.name.originalKeywordKind === SyntaxKind.ConstructorKeyword;
3474
3475                    return !nameIsConstructor;
3476            }
3477        }
3478
3479        return false;
3480    }
3481
3482    function isReusableSwitchClause(node: Node) {
3483        if (node) {
3484            switch (node.kind) {
3485                case SyntaxKind.CaseClause:
3486                case SyntaxKind.DefaultClause:
3487                    return true;
3488            }
3489        }
3490
3491        return false;
3492    }
3493
3494    function isReusableStatement(node: Node) {
3495        if (node) {
3496            switch (node.kind) {
3497                case SyntaxKind.FunctionDeclaration:
3498                case SyntaxKind.VariableStatement:
3499                case SyntaxKind.Block:
3500                case SyntaxKind.IfStatement:
3501                case SyntaxKind.ExpressionStatement:
3502                case SyntaxKind.ThrowStatement:
3503                case SyntaxKind.ReturnStatement:
3504                case SyntaxKind.SwitchStatement:
3505                case SyntaxKind.BreakStatement:
3506                case SyntaxKind.ContinueStatement:
3507                case SyntaxKind.ForInStatement:
3508                case SyntaxKind.ForOfStatement:
3509                case SyntaxKind.ForStatement:
3510                case SyntaxKind.WhileStatement:
3511                case SyntaxKind.WithStatement:
3512                case SyntaxKind.EmptyStatement:
3513                case SyntaxKind.TryStatement:
3514                case SyntaxKind.LabeledStatement:
3515                case SyntaxKind.DoStatement:
3516                case SyntaxKind.DebuggerStatement:
3517                case SyntaxKind.ImportDeclaration:
3518                case SyntaxKind.ImportEqualsDeclaration:
3519                case SyntaxKind.ExportDeclaration:
3520                case SyntaxKind.ExportAssignment:
3521                case SyntaxKind.ModuleDeclaration:
3522                case SyntaxKind.ClassDeclaration:
3523                case SyntaxKind.StructDeclaration:
3524                case SyntaxKind.InterfaceDeclaration:
3525                case SyntaxKind.EnumDeclaration:
3526                case SyntaxKind.TypeAliasDeclaration:
3527                    return true;
3528            }
3529        }
3530
3531        return false;
3532    }
3533
3534    function isReusableEnumMember(node: Node) {
3535        return node.kind === SyntaxKind.EnumMember;
3536    }
3537
3538    function isReusableTypeMember(node: Node) {
3539        if (node) {
3540            switch (node.kind) {
3541                case SyntaxKind.ConstructSignature:
3542                case SyntaxKind.MethodSignature:
3543                case SyntaxKind.IndexSignature:
3544                case SyntaxKind.PropertySignature:
3545                case SyntaxKind.CallSignature:
3546                    return true;
3547            }
3548        }
3549
3550        return false;
3551    }
3552
3553    function isReusableVariableDeclaration(node: Node) {
3554        if (node.kind !== SyntaxKind.VariableDeclaration) {
3555            return false;
3556        }
3557
3558        // Very subtle incremental parsing bug.  Consider the following code:
3559        //
3560        //      let v = new List < A, B
3561        //
3562        // This is actually legal code.  It's a list of variable declarators "v = new List<A"
3563        // on one side and "B" on the other. If you then change that to:
3564        //
3565        //      let v = new List < A, B >()
3566        //
3567        // then we have a problem.  "v = new List<A" doesn't intersect the change range, so we
3568        // start reparsing at "B" and we completely fail to handle this properly.
3569        //
3570        // In order to prevent this, we do not allow a variable declarator to be reused if it
3571        // has an initializer.
3572        const variableDeclarator = node as VariableDeclaration;
3573        return variableDeclarator.initializer === undefined;
3574    }
3575
3576    function isReusableParameter(node: Node) {
3577        if (node.kind !== SyntaxKind.Parameter) {
3578            return false;
3579        }
3580
3581        // See the comment in isReusableVariableDeclaration for why we do this.
3582        const parameter = node as ParameterDeclaration;
3583        return parameter.initializer === undefined;
3584    }
3585
3586    // Returns true if we should abort parsing.
3587    function abortParsingListOrMoveToNextToken(kind: ParsingContext) {
3588        parsingContextErrors(kind);
3589        if (isInSomeParsingContext()) {
3590            return true;
3591        }
3592
3593        nextToken();
3594        return false;
3595    }
3596
3597    function parsingContextErrors(context: ParsingContext) {
3598        switch (context) {
3599            case ParsingContext.SourceElements:
3600                return token() === SyntaxKind.DefaultKeyword
3601                    ? parseErrorAtCurrentToken(Diagnostics._0_expected, tokenToString(SyntaxKind.ExportKeyword))
3602                    : parseErrorAtCurrentToken(Diagnostics.Declaration_or_statement_expected);
3603            case ParsingContext.BlockStatements: return parseErrorAtCurrentToken(Diagnostics.Declaration_or_statement_expected);
3604            case ParsingContext.SwitchClauses: return parseErrorAtCurrentToken(Diagnostics.case_or_default_expected);
3605            case ParsingContext.SwitchClauseStatements: return parseErrorAtCurrentToken(Diagnostics.Statement_expected);
3606            case ParsingContext.RestProperties: // fallthrough
3607            case ParsingContext.TypeMembers: return parseErrorAtCurrentToken(Diagnostics.Property_or_signature_expected);
3608            case ParsingContext.ClassMembers: return parseErrorAtCurrentToken(Diagnostics.Unexpected_token_A_constructor_method_accessor_or_property_was_expected);
3609            case ParsingContext.AnnotationMembers: return parseErrorAtCurrentToken(Diagnostics.Unexpected_token_An_annotation_property_was_expected);
3610            case ParsingContext.EnumMembers: return parseErrorAtCurrentToken(Diagnostics.Enum_member_expected);
3611            case ParsingContext.HeritageClauseElement: return parseErrorAtCurrentToken(Diagnostics.Expression_expected);
3612            case ParsingContext.VariableDeclarations:
3613                return isKeyword(token())
3614                    ? parseErrorAtCurrentToken(Diagnostics._0_is_not_allowed_as_a_variable_declaration_name, tokenToString(token()))
3615                    : parseErrorAtCurrentToken(Diagnostics.Variable_declaration_expected);
3616            case ParsingContext.ObjectBindingElements: return parseErrorAtCurrentToken(Diagnostics.Property_destructuring_pattern_expected);
3617            case ParsingContext.ArrayBindingElements: return parseErrorAtCurrentToken(Diagnostics.Array_element_destructuring_pattern_expected);
3618            case ParsingContext.ArgumentExpressions: return parseErrorAtCurrentToken(Diagnostics.Argument_expression_expected);
3619            case ParsingContext.ObjectLiteralMembers: return parseErrorAtCurrentToken(Diagnostics.Property_assignment_expected);
3620            case ParsingContext.ArrayLiteralMembers: return parseErrorAtCurrentToken(Diagnostics.Expression_or_comma_expected);
3621            case ParsingContext.JSDocParameters: return parseErrorAtCurrentToken(Diagnostics.Parameter_declaration_expected);
3622            case ParsingContext.Parameters:
3623                return isKeyword(token())
3624                    ? parseErrorAtCurrentToken(Diagnostics._0_is_not_allowed_as_a_parameter_name, tokenToString(token()))
3625                    : parseErrorAtCurrentToken(Diagnostics.Parameter_declaration_expected);
3626            case ParsingContext.TypeParameters: return parseErrorAtCurrentToken(Diagnostics.Type_parameter_declaration_expected);
3627            case ParsingContext.TypeArguments: return parseErrorAtCurrentToken(Diagnostics.Type_argument_expected);
3628            case ParsingContext.TupleElementTypes: return parseErrorAtCurrentToken(Diagnostics.Type_expected);
3629            case ParsingContext.HeritageClauses: return parseErrorAtCurrentToken(Diagnostics.Unexpected_token_expected);
3630            case ParsingContext.ImportOrExportSpecifiers: return parseErrorAtCurrentToken(Diagnostics.Identifier_expected);
3631            case ParsingContext.JsxAttributes: return parseErrorAtCurrentToken(Diagnostics.Identifier_expected);
3632            case ParsingContext.JsxChildren: return parseErrorAtCurrentToken(Diagnostics.Identifier_expected);
3633            case ParsingContext.AssertEntries: return parseErrorAtCurrentToken(Diagnostics.Identifier_or_string_literal_expected); // AssertionKey.
3634            case ParsingContext.Count: return Debug.fail("ParsingContext.Count used as a context"); // Not a real context, only a marker.
3635            default: Debug.assertNever(context);
3636        }
3637    }
3638
3639    // Parses a comma-delimited list of elements
3640    function parseDelimitedList<T extends Node>(kind: ParsingContext, parseElement: () => T, considerSemicolonAsDelimiter?: boolean): NodeArray<T>;
3641    function parseDelimitedList<T extends Node | undefined>(kind: ParsingContext, parseElement: () => T, considerSemicolonAsDelimiter?: boolean): NodeArray<NonNullable<T>> | undefined;
3642    function parseDelimitedList<T extends Node | undefined>(kind: ParsingContext, parseElement: () => T, considerSemicolonAsDelimiter?: boolean): NodeArray<NonNullable<T>> | undefined {
3643        const saveParsingContext = parsingContext;
3644        parsingContext |= 1 << kind;
3645        const list: NonNullable<T>[] = [];
3646        const listPos = getNodePos();
3647
3648        let commaStart = -1; // Meaning the previous token was not a comma
3649        while (true) {
3650            if (isListElement(kind, /*inErrorRecovery*/ false)) {
3651                const startPos = scanner.getStartPos();
3652                const result = parseListElement(kind, parseElement);
3653                if (!result) {
3654                    parsingContext = saveParsingContext;
3655                    return undefined;
3656                }
3657                list.push(result);
3658                commaStart = scanner.getTokenPos();
3659
3660                if (parseOptional(SyntaxKind.CommaToken)) {
3661                    // No need to check for a zero length node since we know we parsed a comma
3662                    continue;
3663                }
3664
3665                commaStart = -1; // Back to the state where the last token was not a comma
3666                if (isListTerminator(kind)) {
3667                    break;
3668                }
3669
3670                // We didn't get a comma, and the list wasn't terminated, explicitly parse
3671                // out a comma so we give a good error message.
3672                parseExpected(SyntaxKind.CommaToken, getExpectedCommaDiagnostic(kind));
3673
3674                // If the token was a semicolon, and the caller allows that, then skip it and
3675                // continue.  This ensures we get back on track and don't result in tons of
3676                // parse errors.  For example, this can happen when people do things like use
3677                // a semicolon to delimit object literal members.   Note: we'll have already
3678                // reported an error when we called parseExpected above.
3679                if (considerSemicolonAsDelimiter && token() === SyntaxKind.SemicolonToken && !scanner.hasPrecedingLineBreak()) {
3680                    nextToken();
3681                }
3682                if (startPos === scanner.getStartPos()) {
3683                    // What we're parsing isn't actually remotely recognizable as a element and we've consumed no tokens whatsoever
3684                    // Consume a token to advance the parser in some way and avoid an infinite loop
3685                    // This can happen when we're speculatively parsing parenthesized expressions which we think may be arrow functions,
3686                    // or when a modifier keyword which is disallowed as a parameter name (ie, `static` in strict mode) is supplied
3687                    nextToken();
3688                }
3689                continue;
3690            }
3691
3692            if (isListTerminator(kind)) {
3693                break;
3694            }
3695
3696            if (abortParsingListOrMoveToNextToken(kind)) {
3697                break;
3698            }
3699        }
3700
3701        parsingContext = saveParsingContext;
3702        // Recording the trailing comma is deliberately done after the previous
3703        // loop, and not just if we see a list terminator. This is because the list
3704        // may have ended incorrectly, but it is still important to know if there
3705        // was a trailing comma.
3706        // Check if the last token was a comma.
3707        // Always preserve a trailing comma by marking it on the NodeArray
3708        return createNodeArray(list, listPos, /*end*/ undefined, commaStart >= 0);
3709    }
3710
3711    function getExpectedCommaDiagnostic(kind: ParsingContext) {
3712        return kind === ParsingContext.EnumMembers ? Diagnostics.An_enum_member_name_must_be_followed_by_a_or : undefined;
3713    }
3714
3715    interface MissingList<T extends Node> extends NodeArray<T> {
3716        isMissingList: true;
3717    }
3718
3719    function createMissingList<T extends Node>(): MissingList<T> {
3720        const list = createNodeArray<T>([], getNodePos()) as MissingList<T>;
3721        list.isMissingList = true;
3722        return list;
3723    }
3724
3725    function isMissingList(arr: NodeArray<Node>): boolean {
3726        return !!(arr as MissingList<Node>).isMissingList;
3727    }
3728
3729    function parseBracketedList<T extends Node>(kind: ParsingContext, parseElement: () => T, open: SyntaxKind, close: SyntaxKind): NodeArray<T> {
3730        if (parseExpected(open)) {
3731            const result = parseDelimitedList(kind, parseElement);
3732            parseExpected(close);
3733            return result;
3734        }
3735
3736        return createMissingList<T>();
3737    }
3738
3739    function parseEntityName(allowReservedWords: boolean, diagnosticMessage?: DiagnosticMessage): EntityName {
3740        const pos = getNodePos();
3741        let entity: EntityName = allowReservedWords ? parseIdentifierName(diagnosticMessage) : parseIdentifier(diagnosticMessage);
3742        let dotPos = getNodePos();
3743        while (parseOptional(SyntaxKind.DotToken)) {
3744            if (token() === SyntaxKind.LessThanToken) {
3745                // the entity is part of a JSDoc-style generic, so record the trailing dot for later error reporting
3746                entity.jsdocDotPos = dotPos;
3747                break;
3748            }
3749            dotPos = getNodePos();
3750            entity = finishNode(
3751                factory.createQualifiedName(
3752                    entity,
3753                    parseRightSideOfDot(allowReservedWords, /* allowPrivateIdentifiers */ false) as Identifier
3754                ),
3755                pos
3756            );
3757        }
3758        return entity;
3759    }
3760
3761    function createQualifiedName(entity: EntityName, name: Identifier): QualifiedName {
3762        return finishNode(factory.createQualifiedName(entity, name), entity.pos);
3763    }
3764
3765    function parseRightSideOfDot(allowIdentifierNames: boolean, allowPrivateIdentifiers: boolean): Identifier | PrivateIdentifier {
3766        // Technically a keyword is valid here as all identifiers and keywords are identifier names.
3767        // However, often we'll encounter this in error situations when the identifier or keyword
3768        // is actually starting another valid construct.
3769        //
3770        // So, we check for the following specific case:
3771        //
3772        //      name.
3773        //      identifierOrKeyword identifierNameOrKeyword
3774        //
3775        // Note: the newlines are important here.  For example, if that above code
3776        // were rewritten into:
3777        //
3778        //      name.identifierOrKeyword
3779        //      identifierNameOrKeyword
3780        //
3781        // Then we would consider it valid.  That's because ASI would take effect and
3782        // the code would be implicitly: "name.identifierOrKeyword; identifierNameOrKeyword".
3783        // In the first case though, ASI will not take effect because there is not a
3784        // line terminator after the identifier or keyword.
3785        if (scanner.hasPrecedingLineBreak() && tokenIsIdentifierOrKeyword(token())) {
3786            const matchesPattern = lookAhead(nextTokenIsIdentifierOrKeywordOnSameLine);
3787
3788            if (matchesPattern) {
3789                // Report that we need an identifier.  However, report it right after the dot,
3790                // and not on the next token.  This is because the next token might actually
3791                // be an identifier and the error would be quite confusing.
3792                return createMissingNode<Identifier>(SyntaxKind.Identifier, /*reportAtCurrentPosition*/ true, Diagnostics.Identifier_expected);
3793            }
3794        }
3795
3796        if (token() === SyntaxKind.PrivateIdentifier) {
3797            const node = parsePrivateIdentifier();
3798            return allowPrivateIdentifiers ? node : createMissingNode<Identifier>(SyntaxKind.Identifier, /*reportAtCurrentPosition*/ true, Diagnostics.Identifier_expected);
3799        }
3800
3801        return allowIdentifierNames ? parseIdentifierName() : parseIdentifier();
3802    }
3803
3804    function parseTemplateSpans(isTaggedTemplate: boolean) {
3805        const pos = getNodePos();
3806        const list = [];
3807        let node: TemplateSpan;
3808        do {
3809            node = parseTemplateSpan(isTaggedTemplate);
3810            list.push(node);
3811        }
3812        while (node.literal.kind === SyntaxKind.TemplateMiddle);
3813        return createNodeArray(list, pos);
3814    }
3815
3816    function parseTemplateExpression(isTaggedTemplate: boolean): TemplateExpression {
3817        const pos = getNodePos();
3818        return finishNode(
3819            factory.createTemplateExpression(
3820                parseTemplateHead(isTaggedTemplate),
3821                parseTemplateSpans(isTaggedTemplate)
3822            ),
3823            pos
3824        );
3825    }
3826
3827    function parseTemplateType(): TemplateLiteralTypeNode {
3828        const pos = getNodePos();
3829        return finishNode(
3830            factory.createTemplateLiteralType(
3831                parseTemplateHead(/*isTaggedTemplate*/ false),
3832                parseTemplateTypeSpans()
3833            ),
3834            pos
3835        );
3836    }
3837
3838    function parseTemplateTypeSpans() {
3839        const pos = getNodePos();
3840        const list = [];
3841        let node: TemplateLiteralTypeSpan;
3842        do {
3843            node = parseTemplateTypeSpan();
3844            list.push(node);
3845        }
3846        while (node.literal.kind === SyntaxKind.TemplateMiddle);
3847        return createNodeArray(list, pos);
3848    }
3849
3850    function parseTemplateTypeSpan(): TemplateLiteralTypeSpan {
3851        const pos = getNodePos();
3852        return finishNode(
3853            factory.createTemplateLiteralTypeSpan(
3854                parseType(),
3855                parseLiteralOfTemplateSpan(/*isTaggedTemplate*/ false)
3856            ),
3857            pos
3858        );
3859    }
3860
3861    function parseLiteralOfTemplateSpan(isTaggedTemplate: boolean) {
3862        if (token() === SyntaxKind.CloseBraceToken) {
3863            reScanTemplateToken(isTaggedTemplate);
3864            return parseTemplateMiddleOrTemplateTail();
3865        }
3866        else {
3867            // TODO(rbuckton): Do we need to call `parseExpectedToken` or can we just call `createMissingNode` directly?
3868            return parseExpectedToken(SyntaxKind.TemplateTail, Diagnostics._0_expected, tokenToString(SyntaxKind.CloseBraceToken)) as TemplateTail;
3869        }
3870    }
3871
3872    function parseTemplateSpan(isTaggedTemplate: boolean): TemplateSpan {
3873        const pos = getNodePos();
3874        return finishNode(
3875            factory.createTemplateSpan(
3876                allowInAnd(parseExpression),
3877                parseLiteralOfTemplateSpan(isTaggedTemplate)
3878            ),
3879            pos
3880        );
3881    }
3882
3883    function parseLiteralNode(): LiteralExpression {
3884        return parseLiteralLikeNode(token()) as LiteralExpression;
3885    }
3886
3887    function parseTemplateHead(isTaggedTemplate: boolean): TemplateHead {
3888        if (isTaggedTemplate) {
3889            reScanTemplateHeadOrNoSubstitutionTemplate();
3890        }
3891        const fragment = parseLiteralLikeNode(token());
3892        Debug.assert(fragment.kind === SyntaxKind.TemplateHead, "Template head has wrong token kind");
3893        return fragment as TemplateHead;
3894    }
3895
3896    function parseTemplateMiddleOrTemplateTail(): TemplateMiddle | TemplateTail {
3897        const fragment = parseLiteralLikeNode(token());
3898        Debug.assert(fragment.kind === SyntaxKind.TemplateMiddle || fragment.kind === SyntaxKind.TemplateTail, "Template fragment has wrong token kind");
3899        return fragment as TemplateMiddle | TemplateTail;
3900    }
3901
3902    function getTemplateLiteralRawText(kind: TemplateLiteralToken["kind"]) {
3903        const isLast = kind === SyntaxKind.NoSubstitutionTemplateLiteral || kind === SyntaxKind.TemplateTail;
3904        const tokenText = scanner.getTokenText();
3905        return tokenText.substring(1, tokenText.length - (scanner.isUnterminated() ? 0 : isLast ? 1 : 2));
3906    }
3907
3908    function parseLiteralLikeNode(kind: SyntaxKind): LiteralLikeNode {
3909        const pos = getNodePos();
3910        const node =
3911            isTemplateLiteralKind(kind) ? factory.createTemplateLiteralLikeNode(kind, scanner.getTokenValue(), getTemplateLiteralRawText(kind), scanner.getTokenFlags() & TokenFlags.TemplateLiteralLikeFlags) :
3912            // Octal literals are not allowed in strict mode or ES5
3913            // Note that theoretically the following condition would hold true literals like 009,
3914            // which is not octal. But because of how the scanner separates the tokens, we would
3915            // never get a token like this. Instead, we would get 00 and 9 as two separate tokens.
3916            // We also do not need to check for negatives because any prefix operator would be part of a
3917            // parent unary expression.
3918            kind === SyntaxKind.NumericLiteral ? factory.createNumericLiteral(scanner.getTokenValue(), scanner.getNumericLiteralFlags()) :
3919            kind === SyntaxKind.StringLiteral ? factory.createStringLiteral(scanner.getTokenValue(), /*isSingleQuote*/ undefined, scanner.hasExtendedUnicodeEscape()) :
3920            isLiteralKind(kind) ? factory.createLiteralLikeNode(kind, scanner.getTokenValue()) :
3921            Debug.fail();
3922
3923        if (scanner.hasExtendedUnicodeEscape()) {
3924            node.hasExtendedUnicodeEscape = true;
3925        }
3926
3927        if (scanner.isUnterminated()) {
3928            node.isUnterminated = true;
3929        }
3930
3931        nextToken();
3932        return finishNode(node, pos);
3933    }
3934
3935    // TYPES
3936
3937    function parseEntityNameOfTypeReference() {
3938        return parseEntityName(/*allowReservedWords*/ true, Diagnostics.Type_expected);
3939    }
3940
3941    function parseTypeArgumentsOfTypeReference() {
3942        if (!scanner.hasPrecedingLineBreak() && reScanLessThanToken() === SyntaxKind.LessThanToken) {
3943            return parseBracketedList(ParsingContext.TypeArguments, parseType, SyntaxKind.LessThanToken, SyntaxKind.GreaterThanToken);
3944        }
3945    }
3946
3947    function parseTypeReference(): TypeReferenceNode {
3948        const pos = getNodePos();
3949        return finishNode(
3950            factory.createTypeReferenceNode(
3951                parseEntityNameOfTypeReference(),
3952                parseTypeArgumentsOfTypeReference()
3953            ),
3954            pos
3955        );
3956    }
3957
3958    // If true, we should abort parsing an error function.
3959    function typeHasArrowFunctionBlockingParseError(node: TypeNode): boolean {
3960        switch (node.kind) {
3961            case SyntaxKind.TypeReference:
3962                return nodeIsMissing((node as TypeReferenceNode).typeName);
3963            case SyntaxKind.FunctionType:
3964            case SyntaxKind.ConstructorType: {
3965                const { parameters, type } = node as FunctionOrConstructorTypeNode;
3966                return isMissingList(parameters) || typeHasArrowFunctionBlockingParseError(type);
3967            }
3968            case SyntaxKind.ParenthesizedType:
3969                return typeHasArrowFunctionBlockingParseError((node as ParenthesizedTypeNode).type);
3970            default:
3971                return false;
3972        }
3973    }
3974
3975    function parseThisTypePredicate(lhs: ThisTypeNode): TypePredicateNode {
3976        nextToken();
3977        return finishNode(factory.createTypePredicateNode(/*assertsModifier*/ undefined, lhs, parseType()), lhs.pos);
3978    }
3979
3980    function parseThisTypeNode(): ThisTypeNode {
3981        const pos = getNodePos();
3982        nextToken();
3983        return finishNode(factory.createThisTypeNode(), pos);
3984    }
3985
3986    function parseJSDocAllType(): JSDocAllType | JSDocOptionalType {
3987        const pos = getNodePos();
3988        nextToken();
3989        return finishNode(factory.createJSDocAllType(), pos);
3990    }
3991
3992    function parseJSDocNonNullableType(): TypeNode {
3993        const pos = getNodePos();
3994        nextToken();
3995        return finishNode(factory.createJSDocNonNullableType(parseNonArrayType(), /*postfix*/ false), pos);
3996    }
3997
3998    function parseJSDocUnknownOrNullableType(): JSDocUnknownType | JSDocNullableType {
3999        const pos = getNodePos();
4000        // skip the ?
4001        nextToken();
4002
4003        // Need to lookahead to decide if this is a nullable or unknown type.
4004
4005        // Here are cases where we'll pick the unknown type:
4006        //
4007        //      Foo(?,
4008        //      { a: ? }
4009        //      Foo(?)
4010        //      Foo<?>
4011        //      Foo(?=
4012        //      (?|
4013        if (token() === SyntaxKind.CommaToken ||
4014            token() === SyntaxKind.CloseBraceToken ||
4015            token() === SyntaxKind.CloseParenToken ||
4016            token() === SyntaxKind.GreaterThanToken ||
4017            token() === SyntaxKind.EqualsToken ||
4018            token() === SyntaxKind.BarToken) {
4019            return finishNode(factory.createJSDocUnknownType(), pos);
4020        }
4021        else {
4022            return finishNode(factory.createJSDocNullableType(parseType(), /*postfix*/ false), pos);
4023        }
4024    }
4025
4026    function parseJSDocFunctionType(): JSDocFunctionType | TypeReferenceNode {
4027        const pos = getNodePos();
4028        const hasJSDoc = hasPrecedingJSDocComment();
4029        if (lookAhead(nextTokenIsOpenParen)) {
4030            nextToken();
4031            const parameters = parseParameters(SignatureFlags.Type | SignatureFlags.JSDoc);
4032            const type = parseReturnType(SyntaxKind.ColonToken, /*isType*/ false);
4033            return withJSDoc(finishNode(factory.createJSDocFunctionType(parameters, type), pos), hasJSDoc);
4034        }
4035        return finishNode(factory.createTypeReferenceNode(parseIdentifierName(), /*typeArguments*/ undefined), pos);
4036    }
4037
4038    function parseJSDocParameter(): ParameterDeclaration {
4039        const pos = getNodePos();
4040        let name: Identifier | undefined;
4041        if (token() === SyntaxKind.ThisKeyword || token() === SyntaxKind.NewKeyword) {
4042            name = parseIdentifierName();
4043            parseExpected(SyntaxKind.ColonToken);
4044        }
4045        return finishNode(
4046            factory.createParameterDeclaration(
4047                /*modifiers*/ undefined,
4048                /*dotDotDotToken*/ undefined,
4049                // TODO(rbuckton): JSDoc parameters don't have names (except `this`/`new`), should we manufacture an empty identifier?
4050                name!,
4051                /*questionToken*/ undefined,
4052                parseJSDocType(),
4053                /*initializer*/ undefined
4054            ),
4055            pos
4056        );
4057    }
4058
4059    function parseJSDocType(): TypeNode {
4060        scanner.setInJSDocType(true);
4061        const pos = getNodePos();
4062        if (parseOptional(SyntaxKind.ModuleKeyword)) {
4063            // TODO(rbuckton): We never set the type for a JSDocNamepathType. What should we put here?
4064            const moduleTag = factory.createJSDocNamepathType(/*type*/ undefined!);
4065            terminate: while (true) {
4066                switch (token()) {
4067                    case SyntaxKind.CloseBraceToken:
4068                    case SyntaxKind.EndOfFileToken:
4069                    case SyntaxKind.CommaToken:
4070                    case SyntaxKind.WhitespaceTrivia:
4071                        break terminate;
4072                    default:
4073                        nextTokenJSDoc();
4074                }
4075            }
4076
4077            scanner.setInJSDocType(false);
4078            return finishNode(moduleTag, pos);
4079        }
4080
4081        const hasDotDotDot = parseOptional(SyntaxKind.DotDotDotToken);
4082        let type = parseTypeOrTypePredicate();
4083        scanner.setInJSDocType(false);
4084        if (hasDotDotDot) {
4085            type = finishNode(factory.createJSDocVariadicType(type), pos);
4086        }
4087        if (token() === SyntaxKind.EqualsToken) {
4088            nextToken();
4089            return finishNode(factory.createJSDocOptionalType(type), pos);
4090        }
4091        return type;
4092    }
4093
4094    function parseTypeQuery(): TypeQueryNode {
4095        const pos = getNodePos();
4096        parseExpected(SyntaxKind.TypeOfKeyword);
4097        const entityName = parseEntityName(/*allowReservedWords*/ true);
4098        // Make sure we perform ASI to prevent parsing the next line's type arguments as part of an instantiation expression.
4099        const typeArguments = !scanner.hasPrecedingLineBreak() ? tryParseTypeArguments() : undefined;
4100        return finishNode(factory.createTypeQueryNode(entityName, typeArguments), pos);
4101    }
4102
4103    function parseTypeParameter(position?: number): TypeParameterDeclaration {
4104        const pos = getNodePos();
4105        const modifiers = parseModifiers();
4106        const name = position !== undefined ? parseEtsIdentifier(position) : parseIdentifier();
4107        let constraint: TypeNode | undefined;
4108        let expression: Expression | undefined;
4109        if (parseOptional(SyntaxKind.ExtendsKeyword)) {
4110            // It's not uncommon for people to write improper constraints to a generic.  If the
4111            // user writes a constraint that is an expression and not an actual type, then parse
4112            // it out as an expression (so we can recover well), but report that a type is needed
4113            // instead.
4114            if (isStartOfType() || !isStartOfExpression()) {
4115                constraint = parseType();
4116            }
4117            else {
4118                // It was not a type, and it looked like an expression.  Parse out an expression
4119                // here so we recover well.  Note: it is important that we call parseUnaryExpression
4120                // and not parseExpression here.  If the user has:
4121                //
4122                //      <T extends "">
4123                //
4124                // We do *not* want to consume the `>` as we're consuming the expression for "".
4125                expression = parseUnaryExpressionOrHigher();
4126            }
4127        }
4128
4129        const defaultType = parseOptional(SyntaxKind.EqualsToken) ? parseType() : undefined;
4130        const node = factory.createTypeParameterDeclaration(modifiers, name, constraint, defaultType);
4131        node.expression = expression;
4132        return position !== undefined ? finishVirtualNode(node, position, position) : finishNode(node, pos);
4133    }
4134
4135    function parseTypeParameters(): NodeArray<TypeParameterDeclaration> | undefined {
4136        if (token() === SyntaxKind.LessThanToken) {
4137            return parseBracketedList(ParsingContext.TypeParameters, parseTypeParameter, SyntaxKind.LessThanToken, SyntaxKind.GreaterThanToken);
4138        }
4139    }
4140
4141    function parseEtsTypeParameters(pos: number): NodeArray<TypeParameterDeclaration> | undefined {
4142        return createNodeArray([parseTypeParameter(pos)], getNodePos());
4143    }
4144
4145    function parseEtsTypeArguments(pos: number, name: string): NodeArray<TypeNode> | undefined {
4146        if ((contextFlags & NodeFlags.JavaScriptFile) !== 0) {
4147            // TypeArguments must not be parsed in JavaScript files to avoid ambiguity with binary operators.
4148            return undefined;
4149        }
4150
4151        return createNodeArray([parseEtsType(pos, name)], getNodePos());
4152    }
4153
4154    function isStartOfParameter(isJSDocParameter: boolean): boolean {
4155        return token() === SyntaxKind.DotDotDotToken ||
4156            isBindingIdentifierOrPrivateIdentifierOrPattern() ||
4157            isModifierKind(token()) ||
4158            token() === SyntaxKind.AtToken ||
4159            isStartOfType(/*inStartOfParameter*/ !isJSDocParameter);
4160    }
4161
4162    function parseNameOfParameter(modifiers: NodeArray<ModifierLike> | undefined) {
4163        // FormalParameter [Yield,Await]:
4164        //      BindingElement[?Yield,?Await]
4165        const name = parseIdentifierOrPattern(Diagnostics.Private_identifiers_cannot_be_used_as_parameters);
4166        if (getFullWidth(name) === 0 && !some(modifiers) && isModifierKind(token())) {
4167            // in cases like
4168            // 'use strict'
4169            // function foo(static)
4170            // isParameter('static') === true, because of isModifier('static')
4171            // however 'static' is not a legal identifier in a strict mode.
4172            // so result of this function will be ParameterDeclaration (flags = 0, name = missing, type = undefined, initializer = undefined)
4173            // and current token will not change => parsing of the enclosing parameter list will last till the end of time (or OOM)
4174            // to avoid this we'll advance cursor to the next token.
4175            nextToken();
4176        }
4177        return name;
4178    }
4179
4180    function isParameterNameStart() {
4181        // Be permissive about await and yield by calling isBindingIdentifier instead of isIdentifier; disallowing
4182        // them during a speculative parse leads to many more follow-on errors than allowing the function to parse then later
4183        // complaining about the use of the keywords.
4184        return isBindingIdentifier() || token() === SyntaxKind.OpenBracketToken || token() === SyntaxKind.OpenBraceToken;
4185    }
4186
4187    function parseParameter(inOuterAwaitContext: boolean): ParameterDeclaration {
4188        return parseParameterWorker(inOuterAwaitContext);
4189    }
4190
4191    function parseParameterForSpeculation(inOuterAwaitContext: boolean): ParameterDeclaration | undefined {
4192        return parseParameterWorker(inOuterAwaitContext, /*allowAmbiguity*/ false);
4193    }
4194
4195    function parseParameterWorker(inOuterAwaitContext: boolean): ParameterDeclaration;
4196    function parseParameterWorker(inOuterAwaitContext: boolean, allowAmbiguity: false): ParameterDeclaration | undefined;
4197    function parseParameterWorker(inOuterAwaitContext: boolean, allowAmbiguity = true): ParameterDeclaration | undefined {
4198        const pos = getNodePos();
4199        const hasJSDoc = hasPrecedingJSDocComment();
4200
4201        // FormalParameter [Yield,Await]:
4202        //      BindingElement[?Yield,?Await]
4203
4204        // Decorators are parsed in the outer [Await] context, the rest of the parameter is parsed in the function's [Await] context.
4205        const decorators = inOuterAwaitContext ? doInAwaitContext(parseDecorators) : doOutsideOfAwaitContext(parseDecorators);
4206
4207        if (token() === SyntaxKind.ThisKeyword) {
4208            const node = factory.createParameterDeclaration(
4209                decorators,
4210                /*dotDotDotToken*/ undefined,
4211                createIdentifier(/*isIdentifier*/ true),
4212                /*questionToken*/ undefined,
4213                parseTypeAnnotation(),
4214                /*initializer*/ undefined
4215            );
4216
4217            if (decorators) {
4218                parseErrorAtRange(decorators[0], Diagnostics.Decorators_may_not_be_applied_to_this_parameters);
4219            }
4220
4221            return withJSDoc(finishNode(node, pos), hasJSDoc);
4222        }
4223
4224        const savedTopLevel = topLevel;
4225        topLevel = false;
4226
4227        const modifiers = combineDecoratorsAndModifiers(decorators, parseModifiers());
4228        const dotDotDotToken = parseOptionalToken(SyntaxKind.DotDotDotToken);
4229
4230        if (!allowAmbiguity && !isParameterNameStart()) {
4231            return undefined;
4232        }
4233
4234        const node = withJSDoc(
4235            finishNode(
4236                factory.createParameterDeclaration(
4237                    modifiers,
4238                    dotDotDotToken,
4239                    parseNameOfParameter(modifiers),
4240                    parseOptionalToken(SyntaxKind.QuestionToken),
4241                    parseTypeAnnotation(),
4242                    parseInitializer()
4243                ),
4244                pos
4245            ),
4246            hasJSDoc
4247        );
4248        topLevel = savedTopLevel;
4249        return node;
4250    }
4251
4252    function parseReturnType(returnToken: SyntaxKind.EqualsGreaterThanToken, isType: boolean): TypeNode;
4253    function parseReturnType(returnToken: SyntaxKind.ColonToken | SyntaxKind.EqualsGreaterThanToken, isType: boolean): TypeNode | undefined;
4254    function parseReturnType(returnToken: SyntaxKind.ColonToken | SyntaxKind.EqualsGreaterThanToken, isType: boolean) {
4255        if (shouldParseReturnType(returnToken, isType)) {
4256            return allowConditionalTypesAnd(parseTypeOrTypePredicate);
4257        }
4258    }
4259
4260    function shouldParseReturnType(returnToken: SyntaxKind.ColonToken | SyntaxKind.EqualsGreaterThanToken, isType: boolean): boolean {
4261        if (returnToken === SyntaxKind.EqualsGreaterThanToken) {
4262            parseExpected(returnToken);
4263            return true;
4264        }
4265        else if (parseOptional(SyntaxKind.ColonToken)) {
4266            return true;
4267        }
4268        else if (isType && token() === SyntaxKind.EqualsGreaterThanToken) {
4269            // This is easy to get backward, especially in type contexts, so parse the type anyway
4270            parseErrorAtCurrentToken(Diagnostics._0_expected, tokenToString(SyntaxKind.ColonToken));
4271            nextToken();
4272            return true;
4273        }
4274        return false;
4275    }
4276
4277    function parseParametersWorker(flags: SignatureFlags, allowAmbiguity: true): NodeArray<ParameterDeclaration>;
4278    function parseParametersWorker(flags: SignatureFlags, allowAmbiguity: false): NodeArray<ParameterDeclaration> | undefined;
4279    function parseParametersWorker(flags: SignatureFlags, allowAmbiguity: boolean): NodeArray<ParameterDeclaration> | undefined {
4280        // FormalParameters [Yield,Await]: (modified)
4281        //      [empty]
4282        //      FormalParameterList[?Yield,Await]
4283        //
4284        // FormalParameter[Yield,Await]: (modified)
4285        //      BindingElement[?Yield,Await]
4286        //
4287        // BindingElement [Yield,Await]: (modified)
4288        //      SingleNameBinding[?Yield,?Await]
4289        //      BindingPattern[?Yield,?Await]Initializer [In, ?Yield,?Await] opt
4290        //
4291        // SingleNameBinding [Yield,Await]:
4292        //      BindingIdentifier[?Yield,?Await]Initializer [In, ?Yield,?Await] opt
4293        const savedYieldContext = inYieldContext();
4294        const savedAwaitContext = inAwaitContext();
4295
4296        setYieldContext(!!(flags & SignatureFlags.Yield));
4297        setAwaitContext(!!(flags & SignatureFlags.Await));
4298
4299        const parameters = flags & SignatureFlags.JSDoc ?
4300            parseDelimitedList(ParsingContext.JSDocParameters, parseJSDocParameter) :
4301            parseDelimitedList(ParsingContext.Parameters, () => allowAmbiguity ? parseParameter(savedAwaitContext) : parseParameterForSpeculation(savedAwaitContext));
4302
4303        setYieldContext(savedYieldContext);
4304        setAwaitContext(savedAwaitContext);
4305
4306        return parameters;
4307    }
4308
4309    function parseParameters(flags: SignatureFlags): NodeArray<ParameterDeclaration> {
4310        // FormalParameters [Yield,Await]: (modified)
4311        //      [empty]
4312        //      FormalParameterList[?Yield,Await]
4313        //
4314        // FormalParameter[Yield,Await]: (modified)
4315        //      BindingElement[?Yield,Await]
4316        //
4317        // BindingElement [Yield,Await]: (modified)
4318        //      SingleNameBinding[?Yield,?Await]
4319        //      BindingPattern[?Yield,?Await]Initializer [In, ?Yield,?Await] opt
4320        //
4321        // SingleNameBinding [Yield,Await]:
4322        //      BindingIdentifier[?Yield,?Await]Initializer [In, ?Yield,?Await] opt
4323        if (!parseExpected(SyntaxKind.OpenParenToken)) {
4324            return createMissingList<ParameterDeclaration>();
4325        }
4326
4327        const parameters = parseParametersWorker(flags, /*allowAmbiguity*/ true);
4328        parseExpected(SyntaxKind.CloseParenToken);
4329        return parameters;
4330    }
4331
4332    function parseTypeMemberSemicolon() {
4333        // We allow type members to be separated by commas or (possibly ASI) semicolons.
4334        // First check if it was a comma.  If so, we're done with the member.
4335        if (parseOptional(SyntaxKind.CommaToken)) {
4336            return;
4337        }
4338
4339        // Didn't have a comma.  We must have a (possible ASI) semicolon.
4340        parseSemicolon();
4341    }
4342
4343    function parseSignatureMember(kind: SyntaxKind.CallSignature | SyntaxKind.ConstructSignature): CallSignatureDeclaration | ConstructSignatureDeclaration {
4344        const pos = getNodePos();
4345        const hasJSDoc = hasPrecedingJSDocComment();
4346        if (kind === SyntaxKind.ConstructSignature) {
4347            parseExpected(SyntaxKind.NewKeyword);
4348        }
4349
4350        const typeParameters = parseTypeParameters();
4351        const parameters = parseParameters(SignatureFlags.Type);
4352        const type = parseReturnType(SyntaxKind.ColonToken, /*isType*/ true);
4353        parseTypeMemberSemicolon();
4354        const node = kind === SyntaxKind.CallSignature
4355            ? factory.createCallSignature(typeParameters, parameters, type)
4356            : factory.createConstructSignature(typeParameters, parameters, type);
4357        return withJSDoc(finishNode(node, pos), hasJSDoc);
4358    }
4359
4360    function isIndexSignature(): boolean {
4361        return token() === SyntaxKind.OpenBracketToken && lookAhead(isUnambiguouslyIndexSignature);
4362    }
4363
4364    function isUnambiguouslyIndexSignature() {
4365        // The only allowed sequence is:
4366        //
4367        //   [id:
4368        //
4369        // However, for error recovery, we also check the following cases:
4370        //
4371        //   [...
4372        //   [id,
4373        //   [id?,
4374        //   [id?:
4375        //   [id?]
4376        //   [public id
4377        //   [private id
4378        //   [protected id
4379        //   []
4380        //
4381        nextToken();
4382        if (token() === SyntaxKind.DotDotDotToken || token() === SyntaxKind.CloseBracketToken) {
4383            return true;
4384        }
4385
4386        if (isModifierKind(token())) {
4387            nextToken();
4388            if (isIdentifier()) {
4389                return true;
4390            }
4391        }
4392        else if (!isIdentifier()) {
4393            return false;
4394        }
4395        else {
4396            // Skip the identifier
4397            nextToken();
4398        }
4399
4400        // A colon signifies a well formed indexer
4401        // A comma should be a badly formed indexer because comma expressions are not allowed
4402        // in computed properties.
4403        if (token() === SyntaxKind.ColonToken || token() === SyntaxKind.CommaToken) {
4404            return true;
4405        }
4406
4407        // Question mark could be an indexer with an optional property,
4408        // or it could be a conditional expression in a computed property.
4409        if (token() !== SyntaxKind.QuestionToken) {
4410            return false;
4411        }
4412
4413        // If any of the following tokens are after the question mark, it cannot
4414        // be a conditional expression, so treat it as an indexer.
4415        nextToken();
4416        return token() === SyntaxKind.ColonToken || token() === SyntaxKind.CommaToken || token() === SyntaxKind.CloseBracketToken;
4417    }
4418
4419    function parseIndexSignatureDeclaration(pos: number, hasJSDoc: boolean, decorators: NodeArray<Decorator> | undefined, modifiers: NodeArray<Modifier> | undefined): IndexSignatureDeclaration {
4420        const parameters = parseBracketedList<ParameterDeclaration>(ParsingContext.Parameters, () => parseParameter(/*inOuterAwaitContext*/ false), SyntaxKind.OpenBracketToken, SyntaxKind.CloseBracketToken);
4421        const type = parseTypeAnnotation();
4422        parseTypeMemberSemicolon();
4423        const node = factory.createIndexSignature(modifiers, parameters, type);
4424        (node as Mutable<IndexSignatureDeclaration>).illegalDecorators = decorators;
4425        return withJSDoc(finishNode(node, pos), hasJSDoc);
4426    }
4427
4428    function parsePropertyOrMethodSignature(pos: number, hasJSDoc: boolean, modifiers: NodeArray<Modifier> | undefined): PropertySignature | MethodSignature {
4429        const name = parsePropertyName();
4430        const questionToken = parseOptionalToken(SyntaxKind.QuestionToken);
4431        let node: PropertySignature | MethodSignature;
4432        if (token() === SyntaxKind.OpenParenToken || token() === SyntaxKind.LessThanToken) {
4433            // Method signatures don't exist in expression contexts.  So they have neither
4434            // [Yield] nor [Await]
4435            const typeParameters = parseTypeParameters();
4436            const parameters = parseParameters(SignatureFlags.Type);
4437            const type = parseReturnType(SyntaxKind.ColonToken, /*isType*/ true);
4438            node = factory.createMethodSignature(modifiers, name, questionToken, typeParameters, parameters, type);
4439        }
4440        else {
4441            const type = parseTypeAnnotation();
4442            node = factory.createPropertySignature(modifiers, name, questionToken, type);
4443            // Although type literal properties cannot not have initializers, we attempt
4444            // to parse an initializer so we can report in the checker that an interface
4445            // property or type literal property cannot have an initializer.
4446            if (token() === SyntaxKind.EqualsToken) (node as Mutable<PropertySignature>).initializer = parseInitializer();
4447        }
4448        parseTypeMemberSemicolon();
4449        return withJSDoc(finishNode(node, pos), hasJSDoc);
4450    }
4451
4452    function isTypeMemberStart(): boolean {
4453        // Return true if we have the start of a signature member
4454        if (token() === SyntaxKind.OpenParenToken ||
4455            token() === SyntaxKind.LessThanToken ||
4456            token() === SyntaxKind.GetKeyword ||
4457            token() === SyntaxKind.SetKeyword) {
4458            return true;
4459        }
4460        let idToken = false;
4461        // Eat up all modifiers, but hold on to the last one in case it is actually an identifier
4462        while (isModifierKind(token())) {
4463            idToken = true;
4464            nextToken();
4465        }
4466        // Index signatures and computed property names are type members
4467        if (token() === SyntaxKind.OpenBracketToken) {
4468            return true;
4469        }
4470        // Try to get the first property-like token following all modifiers
4471        if (isLiteralPropertyName()) {
4472            idToken = true;
4473            nextToken();
4474        }
4475        // If we were able to get any potential identifier, check that it is
4476        // the start of a member declaration
4477        if (idToken) {
4478            return token() === SyntaxKind.OpenParenToken ||
4479                token() === SyntaxKind.LessThanToken ||
4480                token() === SyntaxKind.QuestionToken ||
4481                token() === SyntaxKind.ColonToken ||
4482                token() === SyntaxKind.CommaToken ||
4483                canParseSemicolon();
4484        }
4485        return false;
4486    }
4487
4488    function parseTypeMember(): TypeElement {
4489        if (token() === SyntaxKind.OpenParenToken || token() === SyntaxKind.LessThanToken) {
4490            return parseSignatureMember(SyntaxKind.CallSignature);
4491        }
4492        if (token() === SyntaxKind.NewKeyword && lookAhead(nextTokenIsOpenParenOrLessThan)) {
4493            return parseSignatureMember(SyntaxKind.ConstructSignature);
4494        }
4495        const pos = getNodePos();
4496        const hasJSDoc = hasPrecedingJSDocComment();
4497        const modifiers = parseModifiers();
4498        if (parseContextualModifier(SyntaxKind.GetKeyword)) {
4499            return parseAccessorDeclaration(pos, hasJSDoc, /*decorators*/ undefined, modifiers, SyntaxKind.GetAccessor, SignatureFlags.Type);
4500        }
4501
4502        if (parseContextualModifier(SyntaxKind.SetKeyword)) {
4503            return parseAccessorDeclaration(pos, hasJSDoc, /*decorators*/ undefined, modifiers, SyntaxKind.SetAccessor, SignatureFlags.Type);
4504        }
4505
4506        if (isIndexSignature()) {
4507            return parseIndexSignatureDeclaration(pos, hasJSDoc, /*decorators*/ undefined, modifiers);
4508        }
4509        return parsePropertyOrMethodSignature(pos, hasJSDoc, modifiers);
4510    }
4511
4512    function nextTokenIsOpenParenOrLessThan() {
4513        nextToken();
4514        return token() === SyntaxKind.OpenParenToken || token() === SyntaxKind.LessThanToken;
4515    }
4516
4517    function nextTokenIsDot() {
4518        return nextToken() === SyntaxKind.DotToken;
4519    }
4520
4521    function nextTokenIsOpenParenOrLessThanOrDot() {
4522        switch (nextToken()) {
4523            case SyntaxKind.OpenParenToken:
4524            case SyntaxKind.LessThanToken:
4525            case SyntaxKind.DotToken:
4526                return true;
4527        }
4528        return false;
4529    }
4530
4531    function parseTypeLiteral(): TypeLiteralNode {
4532        const pos = getNodePos();
4533        return finishNode(factory.createTypeLiteralNode(parseObjectTypeMembers()), pos);
4534    }
4535
4536    function parseObjectTypeMembers(): NodeArray<TypeElement> {
4537        let members: NodeArray<TypeElement>;
4538        if (parseExpected(SyntaxKind.OpenBraceToken)) {
4539            members = parseList(ParsingContext.TypeMembers, parseTypeMember);
4540            parseExpected(SyntaxKind.CloseBraceToken);
4541        }
4542        else {
4543            members = createMissingList<TypeElement>();
4544        }
4545
4546        return members;
4547    }
4548
4549    function isStartOfMappedType() {
4550        nextToken();
4551        if (token() === SyntaxKind.PlusToken || token() === SyntaxKind.MinusToken) {
4552            return nextToken() === SyntaxKind.ReadonlyKeyword;
4553        }
4554        if (token() === SyntaxKind.ReadonlyKeyword) {
4555            nextToken();
4556        }
4557        return token() === SyntaxKind.OpenBracketToken && nextTokenIsIdentifier() && nextToken() === SyntaxKind.InKeyword;
4558    }
4559
4560    function parseMappedTypeParameter() {
4561        const pos = getNodePos();
4562        const name = parseIdentifierName();
4563        parseExpected(SyntaxKind.InKeyword);
4564        const type = parseType();
4565        return finishNode(factory.createTypeParameterDeclaration(/*modifiers*/ undefined, name, type, /*defaultType*/ undefined), pos);
4566    }
4567
4568    function parseMappedType() {
4569        const pos = getNodePos();
4570        parseExpected(SyntaxKind.OpenBraceToken);
4571        let readonlyToken: ReadonlyKeyword | PlusToken | MinusToken | undefined;
4572        if (token() === SyntaxKind.ReadonlyKeyword || token() === SyntaxKind.PlusToken || token() === SyntaxKind.MinusToken) {
4573            readonlyToken = parseTokenNode<ReadonlyKeyword | PlusToken | MinusToken>();
4574            if (readonlyToken.kind !== SyntaxKind.ReadonlyKeyword) {
4575                parseExpected(SyntaxKind.ReadonlyKeyword);
4576            }
4577        }
4578        parseExpected(SyntaxKind.OpenBracketToken);
4579        const typeParameter = parseMappedTypeParameter();
4580        const nameType = parseOptional(SyntaxKind.AsKeyword) ? parseType() : undefined;
4581        parseExpected(SyntaxKind.CloseBracketToken);
4582        let questionToken: QuestionToken | PlusToken | MinusToken | undefined;
4583        if (token() === SyntaxKind.QuestionToken || token() === SyntaxKind.PlusToken || token() === SyntaxKind.MinusToken) {
4584            questionToken = parseTokenNode<QuestionToken | PlusToken | MinusToken>();
4585            if (questionToken.kind !== SyntaxKind.QuestionToken) {
4586                parseExpected(SyntaxKind.QuestionToken);
4587            }
4588        }
4589        const type = parseTypeAnnotation();
4590        parseSemicolon();
4591        const members = parseList(ParsingContext.TypeMembers, parseTypeMember);
4592        parseExpected(SyntaxKind.CloseBraceToken);
4593        return finishNode(factory.createMappedTypeNode(readonlyToken, typeParameter, nameType, questionToken, type, members), pos);
4594    }
4595
4596    function parseTupleElementType() {
4597        const pos = getNodePos();
4598        if (parseOptional(SyntaxKind.DotDotDotToken)) {
4599            return finishNode(factory.createRestTypeNode(parseType()), pos);
4600        }
4601        const type = parseType();
4602        if (isJSDocNullableType(type) && type.pos === type.type.pos) {
4603            const node = factory.createOptionalTypeNode(type.type);
4604            setTextRange(node, type);
4605            (node as Mutable<Node>).flags = type.flags;
4606            return node;
4607        }
4608        return type;
4609    }
4610
4611    function isNextTokenColonOrQuestionColon() {
4612        return nextToken() === SyntaxKind.ColonToken || (token() === SyntaxKind.QuestionToken && nextToken() === SyntaxKind.ColonToken);
4613    }
4614
4615    function isTupleElementName() {
4616        if (token() === SyntaxKind.DotDotDotToken) {
4617            return tokenIsIdentifierOrKeyword(nextToken()) && isNextTokenColonOrQuestionColon();
4618        }
4619        return tokenIsIdentifierOrKeyword(token()) && isNextTokenColonOrQuestionColon();
4620    }
4621
4622    function parseTupleElementNameOrTupleElementType() {
4623        if (lookAhead(isTupleElementName)) {
4624            const pos = getNodePos();
4625            const hasJSDoc = hasPrecedingJSDocComment();
4626            const dotDotDotToken = parseOptionalToken(SyntaxKind.DotDotDotToken);
4627            const name = parseIdentifierName();
4628            const questionToken = parseOptionalToken(SyntaxKind.QuestionToken);
4629            parseExpected(SyntaxKind.ColonToken);
4630            const type = parseTupleElementType();
4631            const node = factory.createNamedTupleMember(dotDotDotToken, name, questionToken, type);
4632            return withJSDoc(finishNode(node, pos), hasJSDoc);
4633        }
4634        return parseTupleElementType();
4635    }
4636
4637    function parseTupleType(): TupleTypeNode {
4638        const pos = getNodePos();
4639        return finishNode(
4640            factory.createTupleTypeNode(
4641                parseBracketedList(ParsingContext.TupleElementTypes, parseTupleElementNameOrTupleElementType, SyntaxKind.OpenBracketToken, SyntaxKind.CloseBracketToken)
4642            ),
4643            pos
4644        );
4645    }
4646
4647    function parseParenthesizedType(): TypeNode {
4648        const pos = getNodePos();
4649        parseExpected(SyntaxKind.OpenParenToken);
4650        const type = parseType();
4651        parseExpected(SyntaxKind.CloseParenToken);
4652        return finishNode(factory.createParenthesizedType(type), pos);
4653    }
4654
4655    function parseModifiersForConstructorType(): NodeArray<Modifier> | undefined {
4656        let modifiers: NodeArray<Modifier> | undefined;
4657        if (token() === SyntaxKind.AbstractKeyword) {
4658            const pos = getNodePos();
4659            nextToken();
4660            const modifier = finishNode(factory.createToken(SyntaxKind.AbstractKeyword), pos);
4661            modifiers = createNodeArray<Modifier>([modifier], pos);
4662        }
4663        return modifiers;
4664    }
4665
4666    function parseFunctionOrConstructorType(): TypeNode {
4667        const pos = getNodePos();
4668        const hasJSDoc = hasPrecedingJSDocComment();
4669        const modifiers = parseModifiersForConstructorType();
4670        const isConstructorType = parseOptional(SyntaxKind.NewKeyword);
4671        const typeParameters = parseTypeParameters();
4672        const parameters = parseParameters(SignatureFlags.Type);
4673        const type = parseReturnType(SyntaxKind.EqualsGreaterThanToken, /*isType*/ false);
4674        const node = isConstructorType
4675            ? factory.createConstructorTypeNode(modifiers, typeParameters, parameters, type)
4676            : factory.createFunctionTypeNode(typeParameters, parameters, type);
4677        if (!isConstructorType) (node as Mutable<FunctionTypeNode>).modifiers = modifiers;
4678        return withJSDoc(finishNode(node, pos), hasJSDoc);
4679    }
4680
4681    function parseKeywordAndNoDot(): TypeNode | undefined {
4682        const node = parseTokenNode<TypeNode>();
4683        return token() === SyntaxKind.DotToken ? undefined : node;
4684    }
4685
4686    function parseLiteralTypeNode(negative?: boolean): LiteralTypeNode {
4687        const pos = getNodePos();
4688        if (negative) {
4689            nextToken();
4690        }
4691        let expression: BooleanLiteral | NullLiteral | LiteralExpression | PrefixUnaryExpression =
4692            token() === SyntaxKind.TrueKeyword || token() === SyntaxKind.FalseKeyword || token() === SyntaxKind.NullKeyword ?
4693                parseTokenNode<BooleanLiteral | NullLiteral>() :
4694                parseLiteralLikeNode(token()) as LiteralExpression;
4695        if (negative) {
4696            expression = finishNode(factory.createPrefixUnaryExpression(SyntaxKind.MinusToken, expression), pos);
4697        }
4698        return finishNode(factory.createLiteralTypeNode(expression), pos);
4699    }
4700
4701    function isStartOfTypeOfImportType() {
4702        nextToken();
4703        return token() === SyntaxKind.ImportKeyword;
4704    }
4705
4706    function parseImportTypeAssertions(): ImportTypeAssertionContainer {
4707        const pos = getNodePos();
4708        const openBracePosition = scanner.getTokenPos();
4709        parseExpected(SyntaxKind.OpenBraceToken);
4710        const multiLine = scanner.hasPrecedingLineBreak();
4711        parseExpected(SyntaxKind.AssertKeyword);
4712        parseExpected(SyntaxKind.ColonToken);
4713        const clause = parseAssertClause(/*skipAssertKeyword*/ true);
4714        if (!parseExpected(SyntaxKind.CloseBraceToken)) {
4715            const lastError = lastOrUndefined(parseDiagnostics);
4716            if (lastError && lastError.code === Diagnostics._0_expected.code) {
4717                addRelatedInfo(
4718                    lastError,
4719                    createDetachedDiagnostic(fileName, openBracePosition, 1, Diagnostics.The_parser_expected_to_find_a_1_to_match_the_0_token_here, "{", "}")
4720                );
4721            }
4722        }
4723        return finishNode(factory.createImportTypeAssertionContainer(clause, multiLine), pos);
4724    }
4725
4726    function parseImportType(): ImportTypeNode {
4727        sourceFlags |= NodeFlags.PossiblyContainsDynamicImport;
4728        const pos = getNodePos();
4729        const isTypeOf = parseOptional(SyntaxKind.TypeOfKeyword);
4730        parseExpected(SyntaxKind.ImportKeyword);
4731        parseExpected(SyntaxKind.OpenParenToken);
4732        const type = parseType();
4733        let assertions: ImportTypeAssertionContainer | undefined;
4734        if (parseOptional(SyntaxKind.CommaToken)) {
4735            assertions = parseImportTypeAssertions();
4736        }
4737        parseExpected(SyntaxKind.CloseParenToken);
4738        const qualifier = parseOptional(SyntaxKind.DotToken) ? parseEntityNameOfTypeReference() : undefined;
4739        const typeArguments = parseTypeArgumentsOfTypeReference();
4740        return finishNode(factory.createImportTypeNode(type, assertions, qualifier, typeArguments, isTypeOf), pos);
4741    }
4742
4743    function nextTokenIsNumericOrBigIntLiteral() {
4744        nextToken();
4745        return token() === SyntaxKind.NumericLiteral || token() === SyntaxKind.BigIntLiteral;
4746    }
4747
4748    function parseNonArrayType(): TypeNode {
4749        switch (token()) {
4750            case SyntaxKind.AnyKeyword:
4751            case SyntaxKind.UnknownKeyword:
4752            case SyntaxKind.StringKeyword:
4753            case SyntaxKind.NumberKeyword:
4754            case SyntaxKind.BigIntKeyword:
4755            case SyntaxKind.SymbolKeyword:
4756            case SyntaxKind.BooleanKeyword:
4757            case SyntaxKind.UndefinedKeyword:
4758            case SyntaxKind.NeverKeyword:
4759            case SyntaxKind.ObjectKeyword:
4760                // If these are followed by a dot, then parse these out as a dotted type reference instead.
4761                return tryParse(parseKeywordAndNoDot) || parseTypeReference();
4762            case SyntaxKind.AsteriskEqualsToken:
4763                // If there is '*=', treat it as * followed by postfix =
4764                scanner.reScanAsteriskEqualsToken();
4765                // falls through
4766            case SyntaxKind.AsteriskToken:
4767                return parseJSDocAllType();
4768            case SyntaxKind.QuestionQuestionToken:
4769                // If there is '??', treat it as prefix-'?' in JSDoc type.
4770                scanner.reScanQuestionToken();
4771                // falls through
4772            case SyntaxKind.QuestionToken:
4773                return parseJSDocUnknownOrNullableType();
4774            case SyntaxKind.FunctionKeyword:
4775                return parseJSDocFunctionType();
4776            case SyntaxKind.ExclamationToken:
4777                return parseJSDocNonNullableType();
4778            case SyntaxKind.NoSubstitutionTemplateLiteral:
4779            case SyntaxKind.StringLiteral:
4780            case SyntaxKind.NumericLiteral:
4781            case SyntaxKind.BigIntLiteral:
4782            case SyntaxKind.TrueKeyword:
4783            case SyntaxKind.FalseKeyword:
4784            case SyntaxKind.NullKeyword:
4785                return parseLiteralTypeNode();
4786            case SyntaxKind.MinusToken:
4787                return lookAhead(nextTokenIsNumericOrBigIntLiteral) ? parseLiteralTypeNode(/*negative*/ true) : parseTypeReference();
4788            case SyntaxKind.VoidKeyword:
4789                return parseTokenNode<TypeNode>();
4790            case SyntaxKind.ThisKeyword: {
4791                const thisKeyword = parseThisTypeNode();
4792                if (token() === SyntaxKind.IsKeyword && !scanner.hasPrecedingLineBreak()) {
4793                    return parseThisTypePredicate(thisKeyword);
4794                }
4795                else {
4796                    return thisKeyword;
4797                }
4798            }
4799            case SyntaxKind.TypeOfKeyword:
4800                return lookAhead(isStartOfTypeOfImportType) ? parseImportType() : parseTypeQuery();
4801            case SyntaxKind.OpenBraceToken:
4802                return lookAhead(isStartOfMappedType) ? parseMappedType() : parseTypeLiteral();
4803            case SyntaxKind.OpenBracketToken:
4804                return parseTupleType();
4805            case SyntaxKind.OpenParenToken:
4806                return parseParenthesizedType();
4807            case SyntaxKind.ImportKeyword:
4808                return parseImportType();
4809            case SyntaxKind.AssertsKeyword:
4810                return lookAhead(nextTokenIsIdentifierOrKeywordOnSameLine) ? parseAssertsTypePredicate() : parseTypeReference();
4811            case SyntaxKind.TemplateHead:
4812                return parseTemplateType();
4813            default:
4814                return parseTypeReference();
4815        }
4816    }
4817
4818    function isStartOfType(inStartOfParameter?: boolean): boolean {
4819        switch (token()) {
4820            case SyntaxKind.AnyKeyword:
4821            case SyntaxKind.UnknownKeyword:
4822            case SyntaxKind.StringKeyword:
4823            case SyntaxKind.NumberKeyword:
4824            case SyntaxKind.BigIntKeyword:
4825            case SyntaxKind.BooleanKeyword:
4826            case SyntaxKind.ReadonlyKeyword:
4827            case SyntaxKind.SymbolKeyword:
4828            case SyntaxKind.UniqueKeyword:
4829            case SyntaxKind.VoidKeyword:
4830            case SyntaxKind.UndefinedKeyword:
4831            case SyntaxKind.NullKeyword:
4832            case SyntaxKind.ThisKeyword:
4833            case SyntaxKind.TypeOfKeyword:
4834            case SyntaxKind.NeverKeyword:
4835            case SyntaxKind.OpenBraceToken:
4836            case SyntaxKind.OpenBracketToken:
4837            case SyntaxKind.LessThanToken:
4838            case SyntaxKind.BarToken:
4839            case SyntaxKind.AmpersandToken:
4840            case SyntaxKind.NewKeyword:
4841            case SyntaxKind.StringLiteral:
4842            case SyntaxKind.NumericLiteral:
4843            case SyntaxKind.BigIntLiteral:
4844            case SyntaxKind.TrueKeyword:
4845            case SyntaxKind.FalseKeyword:
4846            case SyntaxKind.ObjectKeyword:
4847            case SyntaxKind.AsteriskToken:
4848            case SyntaxKind.QuestionToken:
4849            case SyntaxKind.ExclamationToken:
4850            case SyntaxKind.DotDotDotToken:
4851            case SyntaxKind.InferKeyword:
4852            case SyntaxKind.ImportKeyword:
4853            case SyntaxKind.AssertsKeyword:
4854            case SyntaxKind.NoSubstitutionTemplateLiteral:
4855            case SyntaxKind.TemplateHead:
4856                return true;
4857            case SyntaxKind.FunctionKeyword:
4858                return !inStartOfParameter;
4859            case SyntaxKind.MinusToken:
4860                return !inStartOfParameter && lookAhead(nextTokenIsNumericOrBigIntLiteral);
4861            case SyntaxKind.OpenParenToken:
4862                // Only consider '(' the start of a type if followed by ')', '...', an identifier, a modifier,
4863                // or something that starts a type. We don't want to consider things like '(1)' a type.
4864                return !inStartOfParameter && lookAhead(isStartOfParenthesizedOrFunctionType);
4865            default:
4866                return isIdentifier();
4867        }
4868    }
4869
4870    function isStartOfParenthesizedOrFunctionType() {
4871        nextToken();
4872        return token() === SyntaxKind.CloseParenToken || isStartOfParameter(/*isJSDocParameter*/ false) || isStartOfType();
4873    }
4874
4875    function parsePostfixTypeOrHigher(): TypeNode {
4876        const pos = getNodePos();
4877        let type = parseNonArrayType();
4878        while (!scanner.hasPrecedingLineBreak()) {
4879            switch (token()) {
4880                case SyntaxKind.ExclamationToken:
4881                    nextToken();
4882                    type = finishNode(factory.createJSDocNonNullableType(type, /*postfix*/ true), pos);
4883                    break;
4884                case SyntaxKind.QuestionToken:
4885                    // If next token is start of a type we have a conditional type
4886                    if (lookAhead(nextTokenIsStartOfType)) {
4887                        return type;
4888                    }
4889                    nextToken();
4890                    type = finishNode(factory.createJSDocNullableType(type, /*postfix*/ true), pos);
4891                    break;
4892                case SyntaxKind.OpenBracketToken:
4893                    parseExpected(SyntaxKind.OpenBracketToken);
4894                    if (isStartOfType()) {
4895                        const indexType = parseType();
4896                        parseExpected(SyntaxKind.CloseBracketToken);
4897                        type = finishNode(factory.createIndexedAccessTypeNode(type, indexType), pos);
4898                    }
4899                    else {
4900                        parseExpected(SyntaxKind.CloseBracketToken);
4901                        type = finishNode(factory.createArrayTypeNode(type), pos);
4902                    }
4903                    break;
4904                default:
4905                    return type;
4906            }
4907        }
4908        return type;
4909    }
4910
4911    function parseTypeOperator(operator: SyntaxKind.KeyOfKeyword | SyntaxKind.UniqueKeyword | SyntaxKind.ReadonlyKeyword) {
4912        const pos = getNodePos();
4913        parseExpected(operator);
4914        return finishNode(factory.createTypeOperatorNode(operator, parseTypeOperatorOrHigher()), pos);
4915    }
4916
4917    function tryParseConstraintOfInferType() {
4918        if (parseOptional(SyntaxKind.ExtendsKeyword)) {
4919            const constraint = disallowConditionalTypesAnd(parseType);
4920            if (inDisallowConditionalTypesContext() || token() !== SyntaxKind.QuestionToken) {
4921                return constraint;
4922            }
4923        }
4924    }
4925
4926    function parseTypeParameterOfInferType(): TypeParameterDeclaration {
4927        const pos = getNodePos();
4928        const name = parseIdentifier();
4929        const constraint = tryParse(tryParseConstraintOfInferType);
4930        const node = factory.createTypeParameterDeclaration(/*modifiers*/ undefined, name, constraint);
4931        return finishNode(node, pos);
4932    }
4933
4934    function parseInferType(): InferTypeNode {
4935        const pos = getNodePos();
4936        parseExpected(SyntaxKind.InferKeyword);
4937        return finishNode(factory.createInferTypeNode(parseTypeParameterOfInferType()), pos);
4938    }
4939
4940    function parseTypeOperatorOrHigher(): TypeNode {
4941        const operator = token();
4942        switch (operator) {
4943            case SyntaxKind.KeyOfKeyword:
4944            case SyntaxKind.UniqueKeyword:
4945            case SyntaxKind.ReadonlyKeyword:
4946                return parseTypeOperator(operator);
4947            case SyntaxKind.InferKeyword:
4948                return parseInferType();
4949        }
4950        return allowConditionalTypesAnd(parsePostfixTypeOrHigher);
4951    }
4952
4953    function parseFunctionOrConstructorTypeToError(
4954        isInUnionType: boolean
4955    ): TypeNode | undefined {
4956        // the function type and constructor type shorthand notation
4957        // are not allowed directly in unions and intersections, but we'll
4958        // try to parse them gracefully and issue a helpful message.
4959        if (isStartOfFunctionTypeOrConstructorType()) {
4960            const type = parseFunctionOrConstructorType();
4961            let diagnostic: DiagnosticMessage;
4962            if (isFunctionTypeNode(type)) {
4963                diagnostic = isInUnionType
4964                    ? Diagnostics.Function_type_notation_must_be_parenthesized_when_used_in_a_union_type
4965                    : Diagnostics.Function_type_notation_must_be_parenthesized_when_used_in_an_intersection_type;
4966            }
4967            else {
4968                diagnostic = isInUnionType
4969                    ? Diagnostics.Constructor_type_notation_must_be_parenthesized_when_used_in_a_union_type
4970                    : Diagnostics.Constructor_type_notation_must_be_parenthesized_when_used_in_an_intersection_type;
4971
4972            }
4973            parseErrorAtRange(type, diagnostic);
4974            return type;
4975        }
4976        return undefined;
4977    }
4978
4979    function parseUnionOrIntersectionType(
4980        operator: SyntaxKind.BarToken | SyntaxKind.AmpersandToken,
4981        parseConstituentType: () => TypeNode,
4982        createTypeNode: (types: NodeArray<TypeNode>) => UnionOrIntersectionTypeNode
4983    ): TypeNode {
4984        const pos = getNodePos();
4985        const isUnionType = operator === SyntaxKind.BarToken;
4986        const hasLeadingOperator = parseOptional(operator);
4987        let type = hasLeadingOperator && parseFunctionOrConstructorTypeToError(isUnionType)
4988            || parseConstituentType();
4989        if (token() === operator || hasLeadingOperator) {
4990            const types = [type];
4991            while (parseOptional(operator)) {
4992                types.push(parseFunctionOrConstructorTypeToError(isUnionType) || parseConstituentType());
4993            }
4994            type = finishNode(createTypeNode(createNodeArray(types, pos)), pos);
4995        }
4996        return type;
4997    }
4998
4999    function parseIntersectionTypeOrHigher(): TypeNode {
5000        return parseUnionOrIntersectionType(SyntaxKind.AmpersandToken, parseTypeOperatorOrHigher, factory.createIntersectionTypeNode);
5001    }
5002
5003    function parseUnionTypeOrHigher(): TypeNode {
5004        return parseUnionOrIntersectionType(SyntaxKind.BarToken, parseIntersectionTypeOrHigher, factory.createUnionTypeNode);
5005    }
5006
5007    function nextTokenIsNewKeyword(): boolean {
5008        nextToken();
5009        return token() === SyntaxKind.NewKeyword;
5010    }
5011
5012    function isStartOfFunctionTypeOrConstructorType(): boolean {
5013        if (token() === SyntaxKind.LessThanToken) {
5014            return true;
5015        }
5016        if (token() === SyntaxKind.OpenParenToken && lookAhead(isUnambiguouslyStartOfFunctionType)) {
5017            return true;
5018        }
5019        return token() === SyntaxKind.NewKeyword ||
5020            token() === SyntaxKind.AbstractKeyword && lookAhead(nextTokenIsNewKeyword);
5021    }
5022
5023    function skipParameterStart(): boolean {
5024        if (isModifierKind(token())) {
5025            // Skip modifiers
5026            parseModifiers();
5027        }
5028        if (isIdentifier() || token() === SyntaxKind.ThisKeyword) {
5029            nextToken();
5030            return true;
5031        }
5032        if (token() === SyntaxKind.OpenBracketToken || token() === SyntaxKind.OpenBraceToken) {
5033            // Return true if we can parse an array or object binding pattern with no errors
5034            const previousErrorCount = parseDiagnostics.length;
5035            parseIdentifierOrPattern();
5036            return previousErrorCount === parseDiagnostics.length;
5037        }
5038        return false;
5039    }
5040
5041    function isUnambiguouslyStartOfFunctionType() {
5042        nextToken();
5043        if (token() === SyntaxKind.CloseParenToken || token() === SyntaxKind.DotDotDotToken) {
5044            // ( )
5045            // ( ...
5046            return true;
5047        }
5048        if (skipParameterStart()) {
5049            // We successfully skipped modifiers (if any) and an identifier or binding pattern,
5050            // now see if we have something that indicates a parameter declaration
5051            if (token() === SyntaxKind.ColonToken || token() === SyntaxKind.CommaToken ||
5052                token() === SyntaxKind.QuestionToken || token() === SyntaxKind.EqualsToken) {
5053                // ( xxx :
5054                // ( xxx ,
5055                // ( xxx ?
5056                // ( xxx =
5057                return true;
5058            }
5059            if (token() === SyntaxKind.CloseParenToken) {
5060                nextToken();
5061                if (token() === SyntaxKind.EqualsGreaterThanToken) {
5062                    // ( xxx ) =>
5063                    return true;
5064                }
5065            }
5066        }
5067        return false;
5068    }
5069
5070    function parseTypeOrTypePredicate(): TypeNode {
5071        const pos = getNodePos();
5072        const typePredicateVariable = isIdentifier() && tryParse(parseTypePredicatePrefix);
5073        const type = parseType();
5074        if (typePredicateVariable) {
5075            return finishNode(factory.createTypePredicateNode(/*assertsModifier*/ undefined, typePredicateVariable, type), pos);
5076        }
5077        else {
5078            return type;
5079        }
5080    }
5081
5082    function parseTypePredicatePrefix() {
5083        const id = parseIdentifier();
5084        if (token() === SyntaxKind.IsKeyword && !scanner.hasPrecedingLineBreak()) {
5085            nextToken();
5086            return id;
5087        }
5088    }
5089
5090    function parseAssertsTypePredicate(): TypeNode {
5091        const pos = getNodePos();
5092        const assertsModifier = parseExpectedToken(SyntaxKind.AssertsKeyword);
5093        const parameterName = token() === SyntaxKind.ThisKeyword ? parseThisTypeNode() : parseIdentifier();
5094        const type = parseOptional(SyntaxKind.IsKeyword) ? parseType() : undefined;
5095        return finishNode(factory.createTypePredicateNode(assertsModifier, parameterName, type), pos);
5096    }
5097
5098    function parseType(): TypeNode {
5099        if (contextFlags & NodeFlags.TypeExcludesFlags) {
5100            return doOutsideOfContext(NodeFlags.TypeExcludesFlags, parseType);
5101        }
5102
5103        if (isStartOfFunctionTypeOrConstructorType()) {
5104            return parseFunctionOrConstructorType();
5105        }
5106        const pos = getNodePos();
5107        const type = parseUnionTypeOrHigher();
5108        if (!inDisallowConditionalTypesContext() && !scanner.hasPrecedingLineBreak() && parseOptional(SyntaxKind.ExtendsKeyword)) {
5109            // The type following 'extends' is not permitted to be another conditional type
5110            const extendsType = disallowConditionalTypesAnd(parseType);
5111            parseExpected(SyntaxKind.QuestionToken);
5112            const trueType = allowConditionalTypesAnd(parseType);
5113            parseExpected(SyntaxKind.ColonToken);
5114            const falseType = allowConditionalTypesAnd(parseType);
5115            return finishNode(factory.createConditionalTypeNode(type, extendsType, trueType, falseType), pos);
5116        }
5117        return type;
5118    }
5119
5120    function parseEtsType(pos: number, name: string): TypeNode {
5121        const contextFlagsToClear = NodeFlags.TypeExcludesFlags & contextFlags;
5122        if (contextFlagsToClear) {
5123            // clear the requested context flags
5124            setContextFlag(/*val*/ false, contextFlagsToClear);
5125            const result = parseEtsTypeReferenceWorker(pos, name);
5126            // restore the context flags we just cleared
5127            setContextFlag(/*val*/ true, contextFlagsToClear);
5128            return result;
5129        }
5130
5131        return parseEtsTypeReferenceWorker(pos, name);
5132    }
5133
5134    function parseEtsTypeReferenceWorker(pos: number, name: string): TypeNode {
5135        return finishVirtualNode(
5136            factory.createTypeReferenceNode(
5137                finishVirtualNode(factory.createIdentifier(name), pos, pos)
5138            ),
5139            pos, pos
5140        );
5141    }
5142
5143    function parseTypeAnnotation(): TypeNode | undefined {
5144        return parseOptional(SyntaxKind.ColonToken) ? parseType() : undefined;
5145    }
5146
5147    // EXPRESSIONS
5148    function isStartOfLeftHandSideExpression(): boolean {
5149        switch (token()) {
5150            case SyntaxKind.ThisKeyword:
5151            case SyntaxKind.SuperKeyword:
5152            case SyntaxKind.NullKeyword:
5153            case SyntaxKind.TrueKeyword:
5154            case SyntaxKind.FalseKeyword:
5155            case SyntaxKind.NumericLiteral:
5156            case SyntaxKind.BigIntLiteral:
5157            case SyntaxKind.StringLiteral:
5158            case SyntaxKind.NoSubstitutionTemplateLiteral:
5159            case SyntaxKind.TemplateHead:
5160            case SyntaxKind.OpenParenToken:
5161            case SyntaxKind.OpenBracketToken:
5162            case SyntaxKind.OpenBraceToken:
5163            case SyntaxKind.FunctionKeyword:
5164            case SyntaxKind.ClassKeyword:
5165            case SyntaxKind.NewKeyword:
5166            case SyntaxKind.SlashToken:
5167            case SyntaxKind.SlashEqualsToken:
5168            case SyntaxKind.Identifier:
5169                return true;
5170            case SyntaxKind.StructKeyword:
5171                return inEtsContext();
5172            case SyntaxKind.ImportKeyword:
5173                return lookAhead(nextTokenIsOpenParenOrLessThanOrDot);
5174            default:
5175                return isIdentifier();
5176        }
5177    }
5178
5179    function isStartOfExpression(): boolean {
5180        if (isStartOfLeftHandSideExpression()) {
5181            return true;
5182        }
5183
5184        switch (token()) {
5185            case SyntaxKind.PlusToken:
5186            case SyntaxKind.MinusToken:
5187            case SyntaxKind.TildeToken:
5188            case SyntaxKind.ExclamationToken:
5189            case SyntaxKind.DeleteKeyword:
5190            case SyntaxKind.TypeOfKeyword:
5191            case SyntaxKind.VoidKeyword:
5192            case SyntaxKind.PlusPlusToken:
5193            case SyntaxKind.MinusMinusToken:
5194            case SyntaxKind.LessThanToken:
5195            case SyntaxKind.AwaitKeyword:
5196            case SyntaxKind.YieldKeyword:
5197            case SyntaxKind.PrivateIdentifier:
5198                // Yield/await always starts an expression.  Either it is an identifier (in which case
5199                // it is definitely an expression).  Or it's a keyword (either because we're in
5200                // a generator or async function, or in strict mode (or both)) and it started a yield or await expression.
5201                return true;
5202            case SyntaxKind.DotToken:
5203                return isValidExtendOrStylesContext();
5204            default:
5205                // Error tolerance.  If we see the start of some binary operator, we consider
5206                // that the start of an expression.  That way we'll parse out a missing identifier,
5207                // give a good message about an identifier being missing, and then consume the
5208                // rest of the binary expression.
5209                if (isBinaryOperator()) {
5210                    return true;
5211                }
5212
5213                return isIdentifier();
5214        }
5215    }
5216
5217    function isValidExtendOrStylesContext(): boolean {
5218        return (inEtsExtendComponentsContext() && !!extendEtsComponentDeclaration) ||
5219            (inEtsStylesComponentsContext() && !!stylesEtsComponentDeclaration);
5220    }
5221
5222    function isStartOfExpressionStatement(): boolean {
5223        // As per the grammar, none of '{' or 'function' or 'class' can start an expression statement.
5224        return token() !== SyntaxKind.OpenBraceToken &&
5225            token() !== SyntaxKind.FunctionKeyword &&
5226            token() !== SyntaxKind.ClassKeyword &&
5227            (!inEtsContext() || token() !== SyntaxKind.StructKeyword) &&
5228            token() !== SyntaxKind.AtToken &&
5229            isStartOfExpression();
5230    }
5231
5232    function parseExpression(): Expression {
5233        // Expression[in]:
5234        //      AssignmentExpression[in]
5235        //      Expression[in] , AssignmentExpression[in]
5236
5237        // clear the decorator context when parsing Expression, as it should be unambiguous when parsing a decorator
5238        const saveDecoratorContext = inDecoratorContext();
5239        if (saveDecoratorContext) {
5240            setDecoratorContext(/*val*/ false);
5241        }
5242
5243        const pos = getNodePos();
5244        let expr = parseAssignmentExpressionOrHigher(/*allowReturnTypeInArrowFunction*/ true);
5245        let operatorToken: BinaryOperatorToken;
5246        while ((operatorToken = parseOptionalToken(SyntaxKind.CommaToken))) {
5247            expr = makeBinaryExpression(expr, operatorToken, parseAssignmentExpressionOrHigher(/*allowReturnTypeInArrowFunction*/ true), pos);
5248        }
5249
5250        if (saveDecoratorContext) {
5251            setDecoratorContext(/*val*/ true);
5252        }
5253        return expr;
5254    }
5255
5256    function parseInitializer(): Expression | undefined {
5257        return parseOptional(SyntaxKind.EqualsToken) ? parseAssignmentExpressionOrHigher(/*allowReturnTypeInArrowFunction*/ true) : undefined;
5258    }
5259
5260    function parseAssignmentExpressionOrHigher(allowReturnTypeInArrowFunction: boolean): Expression {
5261        //  AssignmentExpression[in,yield]:
5262        //      1) ConditionalExpression[?in,?yield]
5263        //      2) LeftHandSideExpression = AssignmentExpression[?in,?yield]
5264        //      3) LeftHandSideExpression AssignmentOperator AssignmentExpression[?in,?yield]
5265        //      4) ArrowFunctionExpression[?in,?yield]
5266        //      5) AsyncArrowFunctionExpression[in,yield,await]
5267        //      6) [+Yield] YieldExpression[?In]
5268        //
5269        // Note: for ease of implementation we treat productions '2' and '3' as the same thing.
5270        // (i.e. they're both BinaryExpressions with an assignment operator in it).
5271
5272        // First, do the simple check if we have a YieldExpression (production '6').
5273        if (isYieldExpression()) {
5274            return parseYieldExpression();
5275        }
5276
5277        // Then, check if we have an arrow function (production '4' and '5') that starts with a parenthesized
5278        // parameter list or is an async arrow function.
5279        // AsyncArrowFunctionExpression:
5280        //      1) async[no LineTerminator here]AsyncArrowBindingIdentifier[?Yield][no LineTerminator here]=>AsyncConciseBody[?In]
5281        //      2) CoverCallExpressionAndAsyncArrowHead[?Yield, ?Await][no LineTerminator here]=>AsyncConciseBody[?In]
5282        // Production (1) of AsyncArrowFunctionExpression is parsed in "tryParseAsyncSimpleArrowFunctionExpression".
5283        // And production (2) is parsed in "tryParseParenthesizedArrowFunctionExpression".
5284        //
5285        // If we do successfully parse arrow-function, we must *not* recurse for productions 1, 2 or 3. An ArrowFunction is
5286        // not a LeftHandSideExpression, nor does it start a ConditionalExpression.  So we are done
5287        // with AssignmentExpression if we see one.
5288        const arrowExpression = tryParseParenthesizedArrowFunctionExpression(allowReturnTypeInArrowFunction) || tryParseAsyncSimpleArrowFunctionExpression(allowReturnTypeInArrowFunction);
5289        if (arrowExpression) {
5290            return arrowExpression;
5291        }
5292
5293        // Now try to see if we're in production '1', '2' or '3'.  A conditional expression can
5294        // start with a LogicalOrExpression, while the assignment productions can only start with
5295        // LeftHandSideExpressions.
5296        //
5297        // So, first, we try to just parse out a BinaryExpression.  If we get something that is a
5298        // LeftHandSide or higher, then we can try to parse out the assignment expression part.
5299        // Otherwise, we try to parse out the conditional expression bit.  We want to allow any
5300        // binary expression here, so we pass in the 'lowest' precedence here so that it matches
5301        // and consumes anything.
5302        const pos = getNodePos();
5303        const expr = parseBinaryExpressionOrHigher(OperatorPrecedence.Lowest);
5304
5305        // To avoid a look-ahead, we did not handle the case of an arrow function with a single un-parenthesized
5306        // parameter ('x => ...') above. We handle it here by checking if the parsed expression was a single
5307        // identifier and the current token is an arrow.
5308        if (expr.kind === SyntaxKind.Identifier && token() === SyntaxKind.EqualsGreaterThanToken) {
5309            return parseSimpleArrowFunctionExpression(pos, expr as Identifier, allowReturnTypeInArrowFunction, /*asyncModifier*/ undefined);
5310        }
5311
5312        // Now see if we might be in cases '2' or '3'.
5313        // If the expression was a LHS expression, and we have an assignment operator, then
5314        // we're in '2' or '3'. Consume the assignment and return.
5315        //
5316        // Note: we call reScanGreaterToken so that we get an appropriately merged token
5317        // for cases like `> > =` becoming `>>=`
5318        if (isLeftHandSideExpression(expr) && isAssignmentOperator(reScanGreaterToken())) {
5319            return makeBinaryExpression(expr, parseTokenNode(), parseAssignmentExpressionOrHigher(allowReturnTypeInArrowFunction), pos);
5320        }
5321
5322        // It's a CallExpression with open brace followed, therefore, we think it's an EtsComponentExpression
5323        if ((inBuildContext() || inBuilderContext()) && inUICallbackContext() && isCallExpression(expr) && token() === SyntaxKind.OpenBraceToken) {
5324            return makeEtsComponentExpression(expr, pos);
5325        }
5326
5327        // It wasn't an assignment or a lambda.  This is a conditional expression:
5328        return parseConditionalExpressionRest(expr, pos, allowReturnTypeInArrowFunction);
5329    }
5330
5331    function makeEtsComponentExpression(expression: Expression, pos: number): EtsComponentExpression {
5332        const name = (<CallExpression>expression).expression;
5333        const body = parseFunctionBlock(SignatureFlags.None);
5334        return finishNode(factory.createEtsComponentExpression(<Identifier>name, (<CallExpression>expression).arguments, body), pos);
5335    }
5336
5337    function isYieldExpression(): boolean {
5338        if (token() === SyntaxKind.YieldKeyword) {
5339            // If we have a 'yield' keyword, and this is a context where yield expressions are
5340            // allowed, then definitely parse out a yield expression.
5341            if (inYieldContext()) {
5342                return true;
5343            }
5344
5345            // We're in a context where 'yield expr' is not allowed.  However, if we can
5346            // definitely tell that the user was trying to parse a 'yield expr' and not
5347            // just a normal expr that start with a 'yield' identifier, then parse out
5348            // a 'yield expr'.  We can then report an error later that they are only
5349            // allowed in generator expressions.
5350            //
5351            // for example, if we see 'yield(foo)', then we'll have to treat that as an
5352            // invocation expression of something called 'yield'.  However, if we have
5353            // 'yield foo' then that is not legal as a normal expression, so we can
5354            // definitely recognize this as a yield expression.
5355            //
5356            // for now we just check if the next token is an identifier.  More heuristics
5357            // can be added here later as necessary.  We just need to make sure that we
5358            // don't accidentally consume something legal.
5359            return lookAhead(nextTokenIsIdentifierOrKeywordOrLiteralOnSameLine);
5360        }
5361
5362        return false;
5363    }
5364
5365    function nextTokenIsIdentifierOnSameLine() {
5366        nextToken();
5367        return !scanner.hasPrecedingLineBreak() && isIdentifier();
5368    }
5369
5370    function parseYieldExpression(): YieldExpression {
5371        const pos = getNodePos();
5372
5373        // YieldExpression[In] :
5374        //      yield
5375        //      yield [no LineTerminator here] [Lexical goal InputElementRegExp]AssignmentExpression[?In, Yield]
5376        //      yield [no LineTerminator here] * [Lexical goal InputElementRegExp]AssignmentExpression[?In, Yield]
5377        nextToken();
5378
5379        if (!scanner.hasPrecedingLineBreak() &&
5380            (token() === SyntaxKind.AsteriskToken || isStartOfExpression())) {
5381            return finishNode(
5382                factory.createYieldExpression(
5383                    parseOptionalToken(SyntaxKind.AsteriskToken),
5384                    parseAssignmentExpressionOrHigher(/*allowReturnTypeInArrowFunction*/ true)
5385                ),
5386                pos
5387            );
5388        }
5389        else {
5390            // if the next token is not on the same line as yield.  or we don't have an '*' or
5391            // the start of an expression, then this is just a simple "yield" expression.
5392            return finishNode(factory.createYieldExpression(/*asteriskToken*/ undefined, /*expression*/ undefined), pos);
5393        }
5394    }
5395
5396    function parseSimpleArrowFunctionExpression(pos: number, identifier: Identifier, allowReturnTypeInArrowFunction: boolean, asyncModifier?: NodeArray<Modifier> | undefined): ArrowFunction {
5397        Debug.assert(token() === SyntaxKind.EqualsGreaterThanToken, "parseSimpleArrowFunctionExpression should only have been called if we had a =>");
5398        const parameter = factory.createParameterDeclaration(
5399            /*modifiers*/ undefined,
5400            /*dotDotDotToken*/ undefined,
5401            identifier,
5402            /*questionToken*/ undefined,
5403            /*type*/ undefined,
5404            /*initializer*/ undefined
5405        );
5406        finishNode(parameter, identifier.pos);
5407
5408        const parameters = createNodeArray<ParameterDeclaration>([parameter], parameter.pos, parameter.end);
5409        const equalsGreaterThanToken = parseExpectedToken(SyntaxKind.EqualsGreaterThanToken);
5410        let originUIContextFlag = inUICallbackContext();
5411        let originNoEtsComponentContextFlag = inNoEtsComponentContext();
5412        setUICallbackContext(inSyntaxComponentContext() && !inSyntaxDataSourceContext());
5413        if (inSyntaxComponentContext() && !inSyntaxDataSourceContext()) {
5414            setSyntaxComponentContext(false);
5415        }
5416        setNoEtsComponentContext(!inUICallbackContext());
5417        const body = parseArrowFunctionExpressionBody(/*isAsync*/ !!asyncModifier, allowReturnTypeInArrowFunction);
5418        const node = factory.createArrowFunction(asyncModifier, /*typeParameters*/ undefined, parameters, /*type*/ undefined, equalsGreaterThanToken, body);
5419        setUICallbackContext(originUIContextFlag);
5420        setNoEtsComponentContext(originNoEtsComponentContextFlag);
5421        return addJSDocComment(finishNode(node, pos));
5422    }
5423
5424    function tryParseParenthesizedArrowFunctionExpression(allowReturnTypeInArrowFunction: boolean): Expression | undefined {
5425        const triState = isParenthesizedArrowFunctionExpression();
5426        if (triState === Tristate.False) {
5427            // It's definitely not a parenthesized arrow function expression.
5428            return undefined;
5429        }
5430
5431        // If we definitely have an arrow function, then we can just parse one, not requiring a
5432        // following => or { token. Otherwise, we *might* have an arrow function.  Try to parse
5433        // it out, but don't allow any ambiguity, and return 'undefined' if this could be an
5434        // expression instead.
5435        return triState === Tristate.True ?
5436            parseParenthesizedArrowFunctionExpression(/*allowAmbiguity*/ true, /*allowReturnTypeInArrowFunction*/ true) :
5437            tryParse(() => parsePossibleParenthesizedArrowFunctionExpression(allowReturnTypeInArrowFunction));
5438    }
5439
5440    //  True        -> We definitely expect a parenthesized arrow function here.
5441    //  False       -> There *cannot* be a parenthesized arrow function here.
5442    //  Unknown     -> There *might* be a parenthesized arrow function here.
5443    //                 Speculatively look ahead to be sure, and rollback if not.
5444    function isParenthesizedArrowFunctionExpression(): Tristate {
5445        if (token() === SyntaxKind.OpenParenToken || token() === SyntaxKind.LessThanToken || token() === SyntaxKind.AsyncKeyword) {
5446            return lookAhead(isParenthesizedArrowFunctionExpressionWorker);
5447        }
5448
5449        if (token() === SyntaxKind.EqualsGreaterThanToken) {
5450            // ERROR RECOVERY TWEAK:
5451            // If we see a standalone => try to parse it as an arrow function expression as that's
5452            // likely what the user intended to write.
5453            return Tristate.True;
5454        }
5455        // Definitely not a parenthesized arrow function.
5456        return Tristate.False;
5457    }
5458
5459    function isParenthesizedArrowFunctionExpressionWorker() {
5460        if (token() === SyntaxKind.AsyncKeyword) {
5461            nextToken();
5462            if (scanner.hasPrecedingLineBreak()) {
5463                return Tristate.False;
5464            }
5465            if (token() !== SyntaxKind.OpenParenToken && token() !== SyntaxKind.LessThanToken) {
5466                return Tristate.False;
5467            }
5468        }
5469
5470        const first = token();
5471        const second = nextToken();
5472
5473        if (first === SyntaxKind.OpenParenToken) {
5474            if (second === SyntaxKind.CloseParenToken) {
5475                // Simple cases: "() =>", "(): ", and "() {".
5476                // This is an arrow function with no parameters.
5477                // The last one is not actually an arrow function,
5478                // but this is probably what the user intended.
5479                const third = nextToken();
5480                switch (third) {
5481                    case SyntaxKind.EqualsGreaterThanToken:
5482                    case SyntaxKind.ColonToken:
5483                    case SyntaxKind.OpenBraceToken:
5484                        return Tristate.True;
5485                    default:
5486                        return Tristate.False;
5487                }
5488            }
5489
5490            // If encounter "([" or "({", this could be the start of a binding pattern.
5491            // Examples:
5492            //      ([ x ]) => { }
5493            //      ({ x }) => { }
5494            //      ([ x ])
5495            //      ({ x })
5496            if (second === SyntaxKind.OpenBracketToken || second === SyntaxKind.OpenBraceToken) {
5497                return Tristate.Unknown;
5498            }
5499
5500            // Simple case: "(..."
5501            // This is an arrow function with a rest parameter.
5502            if (second === SyntaxKind.DotDotDotToken) {
5503                return Tristate.True;
5504            }
5505
5506            // Check for "(xxx yyy", where xxx is a modifier and yyy is an identifier. This
5507            // isn't actually allowed, but we want to treat it as a lambda so we can provide
5508            // a good error message.
5509            if (isModifierKind(second) && second !== SyntaxKind.AsyncKeyword && lookAhead(nextTokenIsIdentifier)) {
5510                if (nextToken() === SyntaxKind.AsKeyword) {
5511                    // https://github.com/microsoft/TypeScript/issues/44466
5512                    return Tristate.False;
5513                }
5514                return Tristate.True;
5515            }
5516
5517            // If we had "(" followed by something that's not an identifier,
5518            // then this definitely doesn't look like a lambda.  "this" is not
5519            // valid, but we want to parse it and then give a semantic error.
5520            if (!isIdentifier() && second !== SyntaxKind.ThisKeyword) {
5521                return Tristate.False;
5522            }
5523
5524            switch (nextToken()) {
5525                case SyntaxKind.ColonToken:
5526                    // If we have something like "(a:", then we must have a
5527                    // type-annotated parameter in an arrow function expression.
5528                    return Tristate.True;
5529                case SyntaxKind.QuestionToken:
5530                    nextToken();
5531                    // If we have "(a?:" or "(a?," or "(a?=" or "(a?)" then it is definitely a lambda.
5532                    if (token() === SyntaxKind.ColonToken || token() === SyntaxKind.CommaToken || token() === SyntaxKind.EqualsToken || token() === SyntaxKind.CloseParenToken) {
5533                        return Tristate.True;
5534                    }
5535                    // Otherwise it is definitely not a lambda.
5536                    return Tristate.False;
5537                case SyntaxKind.CommaToken:
5538                case SyntaxKind.EqualsToken:
5539                case SyntaxKind.CloseParenToken:
5540                    // If we have "(a," or "(a=" or "(a)" this *could* be an arrow function
5541                    return Tristate.Unknown;
5542            }
5543            // It is definitely not an arrow function
5544            return Tristate.False;
5545        }
5546        else {
5547            Debug.assert(first === SyntaxKind.LessThanToken);
5548
5549            // If we have "<" not followed by an identifier,
5550            // then this definitely is not an arrow function.
5551            if (!isIdentifier()) {
5552                return Tristate.False;
5553            }
5554
5555            // JSX overrides
5556            if (languageVariant === LanguageVariant.JSX) {
5557                const isArrowFunctionInJsx = lookAhead(() => {
5558                    const third = nextToken();
5559                    if (third === SyntaxKind.ExtendsKeyword) {
5560                        const fourth = nextToken();
5561                        switch (fourth) {
5562                            case SyntaxKind.EqualsToken:
5563                            case SyntaxKind.GreaterThanToken:
5564                                return false;
5565                            default:
5566                                return true;
5567                        }
5568                    }
5569                    else if (third === SyntaxKind.CommaToken || third === SyntaxKind.EqualsToken) {
5570                        return true;
5571                    }
5572                    return false;
5573                });
5574
5575                if (isArrowFunctionInJsx) {
5576                    return Tristate.True;
5577                }
5578
5579                return Tristate.False;
5580            }
5581
5582            // This *could* be a parenthesized arrow function.
5583            return Tristate.Unknown;
5584        }
5585    }
5586
5587    function parsePossibleParenthesizedArrowFunctionExpression(allowReturnTypeInArrowFunction: boolean): ArrowFunction | undefined {
5588        const tokenPos = scanner.getTokenPos();
5589        if (notParenthesizedArrow?.has(tokenPos)) {
5590            return undefined;
5591        }
5592
5593        const result = parseParenthesizedArrowFunctionExpression(/*allowAmbiguity*/ false, allowReturnTypeInArrowFunction);
5594        if (!result) {
5595            (notParenthesizedArrow || (notParenthesizedArrow = new Set())).add(tokenPos);
5596        }
5597
5598        return result;
5599    }
5600
5601    function tryParseAsyncSimpleArrowFunctionExpression(allowReturnTypeInArrowFunction: boolean): ArrowFunction | undefined {
5602        // We do a check here so that we won't be doing unnecessarily call to "lookAhead"
5603        if (token() === SyntaxKind.AsyncKeyword) {
5604            if (lookAhead(isUnParenthesizedAsyncArrowFunctionWorker) === Tristate.True) {
5605                const pos = getNodePos();
5606                const asyncModifier = parseModifiersForArrowFunction();
5607                const expr = parseBinaryExpressionOrHigher(OperatorPrecedence.Lowest);
5608                return parseSimpleArrowFunctionExpression(pos, expr as Identifier, allowReturnTypeInArrowFunction, asyncModifier);
5609            }
5610        }
5611        return undefined;
5612    }
5613
5614    function isUnParenthesizedAsyncArrowFunctionWorker(): Tristate {
5615        // AsyncArrowFunctionExpression:
5616        //      1) async[no LineTerminator here]AsyncArrowBindingIdentifier[?Yield][no LineTerminator here]=>AsyncConciseBody[?In]
5617        //      2) CoverCallExpressionAndAsyncArrowHead[?Yield, ?Await][no LineTerminator here]=>AsyncConciseBody[?In]
5618        if (token() === SyntaxKind.AsyncKeyword) {
5619            nextToken();
5620            // If the "async" is followed by "=>" token then it is not a beginning of an async arrow-function
5621            // but instead a simple arrow-function which will be parsed inside "parseAssignmentExpressionOrHigher"
5622            if (scanner.hasPrecedingLineBreak() || token() === SyntaxKind.EqualsGreaterThanToken) {
5623                return Tristate.False;
5624            }
5625            // Check for un-parenthesized AsyncArrowFunction
5626            const expr = parseBinaryExpressionOrHigher(OperatorPrecedence.Lowest);
5627            if (!scanner.hasPrecedingLineBreak() && expr.kind === SyntaxKind.Identifier && token() === SyntaxKind.EqualsGreaterThanToken) {
5628                return Tristate.True;
5629            }
5630        }
5631
5632        return Tristate.False;
5633    }
5634
5635    function parseParenthesizedArrowFunctionExpression(allowAmbiguity: boolean, allowReturnTypeInArrowFunction: boolean): ArrowFunction | undefined {
5636        const pos = getNodePos();
5637        const hasJSDoc = hasPrecedingJSDocComment();
5638        const modifiers = parseModifiersForArrowFunction();
5639        const isAsync = some(modifiers, isAsyncModifier) ? SignatureFlags.Await : SignatureFlags.None;
5640        // Arrow functions are never generators.
5641        //
5642        // If we're speculatively parsing a signature for a parenthesized arrow function, then
5643        // we have to have a complete parameter list.  Otherwise we might see something like
5644        // a => (b => c)
5645        // And think that "(b =>" was actually a parenthesized arrow function with a missing
5646        // close paren.
5647        const typeParameters = parseTypeParameters();
5648
5649        let parameters: NodeArray<ParameterDeclaration>;
5650        if (!parseExpected(SyntaxKind.OpenParenToken)) {
5651            if (!allowAmbiguity) {
5652                return undefined;
5653            }
5654            parameters = createMissingList<ParameterDeclaration>();
5655        }
5656        else {
5657            if (!allowAmbiguity) {
5658                const maybeParameters = parseParametersWorker(isAsync, allowAmbiguity);
5659                if (!maybeParameters) {
5660                    return undefined;
5661                }
5662                parameters = maybeParameters;
5663            }
5664            else {
5665                parameters = parseParametersWorker(isAsync, allowAmbiguity);
5666            }
5667            if (!parseExpected(SyntaxKind.CloseParenToken) && !allowAmbiguity) {
5668                return undefined;
5669            }
5670        }
5671
5672        const hasReturnColon = token() === SyntaxKind.ColonToken;
5673        const type = parseReturnType(SyntaxKind.ColonToken, /*isType*/ false);
5674        if (type && !allowAmbiguity && typeHasArrowFunctionBlockingParseError(type)) {
5675            return undefined;
5676        }
5677
5678        // Parsing a signature isn't enough.
5679        // Parenthesized arrow signatures often look like other valid expressions.
5680        // For instance:
5681        //  - "(x = 10)" is an assignment expression parsed as a signature with a default parameter value.
5682        //  - "(x,y)" is a comma expression parsed as a signature with two parameters.
5683        //  - "a ? (b): c" will have "(b):" parsed as a signature with a return type annotation.
5684        //  - "a ? (b): function() {}" will too, since function() is a valid JSDoc function type.
5685        //  - "a ? (b): (function() {})" as well, but inside of a parenthesized type with an arbitrary amount of nesting.
5686        //
5687        // So we need just a bit of lookahead to ensure that it can only be a signature.
5688
5689        let unwrappedType = type;
5690        while (unwrappedType?.kind === SyntaxKind.ParenthesizedType) {
5691            unwrappedType = (unwrappedType as ParenthesizedTypeNode).type;  // Skip parens if need be
5692        }
5693
5694        const hasJSDocFunctionType = unwrappedType && isJSDocFunctionType(unwrappedType);
5695        if (!allowAmbiguity && token() !== SyntaxKind.EqualsGreaterThanToken && (hasJSDocFunctionType || token() !== SyntaxKind.OpenBraceToken)) {
5696            // Returning undefined here will cause our caller to rewind to where we started from.
5697                return undefined;
5698        }
5699
5700        // If we have an arrow, then try to parse the body. Even if not, try to parse if we
5701        // have an opening brace, just in case we're in an error state.
5702        const lastToken = token();
5703        const equalsGreaterThanToken = parseExpectedToken(SyntaxKind.EqualsGreaterThanToken);
5704        let originUIContextFlag = inUICallbackContext();
5705        let originNoEtsComponentContextFlag = inNoEtsComponentContext();
5706        setUICallbackContext(inSyntaxComponentContext() && !inSyntaxDataSourceContext());
5707        if (inSyntaxComponentContext() && !inSyntaxDataSourceContext()) {
5708            setSyntaxComponentContext(false);
5709        }
5710        setNoEtsComponentContext(!inUICallbackContext());
5711        const body = (lastToken === SyntaxKind.EqualsGreaterThanToken || lastToken === SyntaxKind.OpenBraceToken)
5712            ? parseArrowFunctionExpressionBody(some(modifiers, isAsyncModifier), allowReturnTypeInArrowFunction)
5713            : parseIdentifier();
5714        setUICallbackContext(originUIContextFlag);
5715        setNoEtsComponentContext(originNoEtsComponentContextFlag);
5716        // Given:
5717        //     x ? y => ({ y }) : z => ({ z })
5718        // We try to parse the body of the first arrow function by looking at:
5719        //     ({ y }) : z => ({ z })
5720        // This is a valid arrow function with "z" as the return type.
5721        //
5722        // But, if we're in the true side of a conditional expression, this colon
5723        // terminates the expression, so we cannot allow a return type if we aren't
5724        // certain whether or not the preceding text was parsed as a parameter list.
5725        //
5726        // For example,
5727        //     a() ? (b: number, c?: string): void => d() : e
5728        // is determined by isParenthesizedArrowFunctionExpression to unambiguously
5729        // be an arrow expression, so we allow a return type.
5730        if (!allowReturnTypeInArrowFunction && hasReturnColon) {
5731            // However, if the arrow function we were able to parse is followed by another colon
5732            // as in:
5733            //     a ? (x): string => x : null
5734            // Then allow the arrow function, and treat the second colon as terminating
5735            // the conditional expression. It's okay to do this because this code would
5736            // be a syntax error in JavaScript (as the second colon shouldn't be there).
5737            if (token() !== SyntaxKind.ColonToken) {
5738                return undefined;
5739            }
5740        }
5741
5742        const node = factory.createArrowFunction(modifiers, typeParameters, parameters, type, equalsGreaterThanToken, body);
5743        return withJSDoc(finishNode(node, pos), hasJSDoc);
5744    }
5745
5746    function parseArrowFunctionExpressionBody(isAsync: boolean, allowReturnTypeInArrowFunction: boolean): Block | Expression {
5747        if (token() === SyntaxKind.OpenBraceToken) {
5748            return parseFunctionBlock(isAsync ? SignatureFlags.Await : SignatureFlags.None);
5749        }
5750
5751        if (token() !== SyntaxKind.SemicolonToken &&
5752            token() !== SyntaxKind.FunctionKeyword &&
5753            token() !== SyntaxKind.ClassKeyword &&
5754            (!inEtsContext() || token() !== SyntaxKind.StructKeyword) &&
5755            isStartOfStatement() &&
5756            !isStartOfExpressionStatement()) {
5757            // Check if we got a plain statement (i.e. no expression-statements, no function/class expressions/declarations)
5758            //
5759            // Here we try to recover from a potential error situation in the case where the
5760            // user meant to supply a block. For example, if the user wrote:
5761            //
5762            //  a =>
5763            //      let v = 0;
5764            //  }
5765            //
5766            // they may be missing an open brace.  Check to see if that's the case so we can
5767            // try to recover better.  If we don't do this, then the next close curly we see may end
5768            // up preemptively closing the containing construct.
5769            //
5770            // Note: even when 'IgnoreMissingOpenBrace' is passed, parseBody will still error.
5771            return parseFunctionBlock(SignatureFlags.IgnoreMissingOpenBrace | (isAsync ? SignatureFlags.Await : SignatureFlags.None));
5772        }
5773
5774        const savedTopLevel = topLevel;
5775        topLevel = false;
5776        const node = isAsync
5777            ? doInAwaitContext(() => parseAssignmentExpressionOrHigher(allowReturnTypeInArrowFunction))
5778            : doOutsideOfAwaitContext(() => parseAssignmentExpressionOrHigher(allowReturnTypeInArrowFunction));
5779        topLevel = savedTopLevel;
5780        return node;
5781    }
5782
5783    function parseConditionalExpressionRest(leftOperand: Expression, pos: number, allowReturnTypeInArrowFunction: boolean): Expression {
5784        // Note: we are passed in an expression which was produced from parseBinaryExpressionOrHigher.
5785        const questionToken = parseOptionalToken(SyntaxKind.QuestionToken);
5786        if (!questionToken) {
5787            return leftOperand;
5788        }
5789
5790        // Note: we explicitly 'allowIn' in the whenTrue part of the condition expression, and
5791        // we do not that for the 'whenFalse' part.
5792        let colonToken;
5793        return finishNode(
5794            factory.createConditionalExpression(
5795                leftOperand,
5796                questionToken,
5797                doOutsideOfContext(disallowInAndDecoratorContext, () => parseAssignmentExpressionOrHigher(/*allowReturnTypeInArrowFunction*/ false)),
5798                colonToken = parseExpectedToken(SyntaxKind.ColonToken),
5799                nodeIsPresent(colonToken)
5800                    ? parseAssignmentExpressionOrHigher(allowReturnTypeInArrowFunction)
5801                    : createMissingNode(SyntaxKind.Identifier, /*reportAtCurrentPosition*/ false, Diagnostics._0_expected, tokenToString(SyntaxKind.ColonToken))
5802            ),
5803            pos
5804        );
5805    }
5806
5807    function parseBinaryExpressionOrHigher(precedence: OperatorPrecedence): Expression {
5808        const pos = getNodePos();
5809        const leftOperand = parseUnaryExpressionOrHigher();
5810        return parseBinaryExpressionRest(precedence, leftOperand, pos);
5811    }
5812
5813    function isInOrOfKeyword(t: SyntaxKind) {
5814        return t === SyntaxKind.InKeyword || t === SyntaxKind.OfKeyword;
5815    }
5816
5817    function parseBinaryExpressionRest(precedence: OperatorPrecedence, leftOperand: Expression, pos: number): Expression {
5818        while (true) {
5819            // We either have a binary operator here, or we're finished.  We call
5820            // reScanGreaterToken so that we merge token sequences like > and = into >=
5821
5822            reScanGreaterToken();
5823            const newPrecedence = getBinaryOperatorPrecedence(token());
5824
5825            // Check the precedence to see if we should "take" this operator
5826            // - For left associative operator (all operator but **), consume the operator,
5827            //   recursively call the function below, and parse binaryExpression as a rightOperand
5828            //   of the caller if the new precedence of the operator is greater then or equal to the current precedence.
5829            //   For example:
5830            //      a - b - c;
5831            //            ^token; leftOperand = b. Return b to the caller as a rightOperand
5832            //      a * b - c
5833            //            ^token; leftOperand = b. Return b to the caller as a rightOperand
5834            //      a - b * c;
5835            //            ^token; leftOperand = b. Return b * c to the caller as a rightOperand
5836            // - For right associative operator (**), consume the operator, recursively call the function
5837            //   and parse binaryExpression as a rightOperand of the caller if the new precedence of
5838            //   the operator is strictly grater than the current precedence
5839            //   For example:
5840            //      a ** b ** c;
5841            //             ^^token; leftOperand = b. Return b ** c to the caller as a rightOperand
5842            //      a - b ** c;
5843            //            ^^token; leftOperand = b. Return b ** c to the caller as a rightOperand
5844            //      a ** b - c
5845            //             ^token; leftOperand = b. Return b to the caller as a rightOperand
5846            const consumeCurrentOperator = token() === SyntaxKind.AsteriskAsteriskToken ?
5847                newPrecedence >= precedence :
5848                newPrecedence > precedence;
5849
5850            if (!consumeCurrentOperator) {
5851                break;
5852            }
5853
5854            if (token() === SyntaxKind.InKeyword && inDisallowInContext()) {
5855                break;
5856            }
5857
5858            if (token() === SyntaxKind.AsKeyword || token() === SyntaxKind.SatisfiesKeyword) {
5859                // Make sure we *do* perform ASI for constructs like this:
5860                //    var x = foo
5861                //    as (Bar)
5862                // This should be parsed as an initialized variable, followed
5863                // by a function call to 'as' with the argument 'Bar'
5864                if (scanner.hasPrecedingLineBreak()) {
5865                    break;
5866                }
5867                else {
5868                    const keywordKind = token();
5869                    nextToken();
5870                    leftOperand = keywordKind === SyntaxKind.SatisfiesKeyword ? makeSatisfiesExpression(leftOperand, parseType()) :
5871                        makeAsExpression(leftOperand, parseType());
5872                }
5873            }
5874            else {
5875                leftOperand = makeBinaryExpression(leftOperand, parseTokenNode(), parseBinaryExpressionOrHigher(newPrecedence), pos);
5876            }
5877        }
5878
5879        return leftOperand;
5880    }
5881
5882    function isBinaryOperator() {
5883        if (inDisallowInContext() && token() === SyntaxKind.InKeyword) {
5884            return false;
5885        }
5886
5887        return getBinaryOperatorPrecedence(token()) > 0;
5888    }
5889
5890    function makeSatisfiesExpression(left: Expression, right: TypeNode): SatisfiesExpression {
5891        return finishNode(factory.createSatisfiesExpression(left, right), left.pos);
5892    }
5893
5894    function makeBinaryExpression(left: Expression, operatorToken: BinaryOperatorToken, right: Expression, pos: number): BinaryExpression {
5895        return finishNode(factory.createBinaryExpression(left, operatorToken, right), pos);
5896    }
5897
5898    function makeAsExpression(left: Expression, right: TypeNode): AsExpression {
5899        return finishNode(factory.createAsExpression(left, right), left.pos);
5900    }
5901
5902    function parsePrefixUnaryExpression() {
5903        const pos = getNodePos();
5904        return finishNode(factory.createPrefixUnaryExpression(token() as PrefixUnaryOperator, nextTokenAnd(parseSimpleUnaryExpression)), pos);
5905    }
5906
5907    function parseDeleteExpression() {
5908        const pos = getNodePos();
5909        return finishNode(factory.createDeleteExpression(nextTokenAnd(parseSimpleUnaryExpression)), pos);
5910    }
5911
5912    function parseTypeOfExpression() {
5913        const pos = getNodePos();
5914        return finishNode(factory.createTypeOfExpression(nextTokenAnd(parseSimpleUnaryExpression)), pos);
5915    }
5916
5917    function parseVoidExpression() {
5918        const pos = getNodePos();
5919        return finishNode(factory.createVoidExpression(nextTokenAnd(parseSimpleUnaryExpression)), pos);
5920    }
5921
5922    function isAwaitExpression(): boolean {
5923        if (token() === SyntaxKind.AwaitKeyword) {
5924            if (inAwaitContext()) {
5925                return true;
5926            }
5927
5928            // here we are using similar heuristics as 'isYieldExpression'
5929            return lookAhead(nextTokenIsIdentifierOrKeywordOrLiteralOnSameLine);
5930        }
5931
5932        return false;
5933    }
5934
5935    function parseAwaitExpression() {
5936        const pos = getNodePos();
5937        return finishNode(factory.createAwaitExpression(nextTokenAnd(parseSimpleUnaryExpression)), pos);
5938    }
5939
5940    /**
5941     * Parse ES7 exponential expression and await expression
5942     *
5943     * ES7 ExponentiationExpression:
5944     *      1) UnaryExpression[?Yield]
5945     *      2) UpdateExpression[?Yield] ** ExponentiationExpression[?Yield]
5946     *
5947     */
5948    function parseUnaryExpressionOrHigher(): UnaryExpression | BinaryExpression {
5949        /**
5950         * ES7 UpdateExpression:
5951         *      1) LeftHandSideExpression[?Yield]
5952         *      2) LeftHandSideExpression[?Yield][no LineTerminator here]++
5953         *      3) LeftHandSideExpression[?Yield][no LineTerminator here]--
5954         *      4) ++UnaryExpression[?Yield]
5955         *      5) --UnaryExpression[?Yield]
5956         */
5957        if (isUpdateExpression()) {
5958            const pos = getNodePos();
5959            const updateExpression = parseUpdateExpression();
5960            return token() === SyntaxKind.AsteriskAsteriskToken ?
5961                parseBinaryExpressionRest(getBinaryOperatorPrecedence(token()), updateExpression, pos) as BinaryExpression :
5962                updateExpression;
5963        }
5964
5965        /**
5966         * ES7 UnaryExpression:
5967         *      1) UpdateExpression[?yield]
5968         *      2) delete UpdateExpression[?yield]
5969         *      3) void UpdateExpression[?yield]
5970         *      4) typeof UpdateExpression[?yield]
5971         *      5) + UpdateExpression[?yield]
5972         *      6) - UpdateExpression[?yield]
5973         *      7) ~ UpdateExpression[?yield]
5974         *      8) ! UpdateExpression[?yield]
5975         */
5976        const unaryOperator = token();
5977        const simpleUnaryExpression = parseSimpleUnaryExpression();
5978        if (token() === SyntaxKind.AsteriskAsteriskToken) {
5979            const pos = skipTrivia(sourceText, simpleUnaryExpression.pos);
5980            const { end } = simpleUnaryExpression;
5981            if (simpleUnaryExpression.kind === SyntaxKind.TypeAssertionExpression) {
5982                parseErrorAt(pos, end, Diagnostics.A_type_assertion_expression_is_not_allowed_in_the_left_hand_side_of_an_exponentiation_expression_Consider_enclosing_the_expression_in_parentheses);
5983            }
5984            else {
5985                parseErrorAt(pos, end, Diagnostics.An_unary_expression_with_the_0_operator_is_not_allowed_in_the_left_hand_side_of_an_exponentiation_expression_Consider_enclosing_the_expression_in_parentheses, tokenToString(unaryOperator));
5986            }
5987        }
5988        return simpleUnaryExpression;
5989    }
5990
5991    /**
5992     * Parse ES7 simple-unary expression or higher:
5993     *
5994     * ES7 UnaryExpression:
5995     *      1) UpdateExpression[?yield]
5996     *      2) delete UnaryExpression[?yield]
5997     *      3) void UnaryExpression[?yield]
5998     *      4) typeof UnaryExpression[?yield]
5999     *      5) + UnaryExpression[?yield]
6000     *      6) - UnaryExpression[?yield]
6001     *      7) ~ UnaryExpression[?yield]
6002     *      8) ! UnaryExpression[?yield]
6003     *      9) [+Await] await UnaryExpression[?yield]
6004     */
6005    function parseSimpleUnaryExpression(): UnaryExpression {
6006        switch (token()) {
6007            case SyntaxKind.PlusToken:
6008            case SyntaxKind.MinusToken:
6009            case SyntaxKind.TildeToken:
6010            case SyntaxKind.ExclamationToken:
6011                return parsePrefixUnaryExpression();
6012            case SyntaxKind.DeleteKeyword:
6013                return parseDeleteExpression();
6014            case SyntaxKind.TypeOfKeyword:
6015                return parseTypeOfExpression();
6016            case SyntaxKind.VoidKeyword:
6017                return parseVoidExpression();
6018            case SyntaxKind.LessThanToken:
6019                // This is modified UnaryExpression grammar in TypeScript
6020                //  UnaryExpression (modified):
6021                //      < type > UnaryExpression
6022                return parseTypeAssertion();
6023            case SyntaxKind.AwaitKeyword:
6024                if (isAwaitExpression()) {
6025                    return parseAwaitExpression();
6026                }
6027                // falls through
6028            default:
6029                return parseUpdateExpression();
6030        }
6031    }
6032
6033    /**
6034     * Check if the current token can possibly be an ES7 increment expression.
6035     *
6036     * ES7 UpdateExpression:
6037     *      LeftHandSideExpression[?Yield]
6038     *      LeftHandSideExpression[?Yield][no LineTerminator here]++
6039     *      LeftHandSideExpression[?Yield][no LineTerminator here]--
6040     *      ++LeftHandSideExpression[?Yield]
6041     *      --LeftHandSideExpression[?Yield]
6042     */
6043    function isUpdateExpression(): boolean {
6044        // This function is called inside parseUnaryExpression to decide
6045        // whether to call parseSimpleUnaryExpression or call parseUpdateExpression directly
6046        switch (token()) {
6047            case SyntaxKind.PlusToken:
6048            case SyntaxKind.MinusToken:
6049            case SyntaxKind.TildeToken:
6050            case SyntaxKind.ExclamationToken:
6051            case SyntaxKind.DeleteKeyword:
6052            case SyntaxKind.TypeOfKeyword:
6053            case SyntaxKind.VoidKeyword:
6054            case SyntaxKind.AwaitKeyword:
6055                return false;
6056            case SyntaxKind.LessThanToken:
6057                // If we are not in JSX context, we are parsing TypeAssertion which is an UnaryExpression
6058                if (languageVariant !== LanguageVariant.JSX) {
6059                    return false;
6060                }
6061                // We are in JSX context and the token is part of JSXElement.
6062                // falls through
6063            default:
6064                return true;
6065        }
6066    }
6067
6068    /**
6069     * Parse ES7 UpdateExpression. UpdateExpression is used instead of ES6's PostFixExpression.
6070     *
6071     * ES7 UpdateExpression[yield]:
6072     *      1) LeftHandSideExpression[?yield]
6073     *      2) LeftHandSideExpression[?yield] [[no LineTerminator here]]++
6074     *      3) LeftHandSideExpression[?yield] [[no LineTerminator here]]--
6075     *      4) ++LeftHandSideExpression[?yield]
6076     *      5) --LeftHandSideExpression[?yield]
6077     * In TypeScript (2), (3) are parsed as PostfixUnaryExpression. (4), (5) are parsed as PrefixUnaryExpression
6078     */
6079    function parseUpdateExpression(): UpdateExpression {
6080        if (token() === SyntaxKind.PlusPlusToken || token() === SyntaxKind.MinusMinusToken) {
6081            const pos = getNodePos();
6082            return finishNode(factory.createPrefixUnaryExpression(token() as PrefixUnaryOperator, nextTokenAnd(parseLeftHandSideExpressionOrHigher)), pos);
6083        }
6084        else if (languageVariant === LanguageVariant.JSX && token() === SyntaxKind.LessThanToken && lookAhead(nextTokenIsIdentifierOrKeywordOrGreaterThan)) {
6085            // JSXElement is part of primaryExpression
6086            return parseJsxElementOrSelfClosingElementOrFragment(/*inExpressionContext*/ true);
6087        }
6088
6089        const expression = parseLeftHandSideExpressionOrHigher();
6090
6091        Debug.assert(isLeftHandSideExpression(expression));
6092        if ((token() === SyntaxKind.PlusPlusToken || token() === SyntaxKind.MinusMinusToken) && !scanner.hasPrecedingLineBreak()) {
6093            const operator = token() as PostfixUnaryOperator;
6094            nextToken();
6095            return finishNode(factory.createPostfixUnaryExpression(expression, operator), expression.pos);
6096        }
6097
6098        return expression;
6099    }
6100
6101    function parseLeftHandSideExpressionOrHigher(): LeftHandSideExpression {
6102        // Original Ecma:
6103        // LeftHandSideExpression: See 11.2
6104        //      NewExpression
6105        //      CallExpression
6106        //
6107        // Our simplification:
6108        //
6109        // LeftHandSideExpression: See 11.2
6110        //      MemberExpression
6111        //      CallExpression
6112        //
6113        // See comment in parseMemberExpressionOrHigher on how we replaced NewExpression with
6114        // MemberExpression to make our lives easier.
6115        //
6116        // to best understand the below code, it's important to see how CallExpression expands
6117        // out into its own productions:
6118        //
6119        // CallExpression:
6120        //      MemberExpression Arguments
6121        //      CallExpression Arguments
6122        //      CallExpression[Expression]
6123        //      CallExpression.IdentifierName
6124        //      import (AssignmentExpression)
6125        //      super Arguments
6126        //      super.IdentifierName
6127        //
6128        // Because of the recursion in these calls, we need to bottom out first. There are three
6129        // bottom out states we can run into: 1) We see 'super' which must start either of
6130        // the last two CallExpression productions. 2) We see 'import' which must start import call.
6131        // 3)we have a MemberExpression which either completes the LeftHandSideExpression,
6132        // or starts the beginning of the first four CallExpression productions.
6133        const pos = getNodePos();
6134        let expression: MemberExpression;
6135        if (token() === SyntaxKind.ImportKeyword) {
6136            if (lookAhead(nextTokenIsOpenParenOrLessThan)) {
6137                // We don't want to eagerly consume all import keyword as import call expression so we look ahead to find "("
6138                // For example:
6139                //      var foo3 = require("subfolder
6140                //      import * as foo1 from "module-from-node
6141                // We want this import to be a statement rather than import call expression
6142                sourceFlags |= NodeFlags.PossiblyContainsDynamicImport;
6143                expression = parseTokenNode<PrimaryExpression>();
6144            }
6145            else if (lookAhead(nextTokenIsDot)) {
6146                // This is an 'import.*' metaproperty (i.e. 'import.meta')
6147                nextToken(); // advance past the 'import'
6148                nextToken(); // advance past the dot
6149                expression = finishNode(factory.createMetaProperty(SyntaxKind.ImportKeyword, parseIdentifierName()), pos);
6150                sourceFlags |= NodeFlags.PossiblyContainsImportMeta;
6151            }
6152            else {
6153                expression = parseMemberExpressionOrHigher();
6154            }
6155        }
6156        else {
6157            expression = token() === SyntaxKind.SuperKeyword ? parseSuperExpression() : parseMemberExpressionOrHigher();
6158        }
6159
6160        // Now, we *may* be complete.  However, we might have consumed the start of a
6161        // CallExpression or OptionalExpression.  As such, we need to consume the rest
6162        // of it here to be complete.
6163        return parseCallExpressionRest(pos, expression);
6164    }
6165
6166    function parseMemberExpressionOrHigher(): MemberExpression {
6167        // Note: to make our lives simpler, we decompose the NewExpression productions and
6168        // place ObjectCreationExpression and FunctionExpression into PrimaryExpression.
6169        // like so:
6170        //
6171        //   PrimaryExpression : See 11.1
6172        //      this
6173        //      Identifier
6174        //      Literal
6175        //      ArrayLiteral
6176        //      ObjectLiteral
6177        //      (Expression)
6178        //      FunctionExpression
6179        //      new MemberExpression Arguments?
6180        //
6181        //   MemberExpression : See 11.2
6182        //      PrimaryExpression
6183        //      MemberExpression[Expression]
6184        //      MemberExpression.IdentifierName
6185        //
6186        //   CallExpression : See 11.2
6187        //      MemberExpression
6188        //      CallExpression Arguments
6189        //      CallExpression[Expression]
6190        //      CallExpression.IdentifierName
6191        //
6192        // Technically this is ambiguous.  i.e. CallExpression defines:
6193        //
6194        //   CallExpression:
6195        //      CallExpression Arguments
6196        //
6197        // If you see: "new Foo()"
6198        //
6199        // Then that could be treated as a single ObjectCreationExpression, or it could be
6200        // treated as the invocation of "new Foo".  We disambiguate that in code (to match
6201        // the original grammar) by making sure that if we see an ObjectCreationExpression
6202        // we always consume arguments if they are there. So we treat "new Foo()" as an
6203        // object creation only, and not at all as an invocation.  Another way to think
6204        // about this is that for every "new" that we see, we will consume an argument list if
6205        // it is there as part of the *associated* object creation node.  Any additional
6206        // argument lists we see, will become invocation expressions.
6207        //
6208        // Because there are no other places in the grammar now that refer to FunctionExpression
6209        // or ObjectCreationExpression, it is safe to push down into the PrimaryExpression
6210        // production.
6211        //
6212        // Because CallExpression and MemberExpression are left recursive, we need to bottom out
6213        // of the recursion immediately.  So we parse out a primary expression to start with.
6214        const pos = getNodePos();
6215        let expression;
6216
6217        if (inEtsExtendComponentsContext() && extendEtsComponentDeclaration && token() === SyntaxKind.DotToken) {
6218            expression = finishVirtualNode(factory.createIdentifier(extendEtsComponentDeclaration.instance, /*typeArguments*/ undefined, SyntaxKind.Identifier), pos, pos);
6219        }
6220        else if (inEtsStylesComponentsContext() && stylesEtsComponentDeclaration && token() === SyntaxKind.DotToken) {
6221            expression = finishVirtualNode(factory.createIdentifier(stylesEtsComponentDeclaration.instance, /*typeArguments*/ undefined, SyntaxKind.Identifier), pos, pos);
6222        }
6223        else if (inEtsStateStylesContext() && stateStylesRootNode && token() === SyntaxKind.DotToken) {
6224            expression = finishVirtualNode(factory.createIdentifier(`${stateStylesRootNode}Instance`, /*typeArguments*/ undefined, SyntaxKind.Identifier), pos, pos);
6225        }
6226        else {
6227            expression = parsePrimaryExpression();
6228        }
6229        return parseMemberExpressionRest(pos, expression, /*allowOptionalChain*/ true);
6230    }
6231
6232    function parseSuperExpression(): MemberExpression {
6233        const pos = getNodePos();
6234        let expression = parseTokenNode<MemberExpression>();
6235        if (token() === SyntaxKind.LessThanToken) {
6236            const startPos = getNodePos();
6237            const typeArguments = tryParse(parseTypeArgumentsInExpression);
6238            if (typeArguments !== undefined) {
6239                parseErrorAt(startPos, getNodePos(), Diagnostics.super_may_not_use_type_arguments);
6240                if (!isTemplateStartOfTaggedTemplate()) {
6241                    expression = factory.createExpressionWithTypeArguments(expression, typeArguments);
6242                }
6243            }
6244        }
6245
6246        if (token() === SyntaxKind.OpenParenToken || token() === SyntaxKind.DotToken || token() === SyntaxKind.OpenBracketToken) {
6247            return expression;
6248        }
6249
6250        // If we have seen "super" it must be followed by '(' or '.'.
6251        // If it wasn't then just try to parse out a '.' and report an error.
6252        parseExpectedToken(SyntaxKind.DotToken, Diagnostics.super_must_be_followed_by_an_argument_list_or_member_access);
6253        // private names will never work with `super` (`super.#foo`), but that's a semantic error, not syntactic
6254        return finishNode(factory.createPropertyAccessExpression(expression, parseRightSideOfDot(/*allowIdentifierNames*/ true, /*allowPrivateIdentifiers*/ true)), pos);
6255    }
6256
6257    function parseJsxElementOrSelfClosingElementOrFragment(inExpressionContext: boolean, topInvalidNodePosition?: number, openingTag?: JsxOpeningElement | JsxOpeningFragment): JsxElement | JsxSelfClosingElement | JsxFragment {
6258        const pos = getNodePos();
6259        const opening = parseJsxOpeningOrSelfClosingElementOrOpeningFragment(inExpressionContext);
6260        let result: JsxElement | JsxSelfClosingElement | JsxFragment;
6261        if (opening.kind === SyntaxKind.JsxOpeningElement) {
6262            let children = parseJsxChildren(opening);
6263            let closingElement: JsxClosingElement;
6264
6265            const lastChild: JsxChild | undefined = children[children.length - 1];
6266            if (lastChild?.kind === SyntaxKind.JsxElement
6267                && !tagNamesAreEquivalent(lastChild.openingElement.tagName, lastChild.closingElement.tagName)
6268                && tagNamesAreEquivalent(opening.tagName, lastChild.closingElement.tagName)) {
6269                // when an unclosed JsxOpeningElement incorrectly parses its parent's JsxClosingElement,
6270                // restructure (<div>(...<span>...</div>)) --> (<div>(...<span>...</>)</div>)
6271                // (no need to error; the parent will error)
6272                const end = lastChild.children.end;
6273                const newLast = finishNode(factory.createJsxElement(
6274                    lastChild.openingElement,
6275                    lastChild.children,
6276                    finishNode(factory.createJsxClosingElement(finishNode(factory.createIdentifier(""), end, end)), end, end)),
6277                lastChild.openingElement.pos,
6278                end);
6279
6280                children = createNodeArray([...children.slice(0, children.length - 1), newLast], children.pos, end);
6281                closingElement = lastChild.closingElement;
6282            }
6283            else {
6284                closingElement = parseJsxClosingElement(opening, inExpressionContext);
6285                if (!tagNamesAreEquivalent(opening.tagName, closingElement.tagName)) {
6286                    if (openingTag && isJsxOpeningElement(openingTag) && tagNamesAreEquivalent(closingElement.tagName, openingTag.tagName)) {
6287                        // opening incorrectly matched with its parent's closing -- put error on opening
6288                        parseErrorAtRange(opening.tagName, Diagnostics.JSX_element_0_has_no_corresponding_closing_tag, getTextOfNodeFromSourceText(sourceText, opening.tagName));
6289                    }
6290                    else {
6291                        // other opening/closing mismatches -- put error on closing
6292                        parseErrorAtRange(closingElement.tagName, Diagnostics.Expected_corresponding_JSX_closing_tag_for_0, getTextOfNodeFromSourceText(sourceText, opening.tagName));
6293                    }
6294                }
6295            }
6296            result = finishNode(factory.createJsxElement(opening, children, closingElement), pos);
6297        }
6298        else if (opening.kind === SyntaxKind.JsxOpeningFragment) {
6299            result = finishNode(factory.createJsxFragment(opening, parseJsxChildren(opening), parseJsxClosingFragment(inExpressionContext)), pos);
6300        }
6301        else {
6302            Debug.assert(opening.kind === SyntaxKind.JsxSelfClosingElement);
6303            // Nothing else to do for self-closing elements
6304            result = opening;
6305        }
6306
6307        // If the user writes the invalid code '<div></div><div></div>' in an expression context (i.e. not wrapped in
6308        // an enclosing tag), we'll naively try to parse   ^ this as a 'less than' operator and the remainder of the tag
6309        // as garbage, which will cause the formatter to badly mangle the JSX. Perform a speculative parse of a JSX
6310        // element if we see a < token so that we can wrap it in a synthetic binary expression so the formatter
6311        // does less damage and we can report a better error.
6312        // Since JSX elements are invalid < operands anyway, this lookahead parse will only occur in error scenarios
6313        // of one sort or another.
6314        if (inExpressionContext && token() === SyntaxKind.LessThanToken) {
6315            const topBadPos = typeof topInvalidNodePosition === "undefined" ? result.pos : topInvalidNodePosition;
6316            const invalidElement = tryParse(() => parseJsxElementOrSelfClosingElementOrFragment(/*inExpressionContext*/ true, topBadPos));
6317            if (invalidElement) {
6318                const operatorToken = createMissingNode(SyntaxKind.CommaToken, /*reportAtCurrentPosition*/ false);
6319                setTextRangePosWidth(operatorToken, invalidElement.pos, 0);
6320                parseErrorAt(skipTrivia(sourceText, topBadPos), invalidElement.end, Diagnostics.JSX_expressions_must_have_one_parent_element);
6321                return finishNode(factory.createBinaryExpression(result, operatorToken as Token<SyntaxKind.CommaToken>, invalidElement), pos) as Node as JsxElement;
6322            }
6323        }
6324
6325        return result;
6326    }
6327
6328    function parseJsxText(): JsxText {
6329        const pos = getNodePos();
6330        const node = factory.createJsxText(scanner.getTokenValue(), currentToken === SyntaxKind.JsxTextAllWhiteSpaces);
6331        currentToken = scanner.scanJsxToken();
6332        return finishNode(node, pos);
6333    }
6334
6335    function parseJsxChild(openingTag: JsxOpeningElement | JsxOpeningFragment, token: JsxTokenSyntaxKind): JsxChild | undefined {
6336        switch (token) {
6337            case SyntaxKind.EndOfFileToken:
6338                // If we hit EOF, issue the error at the tag that lacks the closing element
6339                // rather than at the end of the file (which is useless)
6340                if (isJsxOpeningFragment(openingTag)) {
6341                    parseErrorAtRange(openingTag, Diagnostics.JSX_fragment_has_no_corresponding_closing_tag);
6342                }
6343                else {
6344                    // We want the error span to cover only 'Foo.Bar' in < Foo.Bar >
6345                    // or to cover only 'Foo' in < Foo >
6346                    const tag = openingTag.tagName;
6347                    const start = skipTrivia(sourceText, tag.pos);
6348                    parseErrorAt(start, tag.end, Diagnostics.JSX_element_0_has_no_corresponding_closing_tag, getTextOfNodeFromSourceText(sourceText, openingTag.tagName));
6349                }
6350                return undefined;
6351            case SyntaxKind.LessThanSlashToken:
6352            case SyntaxKind.ConflictMarkerTrivia:
6353                return undefined;
6354            case SyntaxKind.JsxText:
6355            case SyntaxKind.JsxTextAllWhiteSpaces:
6356                return parseJsxText();
6357            case SyntaxKind.OpenBraceToken:
6358                return parseJsxExpression(/*inExpressionContext*/ false);
6359            case SyntaxKind.LessThanToken:
6360                return parseJsxElementOrSelfClosingElementOrFragment(/*inExpressionContext*/ false, /*topInvalidNodePosition*/ undefined, openingTag);
6361            default:
6362                return Debug.assertNever(token);
6363        }
6364    }
6365
6366    function parseJsxChildren(openingTag: JsxOpeningElement | JsxOpeningFragment): NodeArray<JsxChild> {
6367        const list = [];
6368        const listPos = getNodePos();
6369        const saveParsingContext = parsingContext;
6370        parsingContext |= 1 << ParsingContext.JsxChildren;
6371
6372        while (true) {
6373            const child = parseJsxChild(openingTag, currentToken = scanner.reScanJsxToken());
6374            if (!child) break;
6375            list.push(child);
6376            if (isJsxOpeningElement(openingTag)
6377                && child?.kind === SyntaxKind.JsxElement
6378                && !tagNamesAreEquivalent(child.openingElement.tagName, child.closingElement.tagName)
6379                && tagNamesAreEquivalent(openingTag.tagName, child.closingElement.tagName)) {
6380                // stop after parsing a mismatched child like <div>...(<span></div>) in order to reattach the </div> higher
6381                break;
6382            }
6383        }
6384
6385        parsingContext = saveParsingContext;
6386        return createNodeArray(list, listPos);
6387    }
6388
6389    function parseJsxAttributes(): JsxAttributes {
6390        const pos = getNodePos();
6391        return finishNode(factory.createJsxAttributes(parseList(ParsingContext.JsxAttributes, parseJsxAttribute)), pos);
6392    }
6393
6394    function parseJsxOpeningOrSelfClosingElementOrOpeningFragment(inExpressionContext: boolean): JsxOpeningElement | JsxSelfClosingElement | JsxOpeningFragment {
6395        const pos = getNodePos();
6396
6397        parseExpected(SyntaxKind.LessThanToken);
6398
6399        if (token() === SyntaxKind.GreaterThanToken) {
6400            // See below for explanation of scanJsxText
6401            scanJsxText();
6402            return finishNode(factory.createJsxOpeningFragment(), pos);
6403        }
6404        const tagName = parseJsxElementName();
6405        const typeArguments = (contextFlags & NodeFlags.JavaScriptFile) === 0 ? tryParseTypeArguments() : undefined;
6406        const attributes = parseJsxAttributes();
6407
6408        let node: JsxOpeningLikeElement;
6409
6410        if (token() === SyntaxKind.GreaterThanToken) {
6411            // Closing tag, so scan the immediately-following text with the JSX scanning instead
6412            // of regular scanning to avoid treating illegal characters (e.g. '#') as immediate
6413            // scanning errors
6414            scanJsxText();
6415            node = factory.createJsxOpeningElement(tagName, typeArguments, attributes);
6416        }
6417        else {
6418            parseExpected(SyntaxKind.SlashToken);
6419            if (parseExpected(SyntaxKind.GreaterThanToken, /*diagnostic*/ undefined, /*shouldAdvance*/ false)) {
6420                // manually advance the scanner in order to look for jsx text inside jsx
6421                if (inExpressionContext) {
6422                    nextToken();
6423                }
6424                else {
6425                    scanJsxText();
6426                }
6427            }
6428            node = factory.createJsxSelfClosingElement(tagName, typeArguments, attributes);
6429        }
6430
6431        return finishNode(node, pos);
6432    }
6433
6434    function parseJsxElementName(): JsxTagNameExpression {
6435        const pos = getNodePos();
6436        scanJsxIdentifier();
6437        // JsxElement can have name in the form of
6438        //      propertyAccessExpression
6439        //      primaryExpression in the form of an identifier and "this" keyword
6440        // We can't just simply use parseLeftHandSideExpressionOrHigher because then we will start consider class,function etc as a keyword
6441        // We only want to consider "this" as a primaryExpression
6442        let expression: JsxTagNameExpression = token() === SyntaxKind.ThisKeyword ?
6443            parseTokenNode<ThisExpression>() : parseIdentifierName();
6444        while (parseOptional(SyntaxKind.DotToken)) {
6445            expression = finishNode(factory.createPropertyAccessExpression(expression, parseRightSideOfDot(/*allowIdentifierNames*/ true, /*allowPrivateIdentifiers*/ false)), pos) as JsxTagNamePropertyAccess;
6446        }
6447        return expression;
6448    }
6449
6450    function parseJsxExpression(inExpressionContext: boolean): JsxExpression | undefined {
6451        const pos = getNodePos();
6452        if (!parseExpected(SyntaxKind.OpenBraceToken)) {
6453            return undefined;
6454        }
6455
6456        let dotDotDotToken: DotDotDotToken | undefined;
6457        let expression: Expression | undefined;
6458        if (token() !== SyntaxKind.CloseBraceToken) {
6459            dotDotDotToken = parseOptionalToken(SyntaxKind.DotDotDotToken);
6460            // Only an AssignmentExpression is valid here per the JSX spec,
6461            // but we can unambiguously parse a comma sequence and provide
6462            // a better error message in grammar checking.
6463            expression = parseExpression();
6464        }
6465        if (inExpressionContext) {
6466            parseExpected(SyntaxKind.CloseBraceToken);
6467        }
6468        else {
6469            if (parseExpected(SyntaxKind.CloseBraceToken, /*message*/ undefined, /*shouldAdvance*/ false)) {
6470                scanJsxText();
6471            }
6472        }
6473
6474        return finishNode(factory.createJsxExpression(dotDotDotToken, expression), pos);
6475    }
6476
6477    function parseJsxAttribute(): JsxAttribute | JsxSpreadAttribute {
6478        if (token() === SyntaxKind.OpenBraceToken) {
6479            return parseJsxSpreadAttribute();
6480        }
6481
6482        scanJsxIdentifier();
6483        const pos = getNodePos();
6484        return finishNode(factory.createJsxAttribute(parseIdentifierName(), parseJsxAttributeValue()), pos);
6485    }
6486
6487    function parseJsxAttributeValue(): JsxAttributeValue | undefined {
6488        if (token() === SyntaxKind.EqualsToken) {
6489            if (scanJsxAttributeValue() === SyntaxKind.StringLiteral) {
6490                return parseLiteralNode() as StringLiteral;
6491            }
6492            if (token() === SyntaxKind.OpenBraceToken) {
6493                return parseJsxExpression(/*inExpressionContext*/ true);
6494            }
6495            if (token() === SyntaxKind.LessThanToken) {
6496                return parseJsxElementOrSelfClosingElementOrFragment(/*inExpressionContext*/ true);
6497            }
6498            parseErrorAtCurrentToken(Diagnostics.or_JSX_element_expected);
6499        }
6500        return undefined;
6501    }
6502
6503    function parseJsxSpreadAttribute(): JsxSpreadAttribute {
6504        const pos = getNodePos();
6505        parseExpected(SyntaxKind.OpenBraceToken);
6506        parseExpected(SyntaxKind.DotDotDotToken);
6507        const expression = parseExpression();
6508        parseExpected(SyntaxKind.CloseBraceToken);
6509        return finishNode(factory.createJsxSpreadAttribute(expression), pos);
6510    }
6511
6512    function parseJsxClosingElement(open: JsxOpeningElement, inExpressionContext: boolean): JsxClosingElement {
6513        const pos = getNodePos();
6514        parseExpected(SyntaxKind.LessThanSlashToken);
6515        const tagName = parseJsxElementName();
6516        if (parseExpected(SyntaxKind.GreaterThanToken, /*diagnostic*/ undefined, /*shouldAdvance*/ false)) {
6517            // manually advance the scanner in order to look for jsx text inside jsx
6518            if (inExpressionContext || !tagNamesAreEquivalent(open.tagName, tagName)) {
6519                nextToken();
6520            }
6521            else {
6522                scanJsxText();
6523            }
6524        }
6525        return finishNode(factory.createJsxClosingElement(tagName), pos);
6526    }
6527
6528    function parseJsxClosingFragment(inExpressionContext: boolean): JsxClosingFragment {
6529        const pos = getNodePos();
6530        parseExpected(SyntaxKind.LessThanSlashToken);
6531        if (tokenIsIdentifierOrKeyword(token())) {
6532            parseErrorAtRange(parseJsxElementName(), Diagnostics.Expected_corresponding_closing_tag_for_JSX_fragment);
6533        }
6534        if (parseExpected(SyntaxKind.GreaterThanToken, /*diagnostic*/ undefined, /*shouldAdvance*/ false)) {
6535            // manually advance the scanner in order to look for jsx text inside jsx
6536            if (inExpressionContext) {
6537                nextToken();
6538            }
6539            else {
6540                scanJsxText();
6541            }
6542        }
6543        return finishNode(factory.createJsxJsxClosingFragment(), pos);
6544    }
6545
6546    function parseTypeAssertion(): TypeAssertion {
6547        const pos = getNodePos();
6548        parseExpected(SyntaxKind.LessThanToken);
6549        const type = parseType();
6550        parseExpected(SyntaxKind.GreaterThanToken);
6551        const expression = parseSimpleUnaryExpression();
6552        return finishNode(factory.createTypeAssertion(type, expression), pos);
6553    }
6554
6555    function nextTokenIsIdentifierOrKeywordOrOpenBracketOrTemplate() {
6556        nextToken();
6557        return tokenIsIdentifierOrKeyword(token())
6558            || token() === SyntaxKind.OpenBracketToken
6559            || isTemplateStartOfTaggedTemplate();
6560    }
6561
6562    function isStartOfOptionalPropertyOrElementAccessChain() {
6563        return token() === SyntaxKind.QuestionDotToken
6564            && lookAhead(nextTokenIsIdentifierOrKeywordOrOpenBracketOrTemplate);
6565    }
6566
6567    function tryReparseOptionalChain(node: Expression) {
6568        if (node.flags & NodeFlags.OptionalChain) {
6569            return true;
6570        }
6571        // check for an optional chain in a non-null expression
6572        if (isNonNullExpression(node)) {
6573            let expr = node.expression;
6574            while (isNonNullExpression(expr) && !(expr.flags & NodeFlags.OptionalChain)) {
6575                expr = expr.expression;
6576            }
6577            if (expr.flags & NodeFlags.OptionalChain) {
6578                // this is part of an optional chain. Walk down from `node` to `expression` and set the flag.
6579                while (isNonNullExpression(node)) {
6580                    (node as Mutable<NonNullExpression>).flags |= NodeFlags.OptionalChain;
6581                    node = node.expression;
6582                }
6583                return true;
6584            }
6585        }
6586        return false;
6587    }
6588
6589    function parsePropertyAccessExpressionRest(pos: number, expression: LeftHandSideExpression, questionDotToken: QuestionDotToken | undefined) {
6590        const name = parseRightSideOfDot(/*allowIdentifierNames*/ true, /*allowPrivateIdentifiers*/ true);
6591        const isOptionalChain = questionDotToken || tryReparseOptionalChain(expression);
6592        const propertyAccess = isOptionalChain ?
6593            factory.createPropertyAccessChain(expression, questionDotToken, name) :
6594            factory.createPropertyAccessExpression(expression, name);
6595        if (isOptionalChain && isPrivateIdentifier(propertyAccess.name)) {
6596            parseErrorAtRange(propertyAccess.name, Diagnostics.An_optional_chain_cannot_contain_private_identifiers);
6597        }
6598        if (isExpressionWithTypeArguments(expression) && expression.typeArguments) {
6599            const pos = expression.typeArguments.pos - 1;
6600            const end = skipTrivia(sourceText, expression.typeArguments.end) + 1;
6601            parseErrorAt(pos, end, Diagnostics.An_instantiation_expression_cannot_be_followed_by_a_property_access);
6602        }
6603        return finishNode(propertyAccess, pos);
6604    }
6605
6606    function parseElementAccessExpressionRest(pos: number, expression: LeftHandSideExpression, questionDotToken: QuestionDotToken | undefined) {
6607        let argumentExpression: Expression;
6608        if (token() === SyntaxKind.CloseBracketToken) {
6609            argumentExpression = createMissingNode(SyntaxKind.Identifier, /*reportAtCurrentPosition*/ true, Diagnostics.An_element_access_expression_should_take_an_argument);
6610        }
6611        else {
6612            const argument = allowInAnd(parseExpression);
6613            if (isStringOrNumericLiteralLike(argument)) {
6614                argument.text = internIdentifier(argument.text);
6615            }
6616            argumentExpression = argument;
6617        }
6618
6619        parseExpected(SyntaxKind.CloseBracketToken);
6620
6621        const indexedAccess = questionDotToken || tryReparseOptionalChain(expression) ?
6622            factory.createElementAccessChain(expression, questionDotToken, argumentExpression) :
6623            factory.createElementAccessExpression(expression, argumentExpression);
6624        return finishNode(indexedAccess, pos);
6625    }
6626
6627    function parseMemberExpressionRest(pos: number, expression: LeftHandSideExpression, allowOptionalChain: boolean): MemberExpression {
6628        while (true) {
6629            let questionDotToken: QuestionDotToken | undefined;
6630            let isPropertyAccess = false;
6631            if (allowOptionalChain && isStartOfOptionalPropertyOrElementAccessChain()) {
6632                questionDotToken = parseExpectedToken(SyntaxKind.QuestionDotToken);
6633                isPropertyAccess = tokenIsIdentifierOrKeyword(token());
6634            }
6635            else {
6636                isPropertyAccess = parseOptional(SyntaxKind.DotToken);
6637            }
6638
6639            if (isPropertyAccess) {
6640                expression = parsePropertyAccessExpressionRest(pos, expression, questionDotToken);
6641                continue;
6642            }
6643
6644            // when in the [Decorator] context, we do not parse ElementAccess as it could be part of a ComputedPropertyName
6645            if ((questionDotToken || !inDecoratorContext()) && parseOptional(SyntaxKind.OpenBracketToken)) {
6646                expression = parseElementAccessExpressionRest(pos, expression, questionDotToken);
6647                continue;
6648            }
6649
6650            if (isTemplateStartOfTaggedTemplate()) {
6651                // Absorb type arguments into TemplateExpression when preceding expression is ExpressionWithTypeArguments
6652                expression = !questionDotToken && expression.kind === SyntaxKind.ExpressionWithTypeArguments ?
6653                    parseTaggedTemplateRest(pos, (expression as ExpressionWithTypeArguments).expression, questionDotToken, (expression as ExpressionWithTypeArguments).typeArguments) :
6654                    parseTaggedTemplateRest(pos, expression, questionDotToken, /*typeArguments*/ undefined);
6655                continue;
6656            }
6657
6658            if (!questionDotToken) {
6659                if (token() === SyntaxKind.ExclamationToken && !scanner.hasPrecedingLineBreak()) {
6660                    nextToken();
6661                    expression = finishNode(factory.createNonNullExpression(expression), pos);
6662                    continue;
6663                }
6664                const typeArguments = tryParse(parseTypeArgumentsInExpression);
6665                if (typeArguments) {
6666                    expression = finishNode(factory.createExpressionWithTypeArguments(expression, typeArguments), pos);
6667                    continue;
6668                }
6669            }
6670
6671            return expression as MemberExpression;
6672        }
6673    }
6674
6675    function isTemplateStartOfTaggedTemplate() {
6676        return token() === SyntaxKind.NoSubstitutionTemplateLiteral || token() === SyntaxKind.TemplateHead;
6677    }
6678
6679    function parseTaggedTemplateRest(pos: number, tag: LeftHandSideExpression, questionDotToken: QuestionDotToken | undefined, typeArguments: NodeArray<TypeNode> | undefined) {
6680        const tagExpression = factory.createTaggedTemplateExpression(
6681            tag,
6682            typeArguments,
6683            token() === SyntaxKind.NoSubstitutionTemplateLiteral ?
6684                (reScanTemplateHeadOrNoSubstitutionTemplate(), parseLiteralNode() as NoSubstitutionTemplateLiteral) :
6685                parseTemplateExpression(/*isTaggedTemplate*/ true)
6686        );
6687        if (questionDotToken || tag.flags & NodeFlags.OptionalChain) {
6688            (tagExpression as Mutable<Node>).flags |= NodeFlags.OptionalChain;
6689        }
6690        tagExpression.questionDotToken = questionDotToken;
6691        return finishNode(tagExpression, pos);
6692    }
6693
6694    function parseCallExpressionRest(pos: number, expression: LeftHandSideExpression): LeftHandSideExpression {
6695        let currentNodeName: string | undefined;
6696        while (true) {
6697            expression = parseMemberExpressionRest(pos, expression, /*allowOptionalChain*/ true);
6698            let typeArguments: NodeArray<TypeNode> | undefined;
6699            const questionDotToken = parseOptionalToken(SyntaxKind.QuestionDotToken);
6700            if (questionDotToken) {
6701                typeArguments = tryParse(parseTypeArgumentsInExpression);
6702                if (isTemplateStartOfTaggedTemplate()) {
6703                    expression = parseTaggedTemplateRest(pos, expression, questionDotToken, typeArguments);
6704                    continue;
6705                }
6706            }
6707            if (typeArguments || token() === SyntaxKind.OpenParenToken) {
6708                // Absorb type arguments into CallExpression when preceding expression is ExpressionWithTypeArguments
6709                if (!questionDotToken && expression.kind === SyntaxKind.ExpressionWithTypeArguments) {
6710                    typeArguments = (expression as ExpressionWithTypeArguments).typeArguments;
6711                    expression = (expression as ExpressionWithTypeArguments).expression;
6712                }
6713
6714                if (isValidVirtualTypeArgumentsContext() && isPropertyAccessExpression(expression)) {
6715                    const [rootNode, type] = getRootComponent(expression, sourceFileCompilerOptions);
6716                    if (rootNode && type) {
6717                        let rootNodeName = '';
6718                        if (type === 'otherType') {
6719                            rootNodeName = 'Common';
6720                        } else {
6721                            rootNodeName = (<Identifier>(rootNode.expression)).escapedText.toString();
6722                        }
6723                        currentNodeName = getTextOfPropertyName(expression.name).toString();
6724                        if (currentNodeName === sourceFileCompilerOptions?.ets?.styles?.property) {
6725                            setEtsStateStylesContext(true);
6726                            stateStylesRootNode = rootNodeName;
6727                        }
6728                        else {
6729                            setEtsStateStylesContext(false);
6730                            stateStylesRootNode = undefined;
6731                        }
6732                        const syntaxComponents = sourceFileCompilerOptions?.ets?.syntaxComponents?.attrUICallback?.filter(
6733                            (item: any) => item.name === rootNodeName);
6734                        if (type === 'callExpressionComponentType' && syntaxComponents && syntaxComponents.length &&
6735                            syntaxComponents[0]?.attributes?.includes(currentNodeName)) {
6736                            setSyntaxComponentContext(true);
6737                            setFirstArgumentExpression(true);
6738                            if (currentNodeName === 'each') {
6739                                setRepeatEachRest(true);
6740                            }
6741                        } else if (type === 'etsComponentType') {
6742                            typeArguments = parseEtsTypeArguments(pos, `${rootNodeName}Attribute`);
6743                        }
6744                    }
6745                    else if (inEtsStateStylesContext() && stateStylesRootNode) {
6746                        typeArguments = parseEtsTypeArguments(pos, `${stateStylesRootNode}Attribute`);
6747                    } else if (inEtsStylesComponentsContext() || inEtsExtendComponentsContext()) {
6748                        const virtualNode = getVirtualEtsComponent(expression);
6749                        if (virtualNode) {
6750                            let rootNodeName = (<Identifier>(virtualNode.expression)).escapedText.toString();
6751                            currentNodeName = getTextOfPropertyName(expression.name).toString();
6752                            if (currentNodeName === sourceFileCompilerOptions?.ets?.styles?.property) {
6753                                setEtsStateStylesContext(true);
6754                                rootNodeName = rootNodeName.replace("Instance", "");
6755                                stateStylesRootNode = rootNodeName;
6756                                typeArguments = parseEtsTypeArguments(pos, `${rootNodeName}Attribute`);
6757                            }
6758                        }
6759                    }
6760                }
6761                if (isValidVirtualTypeArgumentsContext() && ts.isIdentifier(expression) &&
6762                    sourceFileCompilerOptions?.ets?.syntaxComponents?.paramsUICallback?.includes(expression.escapedText.toString())) {
6763                    setSyntaxComponentContext(true);
6764                    setFirstArgumentExpression(true);
6765                }
6766                const argumentList = parseArgumentList();
6767                const callExpr = questionDotToken || tryReparseOptionalChain(expression) ?
6768                    factory.createCallChain(expression, questionDotToken, typeArguments, argumentList) :
6769                    factory.createCallExpression(expression, typeArguments, argumentList);
6770                expression = finishNode(callExpr, pos);
6771                continue;
6772            }
6773            if (questionDotToken) {
6774                // We parsed `?.` but then failed to parse anything, so report a missing identifier here.
6775                const name = createMissingNode<Identifier>(SyntaxKind.Identifier, /*reportAtCurrentPosition*/ false, Diagnostics.Identifier_expected);
6776                expression = finishNode(factory.createPropertyAccessChain(expression, questionDotToken, name), pos);
6777            }
6778            break;
6779        }
6780        if (currentNodeName === sourceFileCompilerOptions?.ets?.styles?.property) {
6781            setEtsStateStylesContext(false);
6782            stateStylesRootNode = undefined;
6783        }
6784        return expression;
6785    }
6786
6787    function isValidVirtualTypeArgumentsContext(): boolean {
6788        return inBuildContext() || inBuilderContext() || inEtsStylesComponentsContext() || inEtsExtendComponentsContext();
6789    }
6790
6791    function parseArgumentList() {
6792        parseExpected(SyntaxKind.OpenParenToken);
6793        const result = parseDelimitedList(ParsingContext.ArgumentExpressions, parseArgumentExpression);
6794        parseExpected(SyntaxKind.CloseParenToken);
6795        return result;
6796    }
6797
6798    function parseTypeArgumentsInExpression() {
6799        if ((contextFlags & NodeFlags.JavaScriptFile) !== 0) {
6800            // TypeArguments must not be parsed in JavaScript files to avoid ambiguity with binary operators.
6801            return undefined;
6802        }
6803
6804        if (reScanLessThanToken() !== SyntaxKind.LessThanToken) {
6805            return undefined;
6806        }
6807        nextToken();
6808
6809        const typeArguments = parseDelimitedList(ParsingContext.TypeArguments, parseType);
6810        if (reScanGreaterToken() !== SyntaxKind.GreaterThanToken) {
6811            // If it doesn't have the closing `>` then it's definitely not an type argument list.
6812            return undefined;
6813        }
6814        nextToken();
6815
6816        // We successfully parsed a type argument list. The next token determines whether we want to
6817        // treat it as such. If the type argument list is followed by `(` or a template literal, as in
6818        // `f<number>(42)`, we favor the type argument interpretation even though JavaScript would view
6819        // it as a relational expression.
6820        return typeArguments && canFollowTypeArgumentsInExpression() ? typeArguments : undefined;
6821    }
6822
6823    function canFollowTypeArgumentsInExpression(): boolean {
6824        switch (token()) {
6825            // These tokens can follow a type argument list in a call expression.
6826            case SyntaxKind.OpenParenToken:                 // foo<x>(
6827            case SyntaxKind.NoSubstitutionTemplateLiteral:  // foo<T> `...`
6828            case SyntaxKind.TemplateHead:                   // foo<T> `...${100}...`
6829                return true;
6830            // A type argument list followed by `<` never makes sense, and a type argument list followed
6831            // by `>` is ambiguous with a (re-scanned) `>>` operator, so we disqualify both. Also, in
6832            // this context, `+` and `-` are unary operators, not binary operators.
6833            case SyntaxKind.LessThanToken:
6834            case SyntaxKind.GreaterThanToken:
6835            case SyntaxKind.PlusToken:
6836            case SyntaxKind.MinusToken:
6837                return false;
6838        }
6839        // We favor the type argument list interpretation when it is immediately followed by
6840        // a line break, a binary operator, or something that can't start an expression.
6841        return scanner.hasPrecedingLineBreak() || isBinaryOperator() || !isStartOfExpression();
6842    }
6843
6844    function isCurrentTokenAnEtsComponentExpression(): boolean {
6845        if (!inEtsComponentsContext() || inNoEtsComponentContext()) {
6846            return false;
6847        }
6848        const components = sourceFileCompilerOptions.ets?.components ?? [];
6849        return components.includes(scanner.getTokenText());
6850    }
6851
6852    function parseEtsComponentExpression(): EtsComponentExpression {
6853        const pos = getNodePos();
6854        const name = parseBindingIdentifier();
6855        const argumentList = parseArgumentList();
6856        const body = token() === SyntaxKind.OpenBraceToken ? parseFunctionBlock(SignatureFlags.None) : undefined;
6857        const node = factory.createEtsComponentExpression(name, argumentList, body);
6858        return finishNode(node, pos);
6859    }
6860
6861    function parsePrimaryExpression(): PrimaryExpression {
6862        switch (token()) {
6863            case SyntaxKind.NumericLiteral:
6864            case SyntaxKind.BigIntLiteral:
6865            case SyntaxKind.StringLiteral:
6866            case SyntaxKind.NoSubstitutionTemplateLiteral:
6867                return parseLiteralNode();
6868            case SyntaxKind.ThisKeyword:
6869            case SyntaxKind.SuperKeyword:
6870            case SyntaxKind.NullKeyword:
6871            case SyntaxKind.TrueKeyword:
6872            case SyntaxKind.FalseKeyword:
6873                return parseTokenNode<PrimaryExpression>();
6874            case SyntaxKind.OpenParenToken:
6875                return parseParenthesizedExpression();
6876            case SyntaxKind.OpenBracketToken:
6877                return parseArrayLiteralExpression();
6878            case SyntaxKind.OpenBraceToken:
6879                return parseObjectLiteralExpression();
6880            case SyntaxKind.AsyncKeyword:
6881                // Async arrow functions are parsed earlier in parseAssignmentExpressionOrHigher.
6882                // If we encounter `async [no LineTerminator here] function` then this is an async
6883                // function; otherwise, its an identifier.
6884                if (!lookAhead(nextTokenIsFunctionKeywordOnSameLine)) {
6885                    break;
6886                }
6887
6888                return parseFunctionExpression();
6889            case SyntaxKind.ClassKeyword:
6890                return parseClassExpression();
6891            case SyntaxKind.FunctionKeyword:
6892                return parseFunctionExpression();
6893            case SyntaxKind.NewKeyword:
6894                return parseNewExpressionOrNewDotTarget();
6895            case SyntaxKind.SlashToken:
6896            case SyntaxKind.SlashEqualsToken:
6897                if (reScanSlashToken() === SyntaxKind.RegularExpressionLiteral) {
6898                    return parseLiteralNode();
6899                }
6900                break;
6901            case SyntaxKind.TemplateHead:
6902                return parseTemplateExpression(/* isTaggedTemplate */ false);
6903            case SyntaxKind.PrivateIdentifier:
6904                return parsePrivateIdentifier();
6905        }
6906
6907        if(isCurrentTokenAnEtsComponentExpression() && !inEtsNewExpressionContext()) {
6908            return parseEtsComponentExpression();
6909        }
6910
6911        return parseIdentifier(Diagnostics.Expression_expected);
6912    }
6913
6914    function parseParenthesizedExpression(): ParenthesizedExpression {
6915        const pos = getNodePos();
6916        const hasJSDoc = hasPrecedingJSDocComment();
6917        parseExpected(SyntaxKind.OpenParenToken);
6918        const expression = allowInAnd(parseExpression);
6919        parseExpected(SyntaxKind.CloseParenToken);
6920        return withJSDoc(finishNode(factory.createParenthesizedExpression(expression), pos), hasJSDoc);
6921    }
6922
6923    function parseSpreadElement(): Expression {
6924        const pos = getNodePos();
6925        parseExpected(SyntaxKind.DotDotDotToken);
6926        const expression = parseAssignmentExpressionOrHigher(/*allowReturnTypeInArrowFunction*/ true);
6927        return finishNode(factory.createSpreadElement(expression), pos);
6928    }
6929
6930    function parseArgumentOrArrayLiteralElement(): Expression {
6931        return token() === SyntaxKind.DotDotDotToken ? parseSpreadElement() :
6932            token() === SyntaxKind.CommaToken ? finishNode(factory.createOmittedExpression(), getNodePos()) :
6933            parseAssignmentExpressionOrHigher(/*allowReturnTypeInArrowFunction*/ true);
6934    }
6935
6936    function parseArgumentExpression(): Expression {
6937        let resetSyntaxDataSourceContextFlag: boolean = false;
6938        let resetRepeatEachContextFlag: boolean = false;
6939        if (inSyntaxComponentContext() && !inSyntaxDataSourceContext() && getFirstArgumentExpression()) {
6940            setFirstArgumentExpression(false);
6941            if (!getRepeatEachRest()) {
6942                setSyntaxDataSourceContext(true);
6943                resetSyntaxDataSourceContextFlag = true;
6944            } else {
6945                resetRepeatEachContextFlag = true;
6946            }
6947        }
6948        const argumentExpressionResult = doOutsideOfContext(disallowInAndDecoratorContext, parseArgumentOrArrayLiteralElement);
6949
6950        if (resetSyntaxDataSourceContextFlag) {
6951            setSyntaxDataSourceContext(false);
6952        }
6953
6954        if (resetRepeatEachContextFlag) {
6955            setRepeatEachRest(false);
6956        }
6957
6958        return argumentExpressionResult;
6959    }
6960
6961    function parseArrayLiteralExpression(): ArrayLiteralExpression {
6962        const pos = getNodePos();
6963        const openBracketPosition = scanner.getTokenPos();
6964        const openBracketParsed = parseExpected(SyntaxKind.OpenBracketToken);
6965        const multiLine = scanner.hasPrecedingLineBreak();
6966        const elements = parseDelimitedList(ParsingContext.ArrayLiteralMembers, parseArgumentOrArrayLiteralElement);
6967        parseExpectedMatchingBrackets(SyntaxKind.OpenBracketToken, SyntaxKind.CloseBracketToken, openBracketParsed, openBracketPosition);
6968        return finishNode(factory.createArrayLiteralExpression(elements, multiLine), pos);
6969    }
6970
6971    function parseObjectLiteralElement(): ObjectLiteralElementLike {
6972        const pos = getNodePos();
6973        const hasJSDoc = hasPrecedingJSDocComment();
6974
6975        if (parseOptionalToken(SyntaxKind.DotDotDotToken)) {
6976            const expression = parseAssignmentExpressionOrHigher(/*allowReturnTypeInArrowFunction*/ true);
6977            return withJSDoc(finishNode(factory.createSpreadAssignment(expression), pos), hasJSDoc);
6978        }
6979
6980        const decorators = parseDecorators();
6981        const modifiers = parseModifiers();
6982
6983        if (parseContextualModifier(SyntaxKind.GetKeyword)) {
6984            return parseAccessorDeclaration(pos, hasJSDoc, decorators, modifiers, SyntaxKind.GetAccessor, SignatureFlags.None);
6985        }
6986        if (parseContextualModifier(SyntaxKind.SetKeyword)) {
6987            return parseAccessorDeclaration(pos, hasJSDoc, decorators, modifiers, SyntaxKind.SetAccessor, SignatureFlags.None);
6988        }
6989
6990        const asteriskToken = parseOptionalToken(SyntaxKind.AsteriskToken);
6991        const tokenIsIdentifier = isIdentifier();
6992        const name = parsePropertyName();
6993
6994        // Disallowing of optional property assignments and definite assignment assertion happens in the grammar checker.
6995        const questionToken = parseOptionalToken(SyntaxKind.QuestionToken);
6996        const exclamationToken = parseOptionalToken(SyntaxKind.ExclamationToken);
6997
6998        if (asteriskToken || token() === SyntaxKind.OpenParenToken || token() === SyntaxKind.LessThanToken) {
6999            return parseMethodDeclaration(pos, hasJSDoc, decorators, modifiers, asteriskToken, name, questionToken, exclamationToken);
7000        }
7001
7002        // check if it is short-hand property assignment or normal property assignment
7003        // NOTE: if token is EqualsToken it is interpreted as CoverInitializedName production
7004        // CoverInitializedName[Yield] :
7005        //     IdentifierReference[?Yield] Initializer[In, ?Yield]
7006        // this is necessary because ObjectLiteral productions are also used to cover grammar for ObjectAssignmentPattern
7007        let node: Mutable<ShorthandPropertyAssignment | PropertyAssignment>;
7008        const isShorthandPropertyAssignment = tokenIsIdentifier && (token() !== SyntaxKind.ColonToken);
7009        if (isShorthandPropertyAssignment) {
7010            const equalsToken = parseOptionalToken(SyntaxKind.EqualsToken);
7011            const objectAssignmentInitializer = equalsToken ? allowInAnd(() => parseAssignmentExpressionOrHigher(/*allowReturnTypeInArrowFunction*/ true)) : undefined;
7012            node = factory.createShorthandPropertyAssignment(name as Identifier, objectAssignmentInitializer);
7013            // Save equals token for error reporting.
7014            // TODO(rbuckton): Consider manufacturing this when we need to report an error as it is otherwise not useful.
7015            node.equalsToken = equalsToken;
7016        }
7017        else {
7018            parseExpected(SyntaxKind.ColonToken);
7019            const initializer = allowInAnd(() => parseAssignmentExpressionOrHigher(/*allowReturnTypeInArrowFunction*/ true));
7020            node = factory.createPropertyAssignment(name, initializer);
7021        }
7022        // Decorators, Modifiers, questionToken, and exclamationToken are not supported by property assignments and are reported in the grammar checker
7023        node.illegalDecorators = decorators;
7024        node.modifiers = modifiers;
7025        node.questionToken = questionToken;
7026        node.exclamationToken = exclamationToken;
7027        return withJSDoc(finishNode(node, pos), hasJSDoc);
7028    }
7029
7030    function parseObjectLiteralExpression(): ObjectLiteralExpression {
7031        const pos = getNodePos();
7032        const openBracePosition = scanner.getTokenPos();
7033        const openBraceParsed = parseExpected(SyntaxKind.OpenBraceToken);
7034        const multiLine = scanner.hasPrecedingLineBreak();
7035        const properties = parseDelimitedList(ParsingContext.ObjectLiteralMembers, parseObjectLiteralElement, /*considerSemicolonAsDelimiter*/ true);
7036        parseExpectedMatchingBrackets(SyntaxKind.OpenBraceToken, SyntaxKind.CloseBraceToken, openBraceParsed, openBracePosition);
7037        return finishNode(factory.createObjectLiteralExpression(properties, multiLine), pos);
7038    }
7039
7040    function parseFunctionExpression(): FunctionExpression {
7041        // GeneratorExpression:
7042        //      function* BindingIdentifier [Yield][opt](FormalParameters[Yield]) { GeneratorBody }
7043        //
7044        // FunctionExpression:
7045        //      function BindingIdentifier[opt](FormalParameters) { FunctionBody }
7046        const savedDecoratorContext = inDecoratorContext();
7047        setDecoratorContext(/*val*/ false);
7048
7049        const pos = getNodePos();
7050        const hasJSDoc = hasPrecedingJSDocComment();
7051        const modifiers = parseModifiers();
7052        parseExpected(SyntaxKind.FunctionKeyword);
7053        const asteriskToken = parseOptionalToken(SyntaxKind.AsteriskToken);
7054        const isGenerator = asteriskToken ? SignatureFlags.Yield : SignatureFlags.None;
7055        const isAsync = some(modifiers, isAsyncModifier) ? SignatureFlags.Await : SignatureFlags.None;
7056        const name = isGenerator && isAsync ? doInYieldAndAwaitContext(parseOptionalBindingIdentifier) :
7057            isGenerator ? doInYieldContext(parseOptionalBindingIdentifier) :
7058            isAsync ? doInAwaitContext(parseOptionalBindingIdentifier) :
7059            parseOptionalBindingIdentifier();
7060
7061        const typeParameters = parseTypeParameters();
7062        const parameters = parseParameters(isGenerator | isAsync);
7063        const type = parseReturnType(SyntaxKind.ColonToken, /*isType*/ false);
7064        const body = parseFunctionBlock(isGenerator | isAsync);
7065
7066        setDecoratorContext(savedDecoratorContext);
7067
7068        const node = factory.createFunctionExpression(modifiers, asteriskToken, name, typeParameters, parameters, type, body);
7069        return withJSDoc(finishNode(node, pos), hasJSDoc);
7070    }
7071
7072    function parseOptionalBindingIdentifier(): Identifier | undefined {
7073        return isBindingIdentifier() ? parseBindingIdentifier() : undefined;
7074    }
7075
7076    function parseNewExpressionOrNewDotTarget(): NewExpression | MetaProperty {
7077        setEtsNewExpressionContext(inEtsComponentsContext());
7078        const pos = getNodePos();
7079        parseExpected(SyntaxKind.NewKeyword);
7080        if (parseOptional(SyntaxKind.DotToken)) {
7081            const name = parseIdentifierName();
7082            return finishNode(factory.createMetaProperty(SyntaxKind.NewKeyword, name), pos);
7083        }
7084        const expressionPos = getNodePos();
7085        let expression: LeftHandSideExpression = parseMemberExpressionRest(expressionPos, parsePrimaryExpression(), /*allowOptionalChain*/ false);
7086        let typeArguments: NodeArray<TypeNode> | undefined;
7087        // Absorb type arguments into NewExpression when preceding expression is ExpressionWithTypeArguments
7088        if (expression.kind === SyntaxKind.ExpressionWithTypeArguments) {
7089            typeArguments = (expression as ExpressionWithTypeArguments).typeArguments;
7090            expression = (expression as ExpressionWithTypeArguments).expression;
7091        }
7092        if (token() === SyntaxKind.QuestionDotToken) {
7093            parseErrorAtCurrentToken(Diagnostics.Invalid_optional_chain_from_new_expression_Did_you_mean_to_call_0, getTextOfNodeFromSourceText(sourceText, expression));
7094        }
7095        const argumentList = token() === SyntaxKind.OpenParenToken ? parseArgumentList() : undefined;
7096        setEtsNewExpressionContext(false);
7097        return finishNode(factory.createNewExpression(expression, typeArguments, argumentList), pos);
7098    }
7099
7100    // STATEMENTS
7101    function parseBlock(ignoreMissingOpenBrace: boolean, diagnosticMessage?: DiagnosticMessage): Block {
7102        const pos = getNodePos();
7103        const hasJSDoc = hasPrecedingJSDocComment();
7104        const openBracePosition = scanner.getTokenPos();
7105        const openBraceParsed = parseExpected(SyntaxKind.OpenBraceToken, diagnosticMessage);
7106        if (openBraceParsed || ignoreMissingOpenBrace) {
7107            const multiLine = scanner.hasPrecedingLineBreak();
7108            const statements = parseList(ParsingContext.BlockStatements, parseStatement);
7109            parseExpectedMatchingBrackets(SyntaxKind.OpenBraceToken, SyntaxKind.CloseBraceToken, openBraceParsed, openBracePosition);
7110            const result = withJSDoc(finishNode(factory.createBlock(statements, multiLine), pos), hasJSDoc);
7111            if (token() === SyntaxKind.EqualsToken) {
7112                parseErrorAtCurrentToken(Diagnostics.Declaration_or_statement_expected_This_follows_a_block_of_statements_so_if_you_intended_to_write_a_destructuring_assignment_you_might_need_to_wrap_the_the_whole_assignment_in_parentheses);
7113                nextToken();
7114            }
7115
7116            return result;
7117        }
7118        else {
7119            const statements = createMissingList<Statement>();
7120            return withJSDoc(finishNode(factory.createBlock(statements, /*multiLine*/ undefined), pos), hasJSDoc);
7121        }
7122    }
7123
7124    function parseFunctionBlock(flags: SignatureFlags, diagnosticMessage?: DiagnosticMessage): Block {
7125        const savedYieldContext = inYieldContext();
7126        setYieldContext(!!(flags & SignatureFlags.Yield));
7127
7128        const savedAwaitContext = inAwaitContext();
7129        setAwaitContext(!!(flags & SignatureFlags.Await));
7130
7131        const savedTopLevel = topLevel;
7132        topLevel = false;
7133
7134        // We may be in a [Decorator] context when parsing a function expression or
7135        // arrow function. The body of the function is not in [Decorator] context.
7136        const saveDecoratorContext = inDecoratorContext();
7137        if (saveDecoratorContext) {
7138            setDecoratorContext(/*val*/ false);
7139        }
7140
7141        const block = parseBlock(!!(flags & SignatureFlags.IgnoreMissingOpenBrace), diagnosticMessage);
7142
7143        if (saveDecoratorContext) {
7144            setDecoratorContext(/*val*/ true);
7145        }
7146
7147        topLevel = savedTopLevel;
7148        setYieldContext(savedYieldContext);
7149        setAwaitContext(savedAwaitContext);
7150
7151        return block;
7152    }
7153
7154    function parseEmptyStatement(): Statement {
7155        const pos = getNodePos();
7156        const hasJSDoc = hasPrecedingJSDocComment();
7157        parseExpected(SyntaxKind.SemicolonToken);
7158        return withJSDoc(finishNode(factory.createEmptyStatement(), pos), hasJSDoc);
7159    }
7160
7161    function parseIfStatement(): IfStatement {
7162        const pos = getNodePos();
7163        const hasJSDoc = hasPrecedingJSDocComment();
7164        parseExpected(SyntaxKind.IfKeyword);
7165        const openParenPosition = scanner.getTokenPos();
7166        const openParenParsed = parseExpected(SyntaxKind.OpenParenToken);
7167        const expression = allowInAnd(parseExpression);
7168        parseExpectedMatchingBrackets(SyntaxKind.OpenParenToken, SyntaxKind.CloseParenToken, openParenParsed, openParenPosition);
7169        const thenStatement = parseStatement();
7170        const elseStatement = parseOptional(SyntaxKind.ElseKeyword) ? parseStatement() : undefined;
7171        return withJSDoc(finishNode(factory.createIfStatement(expression, thenStatement, elseStatement), pos), hasJSDoc);
7172    }
7173
7174    function parseDoStatement(): DoStatement {
7175        const pos = getNodePos();
7176        const hasJSDoc = hasPrecedingJSDocComment();
7177        parseExpected(SyntaxKind.DoKeyword);
7178        const statement = parseStatement();
7179        parseExpected(SyntaxKind.WhileKeyword);
7180        const openParenPosition = scanner.getTokenPos();
7181        const openParenParsed = parseExpected(SyntaxKind.OpenParenToken);
7182        const expression = allowInAnd(parseExpression);
7183        parseExpectedMatchingBrackets(SyntaxKind.OpenParenToken, SyntaxKind.CloseParenToken, openParenParsed, openParenPosition);
7184
7185        // From: https://mail.mozilla.org/pipermail/es-discuss/2011-August/016188.html
7186        // 157 min --- All allen at wirfs-brock.com CONF --- "do{;}while(false)false" prohibited in
7187        // spec but allowed in consensus reality. Approved -- this is the de-facto standard whereby
7188        //  do;while(0)x will have a semicolon inserted before x.
7189        parseOptional(SyntaxKind.SemicolonToken);
7190        return withJSDoc(finishNode(factory.createDoStatement(statement, expression), pos), hasJSDoc);
7191    }
7192
7193    function parseWhileStatement(): WhileStatement {
7194        const pos = getNodePos();
7195        const hasJSDoc = hasPrecedingJSDocComment();
7196        parseExpected(SyntaxKind.WhileKeyword);
7197        const openParenPosition = scanner.getTokenPos();
7198        const openParenParsed = parseExpected(SyntaxKind.OpenParenToken);
7199        const expression = allowInAnd(parseExpression);
7200        parseExpectedMatchingBrackets(SyntaxKind.OpenParenToken, SyntaxKind.CloseParenToken, openParenParsed, openParenPosition);
7201        const statement = parseStatement();
7202        return withJSDoc(finishNode(factory.createWhileStatement(expression, statement), pos), hasJSDoc);
7203    }
7204
7205    function parseForOrForInOrForOfStatement(): Statement {
7206        const pos = getNodePos();
7207        const hasJSDoc = hasPrecedingJSDocComment();
7208        parseExpected(SyntaxKind.ForKeyword);
7209        const awaitToken = parseOptionalToken(SyntaxKind.AwaitKeyword);
7210        parseExpected(SyntaxKind.OpenParenToken);
7211
7212        let initializer!: VariableDeclarationList | Expression;
7213        if (token() !== SyntaxKind.SemicolonToken) {
7214            if (token() === SyntaxKind.VarKeyword || token() === SyntaxKind.LetKeyword || token() === SyntaxKind.ConstKeyword) {
7215                initializer = parseVariableDeclarationList(/*inForStatementInitializer*/ true);
7216            }
7217            else {
7218                initializer = disallowInAnd(parseExpression);
7219            }
7220        }
7221
7222        let node: IterationStatement;
7223        if (awaitToken ? parseExpected(SyntaxKind.OfKeyword) : parseOptional(SyntaxKind.OfKeyword)) {
7224            const expression = allowInAnd(() => parseAssignmentExpressionOrHigher(/*allowReturnTypeInArrowFunction*/ true));
7225            parseExpected(SyntaxKind.CloseParenToken);
7226            node = factory.createForOfStatement(awaitToken, initializer, expression, parseStatement());
7227        }
7228        else if (parseOptional(SyntaxKind.InKeyword)) {
7229            const expression = allowInAnd(parseExpression);
7230            parseExpected(SyntaxKind.CloseParenToken);
7231            node = factory.createForInStatement(initializer, expression, parseStatement());
7232        }
7233        else {
7234            parseExpected(SyntaxKind.SemicolonToken);
7235            const condition = token() !== SyntaxKind.SemicolonToken && token() !== SyntaxKind.CloseParenToken
7236                ? allowInAnd(parseExpression)
7237                : undefined;
7238            parseExpected(SyntaxKind.SemicolonToken);
7239            const incrementor = token() !== SyntaxKind.CloseParenToken
7240                ? allowInAnd(parseExpression)
7241                : undefined;
7242            parseExpected(SyntaxKind.CloseParenToken);
7243            node = factory.createForStatement(initializer, condition, incrementor, parseStatement());
7244        }
7245
7246        return withJSDoc(finishNode(node, pos) as ForStatement | ForInOrOfStatement, hasJSDoc);
7247    }
7248
7249    function parseBreakOrContinueStatement(kind: SyntaxKind): BreakOrContinueStatement {
7250        const pos = getNodePos();
7251        const hasJSDoc = hasPrecedingJSDocComment();
7252
7253        parseExpected(kind === SyntaxKind.BreakStatement ? SyntaxKind.BreakKeyword : SyntaxKind.ContinueKeyword);
7254        const label = canParseSemicolon() ? undefined : parseIdentifier();
7255
7256        parseSemicolon();
7257        const node = kind === SyntaxKind.BreakStatement
7258            ? factory.createBreakStatement(label)
7259            : factory.createContinueStatement(label);
7260        return withJSDoc(finishNode(node, pos), hasJSDoc);
7261    }
7262
7263    function parseReturnStatement(): ReturnStatement {
7264        const pos = getNodePos();
7265        const hasJSDoc = hasPrecedingJSDocComment();
7266        parseExpected(SyntaxKind.ReturnKeyword);
7267        const expression = canParseSemicolon() ? undefined : allowInAnd(parseExpression);
7268        parseSemicolon();
7269        return withJSDoc(finishNode(factory.createReturnStatement(expression), pos), hasJSDoc);
7270    }
7271
7272    function parseWithStatement(): WithStatement {
7273        const pos = getNodePos();
7274        const hasJSDoc = hasPrecedingJSDocComment();
7275        parseExpected(SyntaxKind.WithKeyword);
7276        const openParenPosition = scanner.getTokenPos();
7277        const openParenParsed = parseExpected(SyntaxKind.OpenParenToken);
7278        const expression = allowInAnd(parseExpression);
7279        parseExpectedMatchingBrackets(SyntaxKind.OpenParenToken, SyntaxKind.CloseParenToken, openParenParsed, openParenPosition);
7280        const statement = doInsideOfContext(NodeFlags.InWithStatement, parseStatement);
7281        return withJSDoc(finishNode(factory.createWithStatement(expression, statement), pos), hasJSDoc);
7282    }
7283
7284    function parseCaseClause(): CaseClause {
7285        const pos = getNodePos();
7286        const hasJSDoc = hasPrecedingJSDocComment();
7287        parseExpected(SyntaxKind.CaseKeyword);
7288        const expression = allowInAnd(parseExpression);
7289        parseExpected(SyntaxKind.ColonToken);
7290        const statements = parseList(ParsingContext.SwitchClauseStatements, parseStatement);
7291        return withJSDoc(finishNode(factory.createCaseClause(expression, statements), pos), hasJSDoc);
7292    }
7293
7294    function parseDefaultClause(): DefaultClause {
7295        const pos = getNodePos();
7296        parseExpected(SyntaxKind.DefaultKeyword);
7297        parseExpected(SyntaxKind.ColonToken);
7298        const statements = parseList(ParsingContext.SwitchClauseStatements, parseStatement);
7299        return finishNode(factory.createDefaultClause(statements), pos);
7300    }
7301
7302    function parseCaseOrDefaultClause(): CaseOrDefaultClause {
7303        return token() === SyntaxKind.CaseKeyword ? parseCaseClause() : parseDefaultClause();
7304    }
7305
7306    function parseCaseBlock(): CaseBlock {
7307        const pos = getNodePos();
7308        parseExpected(SyntaxKind.OpenBraceToken);
7309        const clauses = parseList(ParsingContext.SwitchClauses, parseCaseOrDefaultClause);
7310        parseExpected(SyntaxKind.CloseBraceToken);
7311        return finishNode(factory.createCaseBlock(clauses), pos);
7312    }
7313
7314    function parseSwitchStatement(): SwitchStatement {
7315        const pos = getNodePos();
7316        const hasJSDoc = hasPrecedingJSDocComment();
7317        parseExpected(SyntaxKind.SwitchKeyword);
7318        parseExpected(SyntaxKind.OpenParenToken);
7319        const expression = allowInAnd(parseExpression);
7320        parseExpected(SyntaxKind.CloseParenToken);
7321        const caseBlock = parseCaseBlock();
7322        return withJSDoc(finishNode(factory.createSwitchStatement(expression, caseBlock), pos), hasJSDoc);
7323    }
7324
7325    function parseThrowStatement(): ThrowStatement {
7326        // ThrowStatement[Yield] :
7327        //      throw [no LineTerminator here]Expression[In, ?Yield];
7328
7329        const pos = getNodePos();
7330        const hasJSDoc = hasPrecedingJSDocComment();
7331        parseExpected(SyntaxKind.ThrowKeyword);
7332
7333        // Because of automatic semicolon insertion, we need to report error if this
7334        // throw could be terminated with a semicolon.  Note: we can't call 'parseExpression'
7335        // directly as that might consume an expression on the following line.
7336        // Instead, we create a "missing" identifier, but don't report an error. The actual error
7337        // will be reported in the grammar walker.
7338        let expression = scanner.hasPrecedingLineBreak() ? undefined : allowInAnd(parseExpression);
7339        if (expression === undefined) {
7340            identifierCount++;
7341            expression = finishNode(factory.createIdentifier(""), getNodePos());
7342        }
7343        if (!tryParseSemicolon()) {
7344            parseErrorForMissingSemicolonAfter(expression);
7345        }
7346        return withJSDoc(finishNode(factory.createThrowStatement(expression), pos), hasJSDoc);
7347    }
7348
7349    // TODO: Review for error recovery
7350    function parseTryStatement(): TryStatement {
7351        const pos = getNodePos();
7352        const hasJSDoc = hasPrecedingJSDocComment();
7353
7354        parseExpected(SyntaxKind.TryKeyword);
7355        const tryBlock = parseBlock(/*ignoreMissingOpenBrace*/ false);
7356        const catchClause = token() === SyntaxKind.CatchKeyword ? parseCatchClause() : undefined;
7357
7358        // If we don't have a catch clause, then we must have a finally clause.  Try to parse
7359        // one out no matter what.
7360        let finallyBlock: Block | undefined;
7361        if (!catchClause || token() === SyntaxKind.FinallyKeyword) {
7362            parseExpected(SyntaxKind.FinallyKeyword, Diagnostics.catch_or_finally_expected);
7363            finallyBlock = parseBlock(/*ignoreMissingOpenBrace*/ false);
7364        }
7365
7366        return withJSDoc(finishNode(factory.createTryStatement(tryBlock, catchClause, finallyBlock), pos), hasJSDoc);
7367    }
7368
7369    function parseCatchClause(): CatchClause {
7370        const pos = getNodePos();
7371        parseExpected(SyntaxKind.CatchKeyword);
7372
7373        let variableDeclaration;
7374        if (parseOptional(SyntaxKind.OpenParenToken)) {
7375            variableDeclaration = parseVariableDeclaration();
7376            parseExpected(SyntaxKind.CloseParenToken);
7377        }
7378        else {
7379            // Keep shape of node to avoid degrading performance.
7380            variableDeclaration = undefined;
7381        }
7382
7383        const block = parseBlock(/*ignoreMissingOpenBrace*/ false);
7384        return finishNode(factory.createCatchClause(variableDeclaration, block), pos);
7385    }
7386
7387    function parseDebuggerStatement(): Statement {
7388        const pos = getNodePos();
7389        const hasJSDoc = hasPrecedingJSDocComment();
7390        parseExpected(SyntaxKind.DebuggerKeyword);
7391        parseSemicolon();
7392        return withJSDoc(finishNode(factory.createDebuggerStatement(), pos), hasJSDoc);
7393    }
7394
7395    function parseExpressionOrLabeledStatement(): ExpressionStatement | LabeledStatement {
7396        // Avoiding having to do the lookahead for a labeled statement by just trying to parse
7397        // out an expression, seeing if it is identifier and then seeing if it is followed by
7398        // a colon.
7399        const pos = getNodePos();
7400        let hasJSDoc = hasPrecedingJSDocComment();
7401        let node: ExpressionStatement | LabeledStatement;
7402        const hasParen = token() === SyntaxKind.OpenParenToken;
7403        const expression = allowInAnd(parseExpression);
7404        if (ts.isIdentifier(expression) && parseOptional(SyntaxKind.ColonToken)) {
7405            node = factory.createLabeledStatement(expression, parseStatement());
7406        }
7407        else {
7408            if (!tryParseSemicolon()) {
7409                parseErrorForMissingSemicolonAfter(expression);
7410            }
7411            node = factory.createExpressionStatement(expression);
7412            if (hasParen) {
7413                // do not parse the same jsdoc twice
7414                hasJSDoc = false;
7415            }
7416        }
7417        return withJSDoc(finishNode(node, pos), hasJSDoc);
7418    }
7419
7420    function nextTokenIsIdentifierOrKeywordOnSameLine() {
7421        nextToken();
7422        return tokenIsIdentifierOrKeyword(token()) && !scanner.hasPrecedingLineBreak();
7423    }
7424
7425    function nextTokenIsClassKeywordOnSameLine() {
7426        nextToken();
7427        return token() === SyntaxKind.ClassKeyword && !scanner.hasPrecedingLineBreak();
7428    }
7429
7430    function nextTokenIsFunctionKeywordOnSameLine() {
7431        nextToken();
7432        return token() === SyntaxKind.FunctionKeyword && !scanner.hasPrecedingLineBreak();
7433    }
7434
7435    function nextTokenIsIdentifierOrKeywordOrLiteralOnSameLine() {
7436        nextToken();
7437        return (tokenIsIdentifierOrKeyword(token()) || token() === SyntaxKind.NumericLiteral || token() === SyntaxKind.BigIntLiteral || token() === SyntaxKind.StringLiteral) && !scanner.hasPrecedingLineBreak();
7438    }
7439
7440    function isDeclaration(): boolean {
7441        while (true) {
7442            switch (token()) {
7443                case SyntaxKind.VarKeyword:
7444                case SyntaxKind.LetKeyword:
7445                case SyntaxKind.ConstKeyword:
7446                case SyntaxKind.FunctionKeyword:
7447                case SyntaxKind.ClassKeyword:
7448                case SyntaxKind.EnumKeyword:
7449                    return true;
7450                case SyntaxKind.StructKeyword:
7451                    return inEtsContext();
7452                case SyntaxKind.AtToken:
7453                    return inAllowAnnotationContext() && nextToken() === SyntaxKind.InterfaceKeyword;
7454                // 'declare', 'module', 'namespace', 'interface'* and 'type' are all legal JavaScript identifiers;
7455                // however, an identifier cannot be followed by another identifier on the same line. This is what we
7456                // count on to parse out the respective declarations. For instance, we exploit this to say that
7457                //
7458                //    namespace n
7459                //
7460                // can be none other than the beginning of a namespace declaration, but need to respect that JavaScript sees
7461                //
7462                //    namespace
7463                //    n
7464                //
7465                // as the identifier 'namespace' on one line followed by the identifier 'n' on another.
7466                // We need to look one token ahead to see if it permissible to try parsing a declaration.
7467                //
7468                // *Note*: 'interface' is actually a strict mode reserved word. So while
7469                //
7470                //   "use strict"
7471                //   interface
7472                //   I {}
7473                //
7474                // could be legal, it would add complexity for very little gain.
7475                case SyntaxKind.InterfaceKeyword:
7476                case SyntaxKind.TypeKeyword:
7477                    return nextTokenIsIdentifierOnSameLine();
7478                case SyntaxKind.ModuleKeyword:
7479                case SyntaxKind.NamespaceKeyword:
7480                    return nextTokenIsIdentifierOrStringLiteralOnSameLine();
7481                case SyntaxKind.AbstractKeyword:
7482                case SyntaxKind.AccessorKeyword:
7483                case SyntaxKind.AsyncKeyword:
7484                case SyntaxKind.DeclareKeyword:
7485                case SyntaxKind.PrivateKeyword:
7486                case SyntaxKind.ProtectedKeyword:
7487                case SyntaxKind.PublicKeyword:
7488                case SyntaxKind.ReadonlyKeyword:
7489                    nextToken();
7490                    // ASI takes effect for this modifier.
7491                    if (scanner.hasPrecedingLineBreak()) {
7492                        return false;
7493                    }
7494                    continue;
7495
7496                case SyntaxKind.GlobalKeyword:
7497                    nextToken();
7498                    return token() === SyntaxKind.OpenBraceToken || token() === SyntaxKind.Identifier || token() === SyntaxKind.ExportKeyword;
7499
7500                case SyntaxKind.ImportKeyword:
7501                    nextToken();
7502                    return token() === SyntaxKind.StringLiteral || token() === SyntaxKind.AsteriskToken ||
7503                        token() === SyntaxKind.OpenBraceToken || tokenIsIdentifierOrKeyword(token());
7504                case SyntaxKind.ExportKeyword:
7505                    let currentToken = nextToken();
7506                    if (currentToken === SyntaxKind.TypeKeyword) {
7507                        currentToken = lookAhead(nextToken);
7508                    }
7509                    if (currentToken === SyntaxKind.EqualsToken || currentToken === SyntaxKind.AsteriskToken ||
7510                        currentToken === SyntaxKind.OpenBraceToken || currentToken === SyntaxKind.DefaultKeyword ||
7511                        currentToken === SyntaxKind.AsKeyword) {
7512                        return true;
7513                    }
7514                    continue;
7515
7516                case SyntaxKind.StaticKeyword:
7517                    nextToken();
7518                    continue;
7519                default:
7520                    return false;
7521            }
7522        }
7523    }
7524
7525    function isStartOfDeclaration(): boolean {
7526        return lookAhead(isDeclaration);
7527    }
7528
7529    function isStartOfStatement(): boolean {
7530        switch (token()) {
7531            case SyntaxKind.AtToken:
7532            case SyntaxKind.SemicolonToken:
7533            case SyntaxKind.OpenBraceToken:
7534            case SyntaxKind.VarKeyword:
7535            case SyntaxKind.LetKeyword:
7536            case SyntaxKind.FunctionKeyword:
7537            case SyntaxKind.ClassKeyword:
7538            case SyntaxKind.EnumKeyword:
7539            case SyntaxKind.IfKeyword:
7540            case SyntaxKind.DoKeyword:
7541            case SyntaxKind.WhileKeyword:
7542            case SyntaxKind.ForKeyword:
7543            case SyntaxKind.ContinueKeyword:
7544            case SyntaxKind.BreakKeyword:
7545            case SyntaxKind.ReturnKeyword:
7546            case SyntaxKind.WithKeyword:
7547            case SyntaxKind.SwitchKeyword:
7548            case SyntaxKind.ThrowKeyword:
7549            case SyntaxKind.TryKeyword:
7550            case SyntaxKind.DebuggerKeyword:
7551            // 'catch' and 'finally' do not actually indicate that the code is part of a statement,
7552            // however, we say they are here so that we may gracefully parse them and error later.
7553            // falls through
7554            case SyntaxKind.CatchKeyword:
7555            case SyntaxKind.FinallyKeyword:
7556                return true;
7557            case SyntaxKind.StructKeyword:
7558                return inEtsContext();
7559
7560            case SyntaxKind.ImportKeyword:
7561                return isStartOfDeclaration() || lookAhead(nextTokenIsOpenParenOrLessThanOrDot);
7562
7563            case SyntaxKind.ConstKeyword:
7564            case SyntaxKind.ExportKeyword:
7565                return isStartOfDeclaration();
7566
7567            case SyntaxKind.AsyncKeyword:
7568            case SyntaxKind.DeclareKeyword:
7569            case SyntaxKind.InterfaceKeyword:
7570            case SyntaxKind.ModuleKeyword:
7571            case SyntaxKind.NamespaceKeyword:
7572            case SyntaxKind.TypeKeyword:
7573            case SyntaxKind.GlobalKeyword:
7574                // When these don't start a declaration, they're an identifier in an expression statement
7575                return true;
7576
7577            case SyntaxKind.AccessorKeyword:
7578            case SyntaxKind.PublicKeyword:
7579            case SyntaxKind.PrivateKeyword:
7580            case SyntaxKind.ProtectedKeyword:
7581            case SyntaxKind.StaticKeyword:
7582            case SyntaxKind.ReadonlyKeyword:
7583                // When these don't start a declaration, they may be the start of a class member if an identifier
7584                // immediately follows. Otherwise they're an identifier in an expression statement.
7585                return isStartOfDeclaration() || !lookAhead(nextTokenIsIdentifierOrKeywordOnSameLine);
7586
7587            default:
7588                return isStartOfExpression();
7589        }
7590    }
7591
7592    function nextTokenIsBindingIdentifierOrStartOfDestructuring() {
7593        nextToken();
7594        return isBindingIdentifier() || token() === SyntaxKind.OpenBraceToken || token() === SyntaxKind.OpenBracketToken;
7595    }
7596
7597    function isLetDeclaration() {
7598        // In ES6 'let' always starts a lexical declaration if followed by an identifier or {
7599        // or [.
7600        return lookAhead(nextTokenIsBindingIdentifierOrStartOfDestructuring);
7601    }
7602
7603    function parseStatement(): Statement {
7604        switch (token()) {
7605            case SyntaxKind.SemicolonToken:
7606                return parseEmptyStatement();
7607            case SyntaxKind.OpenBraceToken:
7608                return parseBlock(/*ignoreMissingOpenBrace*/ false);
7609            case SyntaxKind.VarKeyword:
7610                return parseVariableStatement(getNodePos(), hasPrecedingJSDocComment(), /*decorators*/ undefined, /*modifiers*/ undefined);
7611            case SyntaxKind.LetKeyword:
7612                if (isLetDeclaration()) {
7613                    return parseVariableStatement(getNodePos(), hasPrecedingJSDocComment(), /*decorators*/ undefined, /*modifiers*/ undefined);
7614                }
7615                break;
7616            case SyntaxKind.FunctionKeyword:
7617                return parseFunctionDeclaration(getNodePos(), hasPrecedingJSDocComment(), /*decorators*/ undefined, /*modifiers*/ undefined);
7618            case SyntaxKind.StructKeyword:
7619                if (inEtsContext()) {
7620                    return parseStructDeclaration(getNodePos(), hasPrecedingJSDocComment(), /*decorators*/ undefined, /*modifiers*/ undefined);
7621                }
7622                break;
7623            case SyntaxKind.ClassKeyword:
7624                return parseClassDeclaration(getNodePos(), hasPrecedingJSDocComment(), /*decorators*/ undefined, /*modifiers*/ undefined);
7625            case SyntaxKind.IfKeyword:
7626                return parseIfStatement();
7627            case SyntaxKind.DoKeyword:
7628                return parseDoStatement();
7629            case SyntaxKind.WhileKeyword:
7630                return parseWhileStatement();
7631            case SyntaxKind.ForKeyword:
7632                return parseForOrForInOrForOfStatement();
7633            case SyntaxKind.ContinueKeyword:
7634                return parseBreakOrContinueStatement(SyntaxKind.ContinueStatement);
7635            case SyntaxKind.BreakKeyword:
7636                return parseBreakOrContinueStatement(SyntaxKind.BreakStatement);
7637            case SyntaxKind.ReturnKeyword:
7638                return parseReturnStatement();
7639            case SyntaxKind.WithKeyword:
7640                return parseWithStatement();
7641            case SyntaxKind.SwitchKeyword:
7642                return parseSwitchStatement();
7643            case SyntaxKind.ThrowKeyword:
7644                return parseThrowStatement();
7645            case SyntaxKind.TryKeyword:
7646            // Include 'catch' and 'finally' for error recovery.
7647            // falls through
7648            case SyntaxKind.CatchKeyword:
7649            case SyntaxKind.FinallyKeyword:
7650                return parseTryStatement();
7651            case SyntaxKind.DebuggerKeyword:
7652                return parseDebuggerStatement();
7653            case SyntaxKind.AtToken:
7654                return parseDeclaration();
7655            case SyntaxKind.AsyncKeyword:
7656            case SyntaxKind.InterfaceKeyword:
7657            case SyntaxKind.TypeKeyword:
7658            case SyntaxKind.ModuleKeyword:
7659            case SyntaxKind.NamespaceKeyword:
7660            case SyntaxKind.DeclareKeyword:
7661            case SyntaxKind.ConstKeyword:
7662            case SyntaxKind.EnumKeyword:
7663            case SyntaxKind.ExportKeyword:
7664            case SyntaxKind.ImportKeyword:
7665            case SyntaxKind.PrivateKeyword:
7666            case SyntaxKind.ProtectedKeyword:
7667            case SyntaxKind.PublicKeyword:
7668            case SyntaxKind.AbstractKeyword:
7669            case SyntaxKind.AccessorKeyword:
7670            case SyntaxKind.StaticKeyword:
7671            case SyntaxKind.ReadonlyKeyword:
7672            case SyntaxKind.GlobalKeyword:
7673                if (isStartOfDeclaration()) {
7674                    return parseDeclaration();
7675                }
7676                break;
7677        }
7678        return parseExpressionOrLabeledStatement();
7679    }
7680
7681    function isDeclareModifier(modifier: Modifier) {
7682        return modifier.kind === SyntaxKind.DeclareKeyword;
7683    }
7684
7685    function parseAnnotationDeclaration(pos: number, hasJSDoc: boolean, decorators: NodeArray<Decorator> | undefined,
7686        modifiers: NodeArray<Modifier> | undefined): AnnotationDeclaration {
7687        const atTokenPos = scanner.getTokenPos();
7688        parseExpected(SyntaxKind.AtToken);
7689        const interfaceTokenPos = scanner.getTokenPos();
7690        parseExpected(SyntaxKind.InterfaceKeyword);
7691
7692        // Prevent any tokens between '@' and 'interface'
7693        if (interfaceTokenPos - atTokenPos > 1) {
7694            parseErrorAt(atTokenPos + 1, interfaceTokenPos, Diagnostics.In_annotation_declaration_any_symbols_between_and_interface_are_forbidden);
7695        }
7696
7697        const name = createIdentifier(isBindingIdentifier());
7698        let members;
7699        if (parseExpected(SyntaxKind.OpenBraceToken)) {
7700            members = parseAnnotationMembers();
7701            parseExpected(SyntaxKind.CloseBraceToken);
7702        }
7703        else {
7704            members = createMissingList<AnnotationElement>();
7705        }
7706        const node = factory.createAnnotationDeclaration(combineDecoratorsAndModifiers(decorators, modifiers), name, members);
7707        return withJSDoc(finishNode(node, pos), hasJSDoc);
7708    }
7709
7710    function parseDeclaration(): Statement {
7711        // `parseListElement` attempted to get the reused node at this position,
7712        // but the ambient context flag was not yet set, so the node appeared
7713        // not reusable in that context.
7714        const pos = getNodePos();
7715        const hasJSDoc = hasPrecedingJSDocComment();
7716        const decorators = parseDecorators();
7717
7718        if (token() === SyntaxKind.FunctionKeyword || token() === SyntaxKind.ExportKeyword) {
7719            if (hasEtsExtendDecoratorNames(decorators, sourceFileCompilerOptions)) {
7720                const extendEtsComponentDecoratorNames = getEtsExtendDecoratorsComponentNames(decorators, sourceFileCompilerOptions);
7721                if (extendEtsComponentDecoratorNames.length > 0) {
7722                    sourceFileCompilerOptions.ets?.extend.components.forEach(({ name, type, instance }) => {
7723                        if (name === last(extendEtsComponentDecoratorNames)) {
7724                            extendEtsComponentDeclaration = { name, type, instance };
7725                        }
7726                    });
7727                }
7728                setEtsExtendComponentsContext(!!extendEtsComponentDeclaration);
7729            }
7730            else if (hasEtsStylesDecoratorNames(decorators, sourceFileCompilerOptions)) {
7731                const stylesEtsComponentDecoratorNames = getEtsStylesDecoratorComponentNames(decorators, sourceFileCompilerOptions);
7732                if (stylesEtsComponentDecoratorNames.length > 0) {
7733                    stylesEtsComponentDeclaration = sourceFileCompilerOptions.ets?.styles.component;
7734                }
7735                setEtsStylesComponentsContext(!!stylesEtsComponentDeclaration);
7736            }
7737            else {
7738                setEtsComponentsContext(isTokenInsideBuilder(decorators, sourceFileCompilerOptions));
7739            }
7740        }
7741
7742        const modifiers = parseModifiers();
7743        const isAmbient = some(modifiers, isDeclareModifier);
7744        if (isAmbient) {
7745            const node = tryReuseAmbientDeclaration(pos);
7746            if (node) {
7747                return node;
7748            }
7749
7750            for (const m of modifiers!) {
7751                (m as Mutable<Node>).flags |= NodeFlags.Ambient;
7752            }
7753            return doInsideOfContext(NodeFlags.Ambient, () => parseDeclarationWorker(pos, hasJSDoc, decorators, modifiers));
7754        }
7755        else {
7756            return parseDeclarationWorker(pos, hasJSDoc, decorators, modifiers);
7757        }
7758    }
7759
7760    function tryReuseAmbientDeclaration(pos: number): Statement | undefined {
7761        return doInsideOfContext(NodeFlags.Ambient, () => {
7762            const node = currentNode(parsingContext, pos);
7763            if (node) {
7764                return consumeNode(node) as Statement;
7765            }
7766        });
7767    }
7768
7769    function parseDeclarationWorker(pos: number, hasJSDoc: boolean, decorators: NodeArray<Decorator> | undefined, modifiers: NodeArray<Modifier> | undefined): Statement {
7770        switch (token()) {
7771            case SyntaxKind.VarKeyword:
7772            case SyntaxKind.LetKeyword:
7773            case SyntaxKind.ConstKeyword:
7774                return parseVariableStatement(pos, hasJSDoc, decorators, modifiers);
7775            case SyntaxKind.FunctionKeyword:
7776                return parseFunctionDeclaration(pos, hasJSDoc, decorators, modifiers);
7777            case SyntaxKind.ClassKeyword:
7778                return parseClassDeclaration(pos, hasJSDoc, decorators, modifiers);
7779            case SyntaxKind.StructKeyword:
7780                if (inEtsContext()) {
7781                    return parseStructDeclaration(pos, hasJSDoc, decorators, modifiers);
7782                }
7783                return parseDeclarationDefault(pos,decorators, modifiers);
7784            case SyntaxKind.AtToken:
7785                if (inAllowAnnotationContext() &&
7786                    lookAhead(() => nextToken() === SyntaxKind.InterfaceKeyword)) {
7787                    return parseAnnotationDeclaration(pos, hasJSDoc, decorators, modifiers);
7788                }
7789                return parseDeclarationDefault(pos, decorators, modifiers);
7790            case SyntaxKind.InterfaceKeyword:
7791                return parseInterfaceDeclaration(pos, hasJSDoc, decorators, modifiers);
7792            case SyntaxKind.TypeKeyword:
7793                return parseTypeAliasDeclaration(pos, hasJSDoc, decorators, modifiers);
7794            case SyntaxKind.EnumKeyword:
7795                return parseEnumDeclaration(pos, hasJSDoc, decorators, modifiers);
7796            case SyntaxKind.GlobalKeyword:
7797            case SyntaxKind.ModuleKeyword:
7798            case SyntaxKind.NamespaceKeyword:
7799                return parseModuleDeclaration(pos, hasJSDoc, decorators, modifiers);
7800            case SyntaxKind.ImportKeyword:
7801                return parseImportDeclarationOrImportEqualsDeclaration(pos, hasJSDoc, decorators, modifiers);
7802            case SyntaxKind.ExportKeyword:
7803                nextToken();
7804                switch (token()) {
7805                    case SyntaxKind.DefaultKeyword:
7806                    case SyntaxKind.EqualsToken:
7807                        return parseExportAssignment(pos, hasJSDoc, decorators, modifiers);
7808                    case SyntaxKind.AsKeyword:
7809                        return parseNamespaceExportDeclaration(pos, hasJSDoc, decorators, modifiers);
7810                    default:
7811                        return parseExportDeclaration(pos, hasJSDoc, decorators, modifiers);
7812                }
7813            default:
7814                return parseDeclarationDefault(pos,decorators, modifiers);
7815        }
7816    }
7817
7818    function parseDeclarationDefault(pos: number,decorators: NodeArray<Decorator> | undefined, modifiers: NodeArray<Modifier> | undefined): Statement {
7819        if (decorators || modifiers) {
7820            // We reached this point because we encountered decorators and/or modifiers and assumed a declaration
7821            // would follow. For recovery and error reporting purposes, return an incomplete declaration.
7822            const missing = createMissingNode<MissingDeclaration>(SyntaxKind.MissingDeclaration, /*reportAtCurrentPosition*/ true, Diagnostics.Declaration_expected);
7823            setTextRangePos(missing, pos);
7824            missing.illegalDecorators = decorators;
7825            missing.modifiers = modifiers;
7826            return missing;
7827        }
7828        return undefined!; // TODO: GH#18217
7829    }
7830
7831    function nextTokenIsIdentifierOrStringLiteralOnSameLine() {
7832        nextToken();
7833        return !scanner.hasPrecedingLineBreak() && (isIdentifier() || token() === SyntaxKind.StringLiteral);
7834    }
7835
7836    function parseFunctionBlockOrSemicolon(flags: SignatureFlags, diagnosticMessage?: DiagnosticMessage): Block | undefined {
7837        if (token() !== SyntaxKind.OpenBraceToken) {
7838            if (flags & SignatureFlags.Type) {
7839                parseTypeMemberSemicolon();
7840                return;
7841            }
7842            if (canParseSemicolon()) {
7843                parseSemicolon();
7844                return;
7845            }
7846        }
7847        return parseFunctionBlock(flags, diagnosticMessage);
7848    }
7849
7850    // DECLARATIONS
7851
7852    function parseArrayBindingElement(): ArrayBindingElement {
7853        const pos = getNodePos();
7854        if (token() === SyntaxKind.CommaToken) {
7855            return finishNode(factory.createOmittedExpression(), pos);
7856        }
7857        const dotDotDotToken = parseOptionalToken(SyntaxKind.DotDotDotToken);
7858        const name = parseIdentifierOrPattern();
7859        const initializer = parseInitializer();
7860        return finishNode(factory.createBindingElement(dotDotDotToken, /*propertyName*/ undefined, name, initializer), pos);
7861    }
7862
7863    function parseObjectBindingElement(): BindingElement {
7864        const pos = getNodePos();
7865        const dotDotDotToken = parseOptionalToken(SyntaxKind.DotDotDotToken);
7866        const tokenIsIdentifier = isBindingIdentifier();
7867        let propertyName: PropertyName | undefined = parsePropertyName();
7868        let name: BindingName;
7869        if (tokenIsIdentifier && token() !== SyntaxKind.ColonToken) {
7870            name = propertyName as Identifier;
7871            propertyName = undefined;
7872        }
7873        else {
7874            parseExpected(SyntaxKind.ColonToken);
7875            name = parseIdentifierOrPattern();
7876        }
7877        const initializer = parseInitializer();
7878        return finishNode(factory.createBindingElement(dotDotDotToken, propertyName, name, initializer), pos);
7879    }
7880
7881    function parseObjectBindingPattern(): ObjectBindingPattern {
7882        const pos = getNodePos();
7883        parseExpected(SyntaxKind.OpenBraceToken);
7884        const elements = parseDelimitedList(ParsingContext.ObjectBindingElements, parseObjectBindingElement);
7885        parseExpected(SyntaxKind.CloseBraceToken);
7886        return finishNode(factory.createObjectBindingPattern(elements), pos);
7887    }
7888
7889    function parseArrayBindingPattern(): ArrayBindingPattern {
7890        const pos = getNodePos();
7891        parseExpected(SyntaxKind.OpenBracketToken);
7892        const elements = parseDelimitedList(ParsingContext.ArrayBindingElements, parseArrayBindingElement);
7893        parseExpected(SyntaxKind.CloseBracketToken);
7894        return finishNode(factory.createArrayBindingPattern(elements), pos);
7895    }
7896
7897    function isBindingIdentifierOrPrivateIdentifierOrPattern() {
7898        return token() === SyntaxKind.OpenBraceToken
7899            || token() === SyntaxKind.OpenBracketToken
7900            || token() === SyntaxKind.PrivateIdentifier
7901            || isBindingIdentifier();
7902    }
7903
7904    function parseIdentifierOrPattern(privateIdentifierDiagnosticMessage?: DiagnosticMessage): Identifier | BindingPattern {
7905        if (token() === SyntaxKind.OpenBracketToken) {
7906            return parseArrayBindingPattern();
7907        }
7908        if (token() === SyntaxKind.OpenBraceToken) {
7909            return parseObjectBindingPattern();
7910        }
7911        return parseBindingIdentifier(privateIdentifierDiagnosticMessage);
7912    }
7913
7914    function parseVariableDeclarationAllowExclamation() {
7915        return parseVariableDeclaration(/*allowExclamation*/ true);
7916    }
7917
7918    function parseVariableDeclaration(allowExclamation?: boolean): VariableDeclaration {
7919        const pos = getNodePos();
7920        const hasJSDoc = hasPrecedingJSDocComment();
7921        const name = parseIdentifierOrPattern(Diagnostics.Private_identifiers_are_not_allowed_in_variable_declarations);
7922        let exclamationToken: ExclamationToken | undefined;
7923        if (allowExclamation && name.kind === SyntaxKind.Identifier &&
7924            token() === SyntaxKind.ExclamationToken && !scanner.hasPrecedingLineBreak()) {
7925            exclamationToken = parseTokenNode<Token<SyntaxKind.ExclamationToken>>();
7926        }
7927        const type = parseTypeAnnotation();
7928        const initializer = isInOrOfKeyword(token()) ? undefined : parseInitializer();
7929        const node = factory.createVariableDeclaration(name, exclamationToken, type, initializer);
7930        return withJSDoc(finishNode(node, pos), hasJSDoc);
7931    }
7932
7933    function parseVariableDeclarationList(inForStatementInitializer: boolean): VariableDeclarationList {
7934        const pos = getNodePos();
7935
7936        let flags: NodeFlags = 0;
7937        switch (token()) {
7938            case SyntaxKind.VarKeyword:
7939                break;
7940            case SyntaxKind.LetKeyword:
7941                flags |= NodeFlags.Let;
7942                break;
7943            case SyntaxKind.ConstKeyword:
7944                flags |= NodeFlags.Const;
7945                break;
7946            default:
7947                Debug.fail();
7948        }
7949
7950        nextToken();
7951
7952        // The user may have written the following:
7953        //
7954        //    for (let of X) { }
7955        //
7956        // In this case, we want to parse an empty declaration list, and then parse 'of'
7957        // as a keyword. The reason this is not automatic is that 'of' is a valid identifier.
7958        // So we need to look ahead to determine if 'of' should be treated as a keyword in
7959        // this context.
7960        // The checker will then give an error that there is an empty declaration list.
7961        let declarations: readonly VariableDeclaration[];
7962        if (token() === SyntaxKind.OfKeyword && lookAhead(canFollowContextualOfKeyword)) {
7963            declarations = createMissingList<VariableDeclaration>();
7964        }
7965        else {
7966            const savedDisallowIn = inDisallowInContext();
7967            setDisallowInContext(inForStatementInitializer);
7968
7969            declarations = parseDelimitedList(ParsingContext.VariableDeclarations,
7970                inForStatementInitializer ? parseVariableDeclaration : parseVariableDeclarationAllowExclamation);
7971
7972            setDisallowInContext(savedDisallowIn);
7973        }
7974
7975        return finishNode(factory.createVariableDeclarationList(declarations, flags), pos);
7976    }
7977
7978    function canFollowContextualOfKeyword(): boolean {
7979        return nextTokenIsIdentifier() && nextToken() === SyntaxKind.CloseParenToken;
7980    }
7981
7982    function parseVariableStatement(pos: number, hasJSDoc: boolean, decorators: NodeArray<Decorator> | undefined, modifiers: NodeArray<Modifier> | undefined): VariableStatement {
7983        const declarationList = parseVariableDeclarationList(/*inForStatementInitializer*/ false);
7984        parseSemicolon();
7985        const node = factory.createVariableStatement(modifiers, declarationList);
7986        // Decorators are not allowed on a variable statement, so we keep track of them to report them in the grammar checker.
7987        node.illegalDecorators = decorators;
7988        return withJSDoc(finishNode(node, pos), hasJSDoc);
7989    }
7990
7991    function parseFunctionDeclaration(pos: number, hasJSDoc: boolean, decorators: NodeArray<Decorator> | undefined, modifiers: NodeArray<Modifier> | undefined): FunctionDeclaration {
7992        const savedAwaitContext = inAwaitContext();
7993
7994        const modifierFlags = modifiersToFlags(modifiers);
7995        parseExpected(SyntaxKind.FunctionKeyword);
7996        const asteriskToken = parseOptionalToken(SyntaxKind.AsteriskToken);
7997        // We don't parse the name here in await context, instead we will report a grammar error in the checker.
7998        const name = modifierFlags & ModifierFlags.Default ? parseOptionalBindingIdentifier() : parseBindingIdentifier();
7999        if(name && hasEtsStylesDecoratorNames(decorators, sourceFileCompilerOptions)) {
8000            fileStylesComponents.set(name.escapedText.toString(), SyntaxKind.FunctionDeclaration);
8001        }
8002        const originalUICallbackContext = inUICallbackContext();
8003        setEtsBuilderContext(hasEtsBuilderDecoratorNames(decorators, sourceFileCompilerOptions));
8004        setUICallbackContext(inBuilderContext());
8005        const isGenerator = asteriskToken ? SignatureFlags.Yield : SignatureFlags.None;
8006        const isAsync = modifierFlags & ModifierFlags.Async ? SignatureFlags.Await : SignatureFlags.None;
8007        const typeParameters = inEtsStylesComponentsContext() && stylesEtsComponentDeclaration ? parseEtsTypeParameters(scanner.getStartPos()) : parseTypeParameters();
8008        if (modifierFlags & ModifierFlags.Export) setAwaitContext(/*value*/ true);
8009        const parameters = parseParameters(isGenerator | isAsync);
8010        const typeStartPos = scanner.getStartPos();
8011        const type = getFunctionDeclarationReturnType();
8012        const body = parseFunctionBlockOrSemicolon(isGenerator | isAsync, Diagnostics.or_expected);
8013        setEtsBuilderContext(false);
8014        setUICallbackContext(originalUICallbackContext);
8015        setEtsExtendComponentsContext(false);
8016        extendEtsComponentDeclaration = undefined;
8017        setEtsStylesComponentsContext(false);
8018        stylesEtsComponentDeclaration = undefined;
8019        setEtsComponentsContext(inBuildContext());
8020        setAwaitContext(savedAwaitContext);
8021        const node = factory.createFunctionDeclaration(modifiers, asteriskToken, name, typeParameters, parameters, type, body);
8022        (node as Mutable<FunctionDeclaration>).illegalDecorators = decorators;
8023        return withJSDoc(finishNode(node, pos), hasJSDoc);
8024
8025        function getFunctionDeclarationReturnType(): TypeNode | undefined {
8026            let returnType = parseReturnType(SyntaxKind.ColonToken, /*isType*/ false);
8027            // If function decorated by Extend and type is not defined, then will use Ets Extend Components Type
8028            if (!returnType && extendEtsComponentDeclaration && inEtsExtendComponentsContext()) {
8029                returnType = finishVirtualNode(factory.createTypeReferenceNode(
8030                    finishVirtualNode(factory.createIdentifier(extendEtsComponentDeclaration.type), typeStartPos, typeStartPos)),
8031                    typeStartPos, typeStartPos);
8032            }
8033            // If function decorated by Styles and type is not defined, then will use Ets Styles Components Type
8034            if (!returnType && stylesEtsComponentDeclaration && inEtsStylesComponentsContext()) {
8035                returnType = finishVirtualNode(factory.createTypeReferenceNode(
8036                    finishVirtualNode(factory.createIdentifier(stylesEtsComponentDeclaration.type), typeStartPos, typeStartPos)),
8037                    typeStartPos, typeStartPos);
8038            }
8039            return returnType;
8040        }
8041    }
8042
8043    function parseConstructorName() {
8044        if (token() === SyntaxKind.ConstructorKeyword) {
8045            return parseExpected(SyntaxKind.ConstructorKeyword);
8046        }
8047        if (token() === SyntaxKind.StringLiteral && lookAhead(nextToken) === SyntaxKind.OpenParenToken) {
8048            return tryParse(() => {
8049                const literalNode = parseLiteralNode();
8050                return literalNode.text === "constructor" ? literalNode : undefined;
8051            });
8052        }
8053    }
8054
8055    function tryParseConstructorDeclaration(pos: number, hasJSDoc: boolean, decorators: NodeArray<Decorator> | undefined, modifiers: NodeArray<Modifier> | undefined): ConstructorDeclaration | undefined {
8056        return tryParse(() => {
8057            if (parseConstructorName()) {
8058                const typeParameters = parseTypeParameters();
8059                const parameters = parseParameters(SignatureFlags.None);
8060                const type = parseReturnType(SyntaxKind.ColonToken, /*isType*/ false);
8061                const body = parseFunctionBlockOrSemicolon(SignatureFlags.None, Diagnostics.or_expected);
8062                const node = factory.createConstructorDeclaration(modifiers, parameters, body);
8063
8064                // Attach invalid nodes if they exist so that we can report them in the grammar checker.
8065                (node as Mutable<ConstructorDeclaration>).illegalDecorators = decorators;
8066                (node as Mutable<ConstructorDeclaration>).typeParameters = typeParameters;
8067                (node as Mutable<ConstructorDeclaration>).type = type;
8068                return withJSDoc(finishNode(node, pos), hasJSDoc);
8069            }
8070        });
8071    }
8072
8073
8074    function isTokenInsideStructBuild(methodName: PropertyName): boolean {
8075        const renderMethod = sourceFileCompilerOptions.ets?.render?.method?.find(render => render === "build") ?? "build";
8076
8077        if (methodName.kind === SyntaxKind.Identifier && methodName.escapedText === renderMethod) {
8078            return true;
8079        }
8080        return false;
8081    }
8082
8083    function isTokenInsideStructBuilder(decorators: NodeArray<Decorator> | undefined): boolean {
8084        return isTokenInsideBuilder(decorators, sourceFileCompilerOptions);
8085    }
8086
8087    function isTokenInsideStructPageTransition(methodName: PropertyName): boolean {
8088        const renderMethod = sourceFileCompilerOptions.ets?.render?.method?.find(render => render === "pageTransition") ?? "pageTransition";
8089
8090        if (methodName.kind === SyntaxKind.Identifier && methodName.escapedText === renderMethod) {
8091            return true;
8092        }
8093        return false;
8094    }
8095
8096    function parseMethodDeclaration(
8097        pos: number,
8098        hasJSDoc: boolean,
8099        decorators: NodeArray<Decorator> | undefined,
8100        modifiers: NodeArray<Modifier> | undefined,
8101        asteriskToken: AsteriskToken | undefined,
8102        name: PropertyName,
8103        questionToken: QuestionToken | undefined,
8104        exclamationToken: ExclamationToken | undefined,
8105        diagnosticMessage?: DiagnosticMessage
8106    ): MethodDeclaration {
8107        const methodName = getPropertyNameForPropertyNameNode(name)?.toString();
8108        const orignalEtsBuildContext = inBuildContext();
8109        const orignalEtsBuilderContext = inBuilderContext();
8110        const orignalUICallbackContext = inUICallbackContext();
8111        setEtsBuildContext(methodName === sourceFileCompilerOptions?.ets?.render?.method?.find(render => render === "build"));
8112        setEtsBuilderContext(hasEtsBuilderDecoratorNames(decorators, sourceFileCompilerOptions));
8113        setUICallbackContext(inBuildContext() || inBuilderContext());
8114        if (inStructContext() && hasEtsStylesDecoratorNames(decorators, sourceFileCompilerOptions)) {
8115            if (methodName && currentStructName) {
8116                structStylesComponents.set(methodName, { structName: currentStructName, kind: SyntaxKind.MethodDeclaration });
8117            }
8118            const stylesEtsComponentDecoratorNames = getEtsStylesDecoratorComponentNames(decorators, sourceFileCompilerOptions);
8119            if (stylesEtsComponentDecoratorNames.length > 0) {
8120                stylesEtsComponentDeclaration = sourceFileCompilerOptions.ets?.styles.component;
8121            }
8122            setEtsStylesComponentsContext(!!stylesEtsComponentDeclaration);
8123        }
8124        const orignalEtsComponentsContext: boolean = inEtsComponentsContext();
8125        setEtsComponentsContext(inStructContext() && (isTokenInsideStructBuild(name) || isTokenInsideStructBuilder(decorators) ||
8126            isTokenInsideStructPageTransition(name)));
8127        const isGenerator = asteriskToken ? SignatureFlags.Yield : SignatureFlags.None;
8128        const isAsync = some(modifiers, isAsyncModifier) ? SignatureFlags.Await : SignatureFlags.None;
8129        const typeParameters = inEtsStylesComponentsContext() && stylesEtsComponentDeclaration ? parseEtsTypeParameters(pos) : parseTypeParameters();
8130        const parameters = parseParameters(isGenerator | isAsync);
8131        const typeStartPos = scanner.getStartPos();
8132        const type = getMethodDeclarationReturnType();
8133        const body = parseFunctionBlockOrSemicolon(isGenerator | isAsync, diagnosticMessage);
8134        const node = factory.createMethodDeclaration(
8135            combineDecoratorsAndModifiers(decorators, modifiers),
8136            asteriskToken,
8137            name,
8138            questionToken,
8139            typeParameters,
8140            parameters,
8141            type,
8142            body
8143        );
8144
8145        // An exclamation token on a method is invalid syntax and will be handled by the grammar checker
8146        (node as Mutable<MethodDeclaration>).exclamationToken = exclamationToken;
8147        setEtsBuildContext(orignalEtsBuildContext);
8148        setEtsBuilderContext(orignalEtsBuilderContext);
8149        setUICallbackContext(orignalUICallbackContext);
8150        setEtsStylesComponentsContext(false);
8151        stylesEtsComponentDeclaration = undefined;
8152        setEtsComponentsContext(orignalEtsComponentsContext);
8153        return withJSDoc(finishNode(node, pos), hasJSDoc);
8154
8155        function getMethodDeclarationReturnType(): TypeNode | undefined {
8156            let returnType = parseReturnType(SyntaxKind.ColonToken, /*isType*/ false);
8157            // If function decorated by Styles and type is not defined, then will use Ets Styles Components Type
8158            if (!returnType && stylesEtsComponentDeclaration && inEtsStylesComponentsContext()) {
8159                returnType = finishVirtualNode(factory.createTypeReferenceNode(
8160                    finishVirtualNode(factory.createIdentifier(stylesEtsComponentDeclaration.type), typeStartPos, typeStartPos)),
8161                    typeStartPos, typeStartPos);
8162            }
8163            return returnType;
8164        }
8165    }
8166
8167    function parseAnnotationPropertyDeclaration(
8168        pos: number,
8169        hasJSDoc: boolean,
8170        name: PropertyName
8171    ): AnnotationPropertyDeclaration {
8172        const type = parseTypeAnnotation();
8173        const initializer = doOutsideOfContext(NodeFlags.YieldContext | NodeFlags.AwaitContext | NodeFlags.DisallowInContext, parseInitializer);
8174        parseSemicolonAfterPropertyName(name, type, initializer);
8175        const node = factory.createAnnotationPropertyDeclaration(
8176            name,
8177            type,
8178            initializer);
8179        return withJSDoc(finishNode(node, pos), hasJSDoc);
8180    }
8181
8182    function parsePropertyDeclaration(
8183        pos: number,
8184        hasJSDoc: boolean,
8185        decorators: NodeArray<Decorator> | undefined,
8186        modifiers: NodeArray<Modifier> | undefined,
8187        name: PropertyName,
8188        questionToken: QuestionToken | undefined
8189    ): PropertyDeclaration {
8190        const exclamationToken = !questionToken && !scanner.hasPrecedingLineBreak() ? parseOptionalToken(SyntaxKind.ExclamationToken) : undefined;
8191        const type = parseTypeAnnotation();
8192        const initializer = doOutsideOfContext(NodeFlags.YieldContext | NodeFlags.AwaitContext | NodeFlags.DisallowInContext, parseInitializer);
8193        parseSemicolonAfterPropertyName(name, type, initializer);
8194        const node = factory.createPropertyDeclaration(
8195            combineDecoratorsAndModifiers(decorators, modifiers),
8196            name,
8197            questionToken || exclamationToken,
8198            type,
8199            initializer);
8200        return withJSDoc(finishNode(node, pos), hasJSDoc);
8201    }
8202
8203    function parsePropertyOrMethodDeclaration(
8204        pos: number,
8205        hasJSDoc: boolean,
8206        decorators: NodeArray<Decorator> | undefined,
8207        modifiers: NodeArray<Modifier> | undefined
8208    ): PropertyDeclaration | MethodDeclaration {
8209        const asteriskToken = parseOptionalToken(SyntaxKind.AsteriskToken);
8210        const name = parsePropertyName();
8211        // Note: this is not legal as per the grammar.  But we allow it in the parser and
8212        // report an error in the grammar checker.
8213        const questionToken = parseOptionalToken(SyntaxKind.QuestionToken);
8214        if (asteriskToken || token() === SyntaxKind.OpenParenToken || token() === SyntaxKind.LessThanToken) {
8215            return parseMethodDeclaration(pos, hasJSDoc, decorators, modifiers, asteriskToken, name, questionToken, /*exclamationToken*/ undefined, Diagnostics.or_expected);
8216        }
8217        return parsePropertyDeclaration(pos, hasJSDoc, decorators, modifiers, name, questionToken);
8218    }
8219
8220    function parseAccessorDeclaration(pos: number, hasJSDoc: boolean, decorators: NodeArray<Decorator> | undefined, modifiers: NodeArray<Modifier> | undefined, kind: AccessorDeclaration["kind"], flags: SignatureFlags): AccessorDeclaration {
8221        const name = parsePropertyName();
8222        const typeParameters = parseTypeParameters();
8223        const parameters = parseParameters(SignatureFlags.None);
8224        const type = parseReturnType(SyntaxKind.ColonToken, /*isType*/ false);
8225        const body = parseFunctionBlockOrSemicolon(flags);
8226        const node = kind === SyntaxKind.GetAccessor
8227            ? factory.createGetAccessorDeclaration(combineDecoratorsAndModifiers(decorators, modifiers), name, parameters, type, body)
8228            : factory.createSetAccessorDeclaration(combineDecoratorsAndModifiers(decorators, modifiers), name, parameters, body);
8229        // Keep track of `typeParameters` (for both) and `type` (for setters) if they were parsed those indicate grammar errors
8230        (node as Mutable<AccessorDeclaration>).typeParameters = typeParameters;
8231        if (isSetAccessorDeclaration(node)) (node as Mutable<SetAccessorDeclaration>).type = type;
8232        return withJSDoc(finishNode(node, pos), hasJSDoc);
8233    }
8234
8235    function isAnnotationMemberStart(): boolean {
8236        let idToken: SyntaxKind | undefined;
8237
8238        if (token() === SyntaxKind.AtToken) {
8239            return false;
8240        }
8241
8242        if (isModifierKind(token())) {
8243            return false;
8244        }
8245
8246        if (token() === SyntaxKind.AsteriskToken) {
8247            return false;
8248        }
8249
8250        // Try to get the first property-like token following all modifiers.
8251        // This can either be an identifier or the 'get' or 'set' keywords.
8252        if (isLiteralPropertyName()) {
8253            idToken = token();
8254            nextToken();
8255        }
8256
8257        // Index signatures and computed properties are prohibited for annotations
8258        if (token() === SyntaxKind.OpenBracketToken) {
8259            return false;
8260        }
8261
8262        // If we were able to get any potential identifier...
8263        if (idToken !== undefined) {
8264            // If we have a non-keyword identifier, or if we have an accessor, then we no need to parse.
8265            if (isKeyword(idToken)) {
8266                return false;
8267            }
8268
8269            // If it *is* a keyword, but not an accessor, check a little farther along
8270            // to see if it should actually be parsed as a class member.
8271            switch (token()) {
8272                case SyntaxKind.ColonToken: // Type Annotation for declaration
8273                case SyntaxKind.EqualsToken: // Initializer for declaration
8274                    return true;
8275                default:
8276                    // Covers
8277                    //  - Semicolons     (declaration termination)
8278                    //  - Closing braces (end-of-class, must be declaration)
8279                    //  - End-of-files   (not valid, but permitted so that it gets caught later on)
8280                    //  - Line-breaks    (enabling *automatic semicolon insertion*)
8281                    return canParseSemicolon();
8282            }
8283        }
8284        return false;
8285    }
8286
8287    function isClassMemberStart(): boolean {
8288        let idToken: SyntaxKind | undefined;
8289
8290        if (token() === SyntaxKind.AtToken) {
8291            if (inAllowAnnotationContext() && lookAhead(() => nextToken() === SyntaxKind.InterfaceKeyword)) {
8292                return false;
8293            }
8294            return true;
8295        }
8296
8297        // Eat up all modifiers, but hold on to the last one in case it is actually an identifier.
8298        while (isModifierKind(token())) {
8299            idToken = token();
8300            // If the idToken is a class modifier (protected, private, public, and static), it is
8301            // certain that we are starting to parse class member. This allows better error recovery
8302            // Example:
8303            //      public foo() ...     // true
8304            //      public @dec blah ... // true; we will then report an error later
8305            //      export public ...    // true; we will then report an error later
8306            if (isClassMemberModifier(idToken)) {
8307                return true;
8308            }
8309
8310            nextToken();
8311        }
8312
8313        if (token() === SyntaxKind.AsteriskToken) {
8314            return true;
8315        }
8316
8317        // Try to get the first property-like token following all modifiers.
8318        // This can either be an identifier or the 'get' or 'set' keywords.
8319        if (isLiteralPropertyName()) {
8320            idToken = token();
8321            nextToken();
8322        }
8323
8324        // Index signatures and computed properties are class members; we can parse.
8325        if (token() === SyntaxKind.OpenBracketToken) {
8326            return true;
8327        }
8328
8329        // If we were able to get any potential identifier...
8330        if (idToken !== undefined) {
8331            // If we have a non-keyword identifier, or if we have an accessor, then it's safe to parse.
8332            if (!isKeyword(idToken) || idToken === SyntaxKind.SetKeyword || idToken === SyntaxKind.GetKeyword) {
8333                return true;
8334            }
8335
8336            // If it *is* a keyword, but not an accessor, check a little farther along
8337            // to see if it should actually be parsed as a class member.
8338            switch (token()) {
8339                case SyntaxKind.OpenParenToken:     // Method declaration
8340                case SyntaxKind.LessThanToken:      // Generic Method declaration
8341                case SyntaxKind.ExclamationToken:   // Non-null assertion on property name
8342                case SyntaxKind.ColonToken:         // Type Annotation for declaration
8343                case SyntaxKind.EqualsToken:        // Initializer for declaration
8344                case SyntaxKind.QuestionToken:      // Not valid, but permitted so that it gets caught later on.
8345                    return true;
8346                default:
8347                    // Covers
8348                    //  - Semicolons     (declaration termination)
8349                    //  - Closing braces (end-of-class, must be declaration)
8350                    //  - End-of-files   (not valid, but permitted so that it gets caught later on)
8351                    //  - Line-breaks    (enabling *automatic semicolon insertion*)
8352                    return canParseSemicolon();
8353            }
8354        }
8355        return false;
8356    }
8357
8358    function parseClassStaticBlockDeclaration(pos: number, hasJSDoc: boolean, decorators: NodeArray<Decorator> | undefined, modifiers: ModifiersArray | undefined): ClassStaticBlockDeclaration {
8359        parseExpectedToken(SyntaxKind.StaticKeyword);
8360        const body = parseClassStaticBlockBody();
8361        const node = withJSDoc(finishNode(factory.createClassStaticBlockDeclaration(body), pos), hasJSDoc);
8362        (node as Mutable<ClassStaticBlockDeclaration>).illegalDecorators = decorators;
8363        (node as Mutable<ClassStaticBlockDeclaration>).modifiers = modifiers;
8364        return node;
8365    }
8366
8367    function parseClassStaticBlockBody() {
8368        const savedYieldContext = inYieldContext();
8369        const savedAwaitContext = inAwaitContext();
8370
8371        setYieldContext(false);
8372        setAwaitContext(true);
8373
8374        const body = parseBlock(/*ignoreMissingOpenBrace*/ false);
8375
8376        setYieldContext(savedYieldContext);
8377        setAwaitContext(savedAwaitContext);
8378
8379        return body;
8380    }
8381
8382    function parseDecoratorExpression() {
8383        if (inAwaitContext() && token() === SyntaxKind.AwaitKeyword) {
8384            // `@await` is is disallowed in an [Await] context, but can cause parsing to go off the rails
8385            // This simply parses the missing identifier and moves on.
8386            const pos = getNodePos();
8387            const awaitExpression = parseIdentifier(Diagnostics.Expression_expected);
8388            nextToken();
8389            const memberExpression = parseMemberExpressionRest(pos, awaitExpression, /*allowOptionalChain*/ true);
8390            return parseCallExpressionRest(pos, memberExpression);
8391        }
8392        return parseLeftHandSideExpressionOrHigher();
8393    }
8394
8395    function tryParseDecorator(): Decorator | undefined {
8396        const pos = getNodePos();
8397        if (inAllowAnnotationContext() && token() === SyntaxKind.AtToken && lookAhead(() => nextToken() === SyntaxKind.InterfaceKeyword)) {
8398            return undefined;
8399        }
8400        if (!parseOptional(SyntaxKind.AtToken)) {
8401            return undefined;
8402        }
8403        const expression = doInDecoratorContext(parseDecoratorExpression);
8404        return finishNode(factory.createDecorator(expression), pos);
8405    }
8406
8407    function parseDecorators(): NodeArray<Decorator> | undefined {
8408        const pos = getNodePos();
8409        let list, decorator;
8410        while (decorator = tryParseDecorator()) {
8411            list = append(list, decorator);
8412        }
8413        return list && createNodeArray(list, pos);
8414    }
8415
8416    function tryParseModifier(permitInvalidConstAsModifier?: boolean, stopOnStartOfClassStaticBlock?: boolean, hasSeenStaticModifier?: boolean): Modifier | undefined {
8417        const pos = getNodePos();
8418        const kind = token();
8419
8420        if (token() === SyntaxKind.ConstKeyword && permitInvalidConstAsModifier) {
8421            // We need to ensure that any subsequent modifiers appear on the same line
8422            // so that when 'const' is a standalone declaration, we don't issue an error.
8423            if (!tryParse(nextTokenIsOnSameLineAndCanFollowModifier)) {
8424                return undefined;
8425            }
8426        }
8427        else if (stopOnStartOfClassStaticBlock && token() === SyntaxKind.StaticKeyword && lookAhead(nextTokenIsOpenBrace)) {
8428            return undefined;
8429        }
8430        else if (hasSeenStaticModifier && token() === SyntaxKind.StaticKeyword) {
8431            return undefined;
8432        }
8433        else {
8434            if (!parseAnyContextualModifier()) {
8435                return undefined;
8436            }
8437        }
8438
8439        return finishNode(factory.createToken(kind as Modifier["kind"]), pos);
8440    }
8441
8442    function combineDecoratorsAndModifiers(decorators: NodeArray<Decorator> | undefined, modifiers: NodeArray<Modifier> | undefined): NodeArray<ModifierLike> | undefined {
8443        if (!decorators) return modifiers;
8444        if (!modifiers) return decorators;
8445        const decoratorsAndModifiers = factory.createNodeArray(concatenate<ModifierLike>(decorators, modifiers));
8446        setTextRangePosEnd(decoratorsAndModifiers, decorators.pos, modifiers.end);
8447        return decoratorsAndModifiers;
8448    }
8449
8450    function hasParamAndNoOnceDecorator(decorators: NodeArray<Decorator> | undefined): boolean {
8451        let hasParamDecorator = false;
8452        let hasOnceDecorator = false;
8453        decorators?.forEach((decorator) => {
8454            if (!ts.isIdentifier(decorator.expression)) {
8455                return;
8456            }
8457            if (decorator.expression.escapedText === 'Param') {
8458                hasParamDecorator = true;
8459            }
8460            else if (decorator.expression.escapedText === 'Once') {
8461                hasOnceDecorator = true;
8462            }
8463        });
8464        return (hasParamDecorator && !hasOnceDecorator);
8465    }
8466    /*
8467     * There are situations in which a modifier like 'const' will appear unexpectedly, such as on a class member.
8468     * In those situations, if we are entirely sure that 'const' is not valid on its own (such as when ASI takes effect
8469     * and turns it into a standalone declaration), then it is better to parse it and report an error later.
8470     *
8471     * In such situations, 'permitInvalidConstAsModifier' should be set to true.
8472     */
8473    function parseModifiers(
8474        permitInvalidConstAsModifier?: boolean,
8475        stopOnStartOfClassStaticBlock?: boolean,
8476        shouldAddReadonly?: boolean
8477    ): NodeArray<Modifier> | undefined {
8478        const pos = getNodePos();
8479        let list, modifier, hasSeenStatic = false;
8480        let hasReadonly = false;
8481        while (modifier = tryParseModifier(permitInvalidConstAsModifier, stopOnStartOfClassStaticBlock, hasSeenStatic)) {
8482            if (modifier.kind === SyntaxKind.StaticKeyword) hasSeenStatic = true;
8483            if (modifier.kind === SyntaxKind.ReadonlyKeyword) {
8484                hasReadonly = true;
8485            }
8486            list = append(list, modifier);
8487        }
8488        if (shouldAddReadonly && !hasReadonly) {
8489            const readonlyModifier = finishVirtualNode(factory.createToken(SyntaxKind.ReadonlyKeyword));
8490            list = append(list, readonlyModifier);
8491        }
8492        return list && createNodeArray(list, pos);
8493    }
8494
8495    function parseModifiersForArrowFunction(): NodeArray<Modifier> | undefined {
8496        let modifiers: NodeArray<Modifier> | undefined;
8497        if (token() === SyntaxKind.AsyncKeyword) {
8498            const pos = getNodePos();
8499            nextToken();
8500            const modifier = finishNode(factory.createToken(SyntaxKind.AsyncKeyword), pos);
8501            modifiers = createNodeArray<Modifier>([modifier], pos);
8502        }
8503        return modifiers;
8504    }
8505
8506    function parseClassElement(): ClassElement {
8507        const pos = getNodePos();
8508        if (token() === SyntaxKind.SemicolonToken) {
8509            nextToken();
8510            return finishNode(factory.createSemicolonClassElement(), pos);
8511        }
8512
8513        const hasJSDoc = hasPrecedingJSDocComment();
8514        const decorators = parseDecorators();
8515        /*
8516         *  shouldAddReadonly adds readonly modifier when the element in struct has the Param decorator
8517         *  and doesn't have Once decorator.
8518         */
8519        const shouldAddReadonly = inStructContext() && hasParamAndNoOnceDecorator(decorators);
8520        const modifiers = parseModifiers(/*permitInvalidConstAsModifier*/ true, /*stopOnStartOfClassStaticBlock*/ true, shouldAddReadonly);
8521        if (token() === SyntaxKind.StaticKeyword && lookAhead(nextTokenIsOpenBrace)) {
8522            return parseClassStaticBlockDeclaration(pos, hasJSDoc, decorators, modifiers);
8523        }
8524
8525        if (parseContextualModifier(SyntaxKind.GetKeyword)) {
8526            return parseAccessorDeclaration(pos, hasJSDoc, decorators, modifiers, SyntaxKind.GetAccessor, SignatureFlags.None);
8527        }
8528
8529        if (parseContextualModifier(SyntaxKind.SetKeyword)) {
8530            return parseAccessorDeclaration(pos, hasJSDoc, decorators, modifiers, SyntaxKind.SetAccessor, SignatureFlags.None);
8531        }
8532
8533        if (token() === SyntaxKind.ConstructorKeyword || token() === SyntaxKind.StringLiteral) {
8534            const constructorDeclaration = tryParseConstructorDeclaration(pos, hasJSDoc, decorators, modifiers);
8535            if (constructorDeclaration) {
8536                return constructorDeclaration;
8537            }
8538        }
8539
8540        if (isIndexSignature()) {
8541            return parseIndexSignatureDeclaration(pos, hasJSDoc, decorators, modifiers);
8542        }
8543
8544        // It is very important that we check this *after* checking indexers because
8545        // the [ token can start an index signature or a computed property name
8546        if (tokenIsIdentifierOrKeyword(token()) ||
8547            token() === SyntaxKind.StringLiteral ||
8548            token() === SyntaxKind.NumericLiteral ||
8549            token() === SyntaxKind.AsteriskToken ||
8550            token() === SyntaxKind.OpenBracketToken) {
8551            const isAmbient = some(modifiers, isDeclareModifier);
8552            if (isAmbient) {
8553                for (const m of modifiers!) {
8554                    (m as Mutable<Node>).flags |= NodeFlags.Ambient;
8555                }
8556                return doInsideOfContext(NodeFlags.Ambient, () => parsePropertyOrMethodDeclaration(pos, hasJSDoc, decorators, modifiers));
8557            }
8558            else {
8559                return parsePropertyOrMethodDeclaration(pos, hasJSDoc, decorators, modifiers);
8560            }
8561        }
8562
8563        if (decorators || modifiers) {
8564            // treat this as a property declaration with a missing name.
8565            const name = createMissingNode<Identifier>(SyntaxKind.Identifier, /*reportAtCurrentPosition*/ true, Diagnostics.Declaration_expected);
8566            return parsePropertyDeclaration(pos, hasJSDoc, decorators, modifiers, name, /*questionToken*/ undefined);
8567        }
8568
8569        // 'isClassMemberStart' should have hinted not to attempt parsing.
8570        return Debug.fail("Should not have attempted to parse class member declaration.");
8571    }
8572
8573    function parseAnnotationElement(): AnnotationElement {
8574        const pos = getNodePos();
8575        if (token() === SyntaxKind.SemicolonToken) {
8576            parseErrorAt(pos, pos, Diagnostics.Unexpected_keyword_or_identifier);
8577        }
8578
8579        const hasJSDoc = hasPrecedingJSDocComment();
8580        if (token() === SyntaxKind.StaticKeyword && lookAhead(nextTokenIsOpenBrace)) {
8581            return createMissingNode<AnnotationElement>(SyntaxKind.AnnotationPropertyDeclaration, /*reportAtCurrentPosition*/ true,
8582                Diagnostics.Unexpected_keyword_or_identifier);
8583        }
8584
8585        if (parseContextualModifier(SyntaxKind.GetKeyword)) {
8586            return createMissingNode<AnnotationElement>(SyntaxKind.AnnotationPropertyDeclaration, /*reportAtCurrentPosition*/ true,
8587                Diagnostics.Unexpected_keyword_or_identifier);
8588        }
8589
8590        if (parseContextualModifier(SyntaxKind.SetKeyword)) {
8591            return createMissingNode<AnnotationElement>(SyntaxKind.AnnotationPropertyDeclaration, /*reportAtCurrentPosition*/ true,
8592                Diagnostics.Unexpected_keyword_or_identifier);
8593        }
8594
8595        if (token() === SyntaxKind.ConstructorKeyword || token() === SyntaxKind.StringLiteral) {
8596            return createMissingNode<AnnotationElement>(SyntaxKind.AnnotationPropertyDeclaration, /*reportAtCurrentPosition*/ true,
8597                Diagnostics.Unexpected_keyword_or_identifier);
8598        }
8599
8600        if (isIndexSignature()) {
8601            return createMissingNode<AnnotationElement>(SyntaxKind.AnnotationPropertyDeclaration, /*reportAtCurrentPosition*/ true,
8602                Diagnostics.Unexpected_keyword_or_identifier);
8603        }
8604
8605        if (tokenIsIdentifierOrKeyword(token())) {
8606            const name = parsePropertyName();
8607            return parseAnnotationPropertyDeclaration(pos, hasJSDoc, name);
8608        }
8609
8610        // 'isAnnotationMemberStart' should have hinted not to attempt parsing.
8611        return Debug.fail("Should not have attempted to parse annotation member declaration.");
8612    }
8613
8614    function parseClassExpression(): ClassExpression {
8615        return parseClassDeclarationOrExpression(getNodePos(), hasPrecedingJSDocComment(), /*decorators*/ undefined, /*modifiers*/ undefined, SyntaxKind.ClassExpression) as ClassExpression;
8616    }
8617
8618    function parseClassDeclaration(pos: number, hasJSDoc: boolean, decorators: NodeArray<Decorator> | undefined, modifiers: NodeArray<Modifier> | undefined): ClassDeclaration {
8619        return parseClassDeclarationOrExpression(pos, hasJSDoc, decorators, modifiers, SyntaxKind.ClassDeclaration) as ClassDeclaration;
8620    }
8621
8622    function parseStructDeclaration(pos: number, hasJSDoc: boolean, decorators: NodeArray<Decorator> | undefined, modifiers: NodeArray<Modifier> | undefined): StructDeclaration {
8623        return parseStructDeclarationOrExpression(pos, hasJSDoc, decorators, modifiers);
8624    }
8625
8626    function parseClassDeclarationOrExpression(pos: number, hasJSDoc: boolean, decorators: NodeArray<Decorator> | undefined, modifiers: NodeArray<Modifier> | undefined, kind: ClassLikeDeclaration["kind"]): ClassLikeDeclaration {
8627        const savedAwaitContext = inAwaitContext();
8628        parseExpected(SyntaxKind.ClassKeyword);
8629
8630        // We don't parse the name here in await context, instead we will report a grammar error in the checker.
8631        const name = parseNameOfClassDeclarationOrExpression();
8632        const typeParameters = parseTypeParameters();
8633        if (some(modifiers, isExportModifier)) setAwaitContext(/*value*/ true);
8634        const heritageClauses = parseHeritageClauses();
8635
8636        let members;
8637        if (parseExpected(SyntaxKind.OpenBraceToken)) {
8638            // ClassTail[Yield,Await] : (Modified) See 14.5
8639            //      ClassHeritage[?Yield,?Await]opt { ClassBody[?Yield,?Await]opt }
8640            members = parseClassMembers();
8641            parseExpected(SyntaxKind.CloseBraceToken);
8642        }
8643        else {
8644            members = createMissingList<ClassElement>();
8645        }
8646        setAwaitContext(savedAwaitContext);
8647        const node = kind === SyntaxKind.ClassDeclaration
8648            ? factory.createClassDeclaration(combineDecoratorsAndModifiers(decorators, modifiers), name, typeParameters, heritageClauses, members)
8649            : factory.createClassExpression(combineDecoratorsAndModifiers(decorators, modifiers), name, typeParameters, heritageClauses, members);
8650        return withJSDoc(finishNode(node, pos), hasJSDoc);
8651    }
8652
8653    function parseStructDeclarationOrExpression(pos: number, hasJSDoc: boolean, decorators: NodeArray<Decorator> | undefined, modifiers: NodeArray<Modifier> | undefined): StructDeclaration {
8654        const savedAwaitContext = inAwaitContext();
8655        parseExpected(SyntaxKind.StructKeyword);
8656        setStructContext(true);
8657        // We don't parse the name here in await context, instead we will report a grammar error in the checker.
8658        // struct Identifier logic is same to class Identifier
8659        const name = parseNameOfClassDeclarationOrExpression();
8660        const typeParameters = parseTypeParameters();
8661        if (some(modifiers, isExportModifier)) setAwaitContext(/*value*/ true);
8662        let heritageClauses = parseHeritageClauses();
8663        const customComponent = sourceFileCompilerOptions.ets?.customComponent;
8664        if (!heritageClauses && customComponent) {
8665            heritageClauses = createVirtualHeritageClauses(customComponent);
8666        }
8667        let members;
8668        if (parseExpected(SyntaxKind.OpenBraceToken)) {
8669            // ClassTail[Yield,Await] : (Modified) See 14.5
8670            //      ClassHeritage[?Yield,?Await]opt { ClassBody[?Yield,?Await]opt }
8671            members = parseStructMembers(pos);
8672            parseExpected(SyntaxKind.CloseBraceToken);
8673        }
8674        else {
8675            members = createMissingList<ClassElement>();
8676        }
8677        setAwaitContext(savedAwaitContext);
8678        const node = factory.createStructDeclaration(combineDecoratorsAndModifiers(decorators, modifiers), name, typeParameters, heritageClauses, members);
8679        structStylesComponents.clear();
8680        setStructContext(false);
8681        return withJSDoc(finishNode(node, pos), hasJSDoc);
8682    }
8683
8684    function createVirtualHeritageClauses(customComponent: string): NodeArray<HeritageClause> {
8685        const curPos = getNodePos();
8686        const clause = factory.createHeritageClause(
8687            SyntaxKind.ExtendsKeyword,
8688            createNodeArray([finishNode(factory.createExpressionWithTypeArguments(
8689                finishNode(factory.createIdentifier(/*text*/ customComponent), curPos, /*end*/ undefined, /*virtual*/ true),
8690            /*typeArguments*/ undefined
8691            ), curPos)], curPos, /*end*/ undefined, /*hasTrailingComma*/ false)
8692        );
8693        return createNodeArray([finishNode(clause, curPos, /*end*/ undefined, /*virtual*/ true)], curPos, /*end*/ undefined, /*hasTrailingComma*/ false);
8694    }
8695
8696    function parseNameOfClassDeclarationOrExpression(): Identifier | undefined {
8697        // implements is a future reserved word so
8698        // 'class implements' might mean either
8699        // - class expression with omitted name, 'implements' starts heritage clause
8700        // - class with name 'implements'
8701        // 'isImplementsClause' helps to disambiguate between these two cases
8702        return isBindingIdentifier() && !isImplementsClause()
8703            ? createIdentifier(isBindingIdentifier())
8704            : undefined;
8705    }
8706
8707    function isImplementsClause() {
8708        return token() === SyntaxKind.ImplementsKeyword && lookAhead(nextTokenIsIdentifierOrKeyword);
8709    }
8710
8711    function parseHeritageClauses(): NodeArray<HeritageClause> | undefined {
8712        // ClassTail[Yield,Await] : (Modified) See 14.5
8713        //      ClassHeritage[?Yield,?Await]opt { ClassBody[?Yield,?Await]opt }
8714
8715        if (isHeritageClause()) {
8716            return parseList(ParsingContext.HeritageClauses, parseHeritageClause);
8717        }
8718
8719        return undefined;
8720    }
8721
8722    function parseHeritageClause(): HeritageClause {
8723        const pos = getNodePos();
8724        const tok = token();
8725        Debug.assert(tok === SyntaxKind.ExtendsKeyword || tok === SyntaxKind.ImplementsKeyword); // isListElement() should ensure this.
8726        nextToken();
8727        const types = parseDelimitedList(ParsingContext.HeritageClauseElement, parseExpressionWithTypeArguments);
8728        return finishNode(factory.createHeritageClause(tok, types), pos);
8729    }
8730
8731    function parseExpressionWithTypeArguments(): ExpressionWithTypeArguments {
8732        const pos = getNodePos();
8733        const expression = parseLeftHandSideExpressionOrHigher();
8734        if (expression.kind === SyntaxKind.ExpressionWithTypeArguments) {
8735            return expression as ExpressionWithTypeArguments;
8736        }
8737        const typeArguments = tryParseTypeArguments();
8738        return finishNode(factory.createExpressionWithTypeArguments(expression, typeArguments), pos);
8739    }
8740
8741    function tryParseTypeArguments(): NodeArray<TypeNode> | undefined {
8742        return token() === SyntaxKind.LessThanToken ?
8743            parseBracketedList(ParsingContext.TypeArguments, parseType, SyntaxKind.LessThanToken, SyntaxKind.GreaterThanToken) : undefined;
8744    }
8745
8746    function isHeritageClause(): boolean {
8747        return token() === SyntaxKind.ExtendsKeyword || token() === SyntaxKind.ImplementsKeyword;
8748    }
8749
8750    function parseClassMembers(): NodeArray<ClassElement> {
8751        return parseList(ParsingContext.ClassMembers, parseClassElement);
8752    }
8753
8754    function parseAnnotationMembers(): NodeArray<AnnotationElement> {
8755        return parseList(ParsingContext.AnnotationMembers, parseAnnotationElement);
8756    }
8757
8758    function parseStructMembers(pos: number): NodeArray<ClassElement> {
8759        const structMembers = parseList(ParsingContext.ClassMembers, parseClassElement);
8760
8761        const virtualStructMembers: ClassElement[] = [];
8762        // create constructor function argument object properties
8763        const virtualParameterProperties: TypeElement[] = [];
8764        structMembers.forEach(member => {
8765            virtualStructMembers.push(member);
8766            if (member.kind === SyntaxKind.PropertyDeclaration) {
8767                const property = <PropertyDeclaration>member;
8768                virtualParameterProperties.push(
8769                    finishVirtualNode(
8770                        factory.createPropertySignature(getModifiers(property), property.name, factory.createToken(SyntaxKind.QuestionToken), property.type)
8771                    )
8772                );
8773            }
8774        });
8775        const parameters: ParameterDeclaration[] = [];
8776        if (virtualParameterProperties.length) {
8777            const type = finishVirtualNode(factory.createTypeLiteralNode(createNodeArray(virtualParameterProperties, 0, 0)));
8778            parameters.push(
8779                finishVirtualNode(
8780                    factory.createParameterDeclaration(/*modifiers*/ undefined, /*dotDotDotToken*/ undefined,
8781                        finishVirtualNode(factory.createIdentifier("value")), factory.createToken(SyntaxKind.QuestionToken), type
8782                    )
8783                )
8784            );
8785        }
8786        // Add parameter ##storage?: LocalStorage to struct constructor.
8787        parameters.push(
8788            finishVirtualNode(
8789                factory.createParameterDeclaration(/*modifiers*/ undefined, /*dotDotDotToken*/ undefined,
8790                    finishVirtualNode(factory.createIdentifier("##storage")), factory.createToken(SyntaxKind.QuestionToken),
8791                    finishVirtualNode(factory.createTypeReferenceNode(finishVirtualNode(factory.createIdentifier("LocalStorage"))))
8792                )
8793            )
8794        );
8795        const emptyBody = finishVirtualNode(factory.createBlock(createNodeArray([], 0, 0)));
8796        const virtualConstructor = factory.createConstructorDeclaration(/*modifier*/ undefined, createNodeArray(parameters, 0, 0), emptyBody);
8797
8798        virtualStructMembers.unshift(finishVirtualNode(virtualConstructor, pos, pos));
8799
8800        return createNodeArray(virtualStructMembers, structMembers.pos);
8801    }
8802
8803    function finishVirtualNode<T extends Node>(node: T, start = 0, end = 0) {
8804        return finishNode(node, start, end, /*virtual*/ true);
8805    }
8806
8807    function parseInterfaceDeclaration(pos: number, hasJSDoc: boolean, decorators: NodeArray<Decorator> | undefined, modifiers: NodeArray<Modifier> | undefined): InterfaceDeclaration {
8808        parseExpected(SyntaxKind.InterfaceKeyword);
8809        const name = parseIdentifier();
8810        const typeParameters = parseTypeParameters();
8811        const heritageClauses = parseHeritageClauses();
8812        const members = parseObjectTypeMembers();
8813        const node = factory.createInterfaceDeclaration(modifiers, name, typeParameters, heritageClauses, members);
8814        (node as Mutable<InterfaceDeclaration>).illegalDecorators = decorators;
8815        return withJSDoc(finishNode(node, pos), hasJSDoc);
8816    }
8817
8818    function parseTypeAliasDeclaration(pos: number, hasJSDoc: boolean, decorators: NodeArray<Decorator> | undefined, modifiers: NodeArray<Modifier> | undefined): TypeAliasDeclaration {
8819        parseExpected(SyntaxKind.TypeKeyword);
8820        const name = parseIdentifier();
8821        const typeParameters = parseTypeParameters();
8822        parseExpected(SyntaxKind.EqualsToken);
8823        const type = token() === SyntaxKind.IntrinsicKeyword && tryParse(parseKeywordAndNoDot) || parseType();
8824        parseSemicolon();
8825        const node = factory.createTypeAliasDeclaration(modifiers, name, typeParameters, type);
8826        (node as Mutable<TypeAliasDeclaration>).illegalDecorators = decorators;
8827        return withJSDoc(finishNode(node, pos), hasJSDoc);
8828    }
8829
8830    // In an ambient declaration, the grammar only allows integer literals as initializers.
8831    // In a non-ambient declaration, the grammar allows uninitialized members only in a
8832    // ConstantEnumMemberSection, which starts at the beginning of an enum declaration
8833    // or any time an integer literal initializer is encountered.
8834    function parseEnumMember(): EnumMember {
8835        const pos = getNodePos();
8836        const hasJSDoc = hasPrecedingJSDocComment();
8837        const name = parsePropertyName();
8838        const initializer = allowInAnd(parseInitializer);
8839        return withJSDoc(finishNode(factory.createEnumMember(name, initializer), pos), hasJSDoc);
8840    }
8841
8842    function parseEnumDeclaration(pos: number, hasJSDoc: boolean, decorators: NodeArray<Decorator> | undefined, modifiers: NodeArray<Modifier> | undefined): EnumDeclaration {
8843        parseExpected(SyntaxKind.EnumKeyword);
8844        const name = parseIdentifier();
8845        let members;
8846        if (parseExpected(SyntaxKind.OpenBraceToken)) {
8847            members = doOutsideOfYieldAndAwaitContext(() => parseDelimitedList(ParsingContext.EnumMembers, parseEnumMember));
8848            parseExpected(SyntaxKind.CloseBraceToken);
8849        }
8850        else {
8851            members = createMissingList<EnumMember>();
8852        }
8853        const node = factory.createEnumDeclaration(modifiers, name, members);
8854        (node as Mutable<EnumDeclaration>).illegalDecorators = decorators;
8855        return withJSDoc(finishNode(node, pos), hasJSDoc);
8856    }
8857
8858    function parseModuleBlock(): ModuleBlock {
8859        const pos = getNodePos();
8860        let statements;
8861        if (parseExpected(SyntaxKind.OpenBraceToken)) {
8862            statements = parseList(ParsingContext.BlockStatements, parseStatement);
8863            parseExpected(SyntaxKind.CloseBraceToken);
8864        }
8865        else {
8866            statements = createMissingList<Statement>();
8867        }
8868        return finishNode(factory.createModuleBlock(statements), pos);
8869    }
8870
8871    function parseModuleOrNamespaceDeclaration(pos: number, hasJSDoc: boolean, decorators: NodeArray<Decorator> | undefined, modifiers: NodeArray<Modifier> | undefined, flags: NodeFlags): ModuleDeclaration {
8872        // If we are parsing a dotted namespace name, we want to
8873        // propagate the 'Namespace' flag across the names if set.
8874        const namespaceFlag = flags & NodeFlags.Namespace;
8875        const name = parseIdentifier();
8876        const body = parseOptional(SyntaxKind.DotToken)
8877            ? parseModuleOrNamespaceDeclaration(getNodePos(), /*hasJSDoc*/ false, /*decorators*/ undefined, /*modifiers*/ undefined, NodeFlags.NestedNamespace | namespaceFlag) as NamespaceDeclaration
8878            : parseModuleBlock();
8879        const node = factory.createModuleDeclaration(modifiers, name, body, flags);
8880        (node as Mutable<ModuleDeclaration>).illegalDecorators = decorators;
8881        return withJSDoc(finishNode(node, pos), hasJSDoc);
8882    }
8883
8884    function parseAmbientExternalModuleDeclaration(pos: number, hasJSDoc: boolean, decorators: NodeArray<Decorator> | undefined, modifiers: NodeArray<Modifier> | undefined): ModuleDeclaration {
8885        let flags: NodeFlags = 0;
8886        let name;
8887        if (token() === SyntaxKind.GlobalKeyword) {
8888            // parse 'global' as name of global scope augmentation
8889            name = parseIdentifier();
8890            flags |= NodeFlags.GlobalAugmentation;
8891        }
8892        else {
8893            name = parseLiteralNode() as StringLiteral;
8894            name.text = internIdentifier(name.text);
8895        }
8896        let body: ModuleBlock | undefined;
8897        if (token() === SyntaxKind.OpenBraceToken) {
8898            body = parseModuleBlock();
8899        }
8900        else {
8901            parseSemicolon();
8902        }
8903        const node = factory.createModuleDeclaration(modifiers, name, body, flags);
8904        (node as Mutable<ModuleDeclaration>).illegalDecorators = decorators;
8905        return withJSDoc(finishNode(node, pos), hasJSDoc);
8906    }
8907
8908    function parseModuleDeclaration(pos: number, hasJSDoc: boolean, decorators: NodeArray<Decorator> | undefined, modifiers: NodeArray<Modifier> | undefined): ModuleDeclaration {
8909        let flags: NodeFlags = 0;
8910        if (token() === SyntaxKind.GlobalKeyword) {
8911            // global augmentation
8912            return parseAmbientExternalModuleDeclaration(pos, hasJSDoc, decorators, modifiers);
8913        }
8914        else if (parseOptional(SyntaxKind.NamespaceKeyword)) {
8915            flags |= NodeFlags.Namespace;
8916        }
8917        else {
8918            parseExpected(SyntaxKind.ModuleKeyword);
8919            if (token() === SyntaxKind.StringLiteral) {
8920                return parseAmbientExternalModuleDeclaration(pos, hasJSDoc, decorators, modifiers);
8921            }
8922        }
8923        return parseModuleOrNamespaceDeclaration(pos, hasJSDoc, decorators, modifiers, flags);
8924    }
8925
8926    function isExternalModuleReference() {
8927        return token() === SyntaxKind.RequireKeyword &&
8928            lookAhead(nextTokenIsOpenParen);
8929    }
8930
8931    function nextTokenIsOpenParen() {
8932        return nextToken() === SyntaxKind.OpenParenToken;
8933    }
8934
8935    function nextTokenIsOpenBrace() {
8936        return nextToken() === SyntaxKind.OpenBraceToken;
8937    }
8938
8939    function nextTokenIsSlash() {
8940        return nextToken() === SyntaxKind.SlashToken;
8941    }
8942
8943    function parseNamespaceExportDeclaration(pos: number, hasJSDoc: boolean, decorators: NodeArray<Decorator> | undefined, modifiers: NodeArray<Modifier> | undefined): NamespaceExportDeclaration {
8944        parseExpected(SyntaxKind.AsKeyword);
8945        parseExpected(SyntaxKind.NamespaceKeyword);
8946        const name = parseIdentifier();
8947        parseSemicolon();
8948        const node = factory.createNamespaceExportDeclaration(name);
8949        // NamespaceExportDeclaration nodes cannot have decorators or modifiers, so we attach them here so we can report them in the grammar checker
8950        (node as Mutable<NamespaceExportDeclaration>).illegalDecorators = decorators;
8951        (node as Mutable<NamespaceExportDeclaration>).modifiers = modifiers;
8952        return withJSDoc(finishNode(node, pos), hasJSDoc);
8953    }
8954
8955    function parseImportDeclarationOrImportEqualsDeclaration(pos: number, hasJSDoc: boolean, decorators: NodeArray<Decorator> | undefined, modifiers: NodeArray<Modifier> | undefined): ImportEqualsDeclaration | ImportDeclaration {
8956        parseExpected(SyntaxKind.ImportKeyword);
8957
8958        const afterImportPos = scanner.getStartPos();
8959
8960        // We don't parse the identifier here in await context, instead we will report a grammar error in the checker.
8961        let identifier: Identifier | undefined;
8962        if (isIdentifier()) {
8963            identifier = parseIdentifier();
8964        }
8965
8966        let isTypeOnly = false;
8967        let isLazy = false;
8968        if (token() !== SyntaxKind.FromKeyword &&
8969            identifier?.escapedText === "type" &&
8970            (isIdentifier() || tokenAfterImportDefinitelyProducesImportDeclaration())
8971        ) {
8972            isTypeOnly = true;
8973            identifier = isIdentifier() ? parseIdentifier() : undefined;
8974        }
8975        else if (isSetLazy(identifier)) {
8976            isLazy = true;
8977            identifier = isIdentifier() ? parseIdentifier() : undefined;
8978        }
8979
8980        if (identifier && !tokenAfterImportedIdentifierDefinitelyProducesImportDeclaration()) {
8981            return parseImportEqualsDeclaration(pos, hasJSDoc, decorators, modifiers, identifier, isTypeOnly);
8982        }
8983
8984        // ImportDeclaration:
8985        //  import ImportClause from ModuleSpecifier;
8986        //  import ModuleSpecifier;
8987        let importClause: ImportClause | undefined;
8988        if (identifier || // import id
8989            token() === SyntaxKind.AsteriskToken || // import *
8990            token() === SyntaxKind.OpenBraceToken    // import {
8991        ) {
8992            importClause = parseImportClause(identifier, afterImportPos, isTypeOnly);
8993            (importClause as Mutable<ImportClause>).isLazy = isLazy;
8994            parseExpected(SyntaxKind.FromKeyword);
8995        }
8996        const moduleSpecifier = parseModuleSpecifier();
8997
8998        let assertClause: AssertClause | undefined;
8999        if (token() === SyntaxKind.AssertKeyword && !scanner.hasPrecedingLineBreak()) {
9000            assertClause = parseAssertClause();
9001        }
9002
9003        parseSemicolon();
9004        const node = factory.createImportDeclaration(modifiers, importClause, moduleSpecifier, assertClause);
9005        (node as Mutable<ImportDeclaration>).illegalDecorators = decorators;
9006        return withJSDoc(finishNode(node, pos), hasJSDoc);
9007    }
9008
9009    function isSetLazy(identifier: Identifier | undefined): boolean {
9010        // 1. import lazy { export } from "mod";
9011        // 2. import lazy defaultExport from "mod";
9012        // 3. import lazy defaultExport, { export, /* ... */ } from "mod";
9013        return identifier?.escapedText === 'lazy' &&
9014            (token() === SyntaxKind.OpenBraceToken ||
9015            (isIdentifier() && lookAhead(() => nextToken() === SyntaxKind.FromKeyword)) ||
9016            (isIdentifier() && lookAhead(() => nextToken() === SyntaxKind.CommaToken && nextToken() === SyntaxKind.OpenBraceToken)));
9017    }
9018
9019    function parseAssertEntry() {
9020        const pos = getNodePos();
9021        const name = tokenIsIdentifierOrKeyword(token()) ? parseIdentifierName() : parseLiteralLikeNode(SyntaxKind.StringLiteral) as StringLiteral;
9022        parseExpected(SyntaxKind.ColonToken);
9023        const value = parseAssignmentExpressionOrHigher(/*allowReturnTypeInArrowFunction*/ true);
9024        return finishNode(factory.createAssertEntry(name, value), pos);
9025    }
9026
9027    function parseAssertClause(skipAssertKeyword?: true) {
9028        const pos = getNodePos();
9029        if (!skipAssertKeyword) {
9030            parseExpected(SyntaxKind.AssertKeyword);
9031        }
9032        const openBracePosition = scanner.getTokenPos();
9033        if (parseExpected(SyntaxKind.OpenBraceToken)) {
9034            const multiLine = scanner.hasPrecedingLineBreak();
9035            const elements = parseDelimitedList(ParsingContext.AssertEntries, parseAssertEntry, /*considerSemicolonAsDelimiter*/ true);
9036            if (!parseExpected(SyntaxKind.CloseBraceToken)) {
9037                const lastError = lastOrUndefined(parseDiagnostics);
9038                if (lastError && lastError.code === Diagnostics._0_expected.code) {
9039                    addRelatedInfo(
9040                        lastError,
9041                        createDetachedDiagnostic(fileName, openBracePosition, 1, Diagnostics.The_parser_expected_to_find_a_1_to_match_the_0_token_here, "{", "}")
9042                    );
9043                }
9044            }
9045            return finishNode(factory.createAssertClause(elements, multiLine), pos);
9046        }
9047        else {
9048            const elements = createNodeArray([], getNodePos(), /*end*/ undefined, /*hasTrailingComma*/ false);
9049            return finishNode(factory.createAssertClause(elements, /*multiLine*/ false), pos);
9050        }
9051    }
9052
9053    function tokenAfterImportDefinitelyProducesImportDeclaration() {
9054        return token() === SyntaxKind.AsteriskToken || token() === SyntaxKind.OpenBraceToken;
9055    }
9056
9057    function tokenAfterImportedIdentifierDefinitelyProducesImportDeclaration() {
9058        // In `import id ___`, the current token decides whether to produce
9059        // an ImportDeclaration or ImportEqualsDeclaration.
9060        return token() === SyntaxKind.CommaToken || token() === SyntaxKind.FromKeyword;
9061    }
9062
9063    function parseImportEqualsDeclaration(pos: number, hasJSDoc: boolean, decorators: NodeArray<Decorator> | undefined, modifiers: NodeArray<Modifier> | undefined, identifier: Identifier, isTypeOnly: boolean): ImportEqualsDeclaration {
9064        parseExpected(SyntaxKind.EqualsToken);
9065        const moduleReference = parseModuleReference();
9066        parseSemicolon();
9067        const node = factory.createImportEqualsDeclaration(modifiers, isTypeOnly, identifier, moduleReference);
9068        (node as Mutable<ImportEqualsDeclaration>).illegalDecorators = decorators;
9069        const finished = withJSDoc(finishNode(node, pos), hasJSDoc);
9070        return finished;
9071    }
9072
9073    function parseImportClause(identifier: Identifier | undefined, pos: number, isTypeOnly: boolean) {
9074        // ImportClause:
9075        //  ImportedDefaultBinding
9076        //  NameSpaceImport
9077        //  NamedImports
9078        //  ImportedDefaultBinding, NameSpaceImport
9079        //  ImportedDefaultBinding, NamedImports
9080
9081        // If there was no default import or if there is comma token after default import
9082        // parse namespace or named imports
9083        let namedBindings: NamespaceImport | NamedImports | undefined;
9084        if (!identifier ||
9085            parseOptional(SyntaxKind.CommaToken)) {
9086            namedBindings = token() === SyntaxKind.AsteriskToken ? parseNamespaceImport() : parseNamedImportsOrExports(SyntaxKind.NamedImports);
9087        }
9088
9089        return finishNode(factory.createImportClause(isTypeOnly, identifier, namedBindings), pos);
9090    }
9091
9092    function parseModuleReference() {
9093        return isExternalModuleReference()
9094            ? parseExternalModuleReference()
9095            : parseEntityName(/*allowReservedWords*/ false);
9096    }
9097
9098    function parseExternalModuleReference() {
9099        const pos = getNodePos();
9100        parseExpected(SyntaxKind.RequireKeyword);
9101        parseExpected(SyntaxKind.OpenParenToken);
9102        const expression = parseModuleSpecifier();
9103        parseExpected(SyntaxKind.CloseParenToken);
9104        return finishNode(factory.createExternalModuleReference(expression), pos);
9105    }
9106
9107    function parseModuleSpecifier(): Expression {
9108        if (token() === SyntaxKind.StringLiteral) {
9109            const result = parseLiteralNode();
9110            result.text = internIdentifier(result.text);
9111            return result;
9112        }
9113        else {
9114            // We allow arbitrary expressions here, even though the grammar only allows string
9115            // literals.  We check to ensure that it is only a string literal later in the grammar
9116            // check pass.
9117            return parseExpression();
9118        }
9119    }
9120
9121    function parseNamespaceImport(): NamespaceImport {
9122        // NameSpaceImport:
9123        //  * as ImportedBinding
9124        const pos = getNodePos();
9125        parseExpected(SyntaxKind.AsteriskToken);
9126        parseExpected(SyntaxKind.AsKeyword);
9127        const name = parseIdentifier();
9128        return finishNode(factory.createNamespaceImport(name), pos);
9129    }
9130
9131    function parseNamedImportsOrExports(kind: SyntaxKind.NamedImports): NamedImports;
9132    function parseNamedImportsOrExports(kind: SyntaxKind.NamedExports): NamedExports;
9133    function parseNamedImportsOrExports(kind: SyntaxKind): NamedImportsOrExports {
9134        const pos = getNodePos();
9135
9136        // NamedImports:
9137        //  { }
9138        //  { ImportsList }
9139        //  { ImportsList, }
9140
9141        // ImportsList:
9142        //  ImportSpecifier
9143        //  ImportsList, ImportSpecifier
9144        const node = kind === SyntaxKind.NamedImports
9145            ? factory.createNamedImports(parseBracketedList(ParsingContext.ImportOrExportSpecifiers, parseImportSpecifier, SyntaxKind.OpenBraceToken, SyntaxKind.CloseBraceToken))
9146            : factory.createNamedExports(parseBracketedList(ParsingContext.ImportOrExportSpecifiers, parseExportSpecifier, SyntaxKind.OpenBraceToken, SyntaxKind.CloseBraceToken));
9147        return finishNode(node, pos);
9148    }
9149
9150    function parseExportSpecifier() {
9151        const hasJSDoc = hasPrecedingJSDocComment();
9152        return withJSDoc(parseImportOrExportSpecifier(SyntaxKind.ExportSpecifier) as ExportSpecifier, hasJSDoc);
9153    }
9154
9155    function parseImportSpecifier() {
9156        return parseImportOrExportSpecifier(SyntaxKind.ImportSpecifier) as ImportSpecifier;
9157    }
9158
9159    function parseImportOrExportSpecifier(kind: SyntaxKind): ImportOrExportSpecifier {
9160        const pos = getNodePos();
9161        // ImportSpecifier:
9162        //   BindingIdentifier
9163        //   IdentifierName as BindingIdentifier
9164        // ExportSpecifier:
9165        //   IdentifierName
9166        //   IdentifierName as IdentifierName
9167        let checkIdentifierIsKeyword = isKeyword(token()) && !isIdentifier();
9168        let checkIdentifierStart = scanner.getTokenPos();
9169        let checkIdentifierEnd = scanner.getTextPos();
9170        let isTypeOnly = false;
9171        let propertyName: Identifier | undefined;
9172        let canParseAsKeyword = true;
9173        let name = parseIdentifierName();
9174        if (name.escapedText === "type") {
9175            // If the first token of an import specifier is 'type', there are a lot of possibilities,
9176            // especially if we see 'as' afterwards:
9177            //
9178            // import { type } from "mod";          - isTypeOnly: false,   name: type
9179            // import { type as } from "mod";       - isTypeOnly: true,    name: as
9180            // import { type as as } from "mod";    - isTypeOnly: false,   name: as,    propertyName: type
9181            // import { type as as as } from "mod"; - isTypeOnly: true,    name: as,    propertyName: as
9182            if (token() === SyntaxKind.AsKeyword) {
9183                // { type as ...? }
9184                const firstAs = parseIdentifierName();
9185                if (token() === SyntaxKind.AsKeyword) {
9186                    // { type as as ...? }
9187                    const secondAs = parseIdentifierName();
9188                    if (tokenIsIdentifierOrKeyword(token())) {
9189                        // { type as as something }
9190                        isTypeOnly = true;
9191                        propertyName = firstAs;
9192                        name = parseNameWithKeywordCheck();
9193                        canParseAsKeyword = false;
9194                    }
9195                    else {
9196                        // { type as as }
9197                        propertyName = name;
9198                        name = secondAs;
9199                        canParseAsKeyword = false;
9200                    }
9201                }
9202                else if (tokenIsIdentifierOrKeyword(token())) {
9203                    // { type as something }
9204                    propertyName = name;
9205                    canParseAsKeyword = false;
9206                    name = parseNameWithKeywordCheck();
9207                }
9208                else {
9209                    // { type as }
9210                    isTypeOnly = true;
9211                    name = firstAs;
9212                }
9213            }
9214            else if (tokenIsIdentifierOrKeyword(token())) {
9215                // { type something ...? }
9216                isTypeOnly = true;
9217                name = parseNameWithKeywordCheck();
9218            }
9219        }
9220
9221        if (canParseAsKeyword && token() === SyntaxKind.AsKeyword) {
9222            propertyName = name;
9223            parseExpected(SyntaxKind.AsKeyword);
9224            name = parseNameWithKeywordCheck();
9225        }
9226        if (kind === SyntaxKind.ImportSpecifier && checkIdentifierIsKeyword) {
9227            parseErrorAt(checkIdentifierStart, checkIdentifierEnd, Diagnostics.Identifier_expected);
9228        }
9229        const node = kind === SyntaxKind.ImportSpecifier
9230            ? factory.createImportSpecifier(isTypeOnly, propertyName, name)
9231            : factory.createExportSpecifier(isTypeOnly, propertyName, name);
9232        return finishNode(node, pos);
9233
9234        function parseNameWithKeywordCheck() {
9235            checkIdentifierIsKeyword = isKeyword(token()) && !isIdentifier();
9236            checkIdentifierStart = scanner.getTokenPos();
9237            checkIdentifierEnd = scanner.getTextPos();
9238            return parseIdentifierName();
9239        }
9240    }
9241
9242    function parseNamespaceExport(pos: number): NamespaceExport {
9243        return finishNode(factory.createNamespaceExport(parseIdentifierName()), pos);
9244    }
9245
9246    function parseExportDeclaration(pos: number, hasJSDoc: boolean, decorators: NodeArray<Decorator> | undefined, modifiers: NodeArray<Modifier> | undefined): ExportDeclaration {
9247        const savedAwaitContext = inAwaitContext();
9248        setAwaitContext(/*value*/ true);
9249        let exportClause: NamedExportBindings | undefined;
9250        let moduleSpecifier: Expression | undefined;
9251        let assertClause: AssertClause | undefined;
9252        const isTypeOnly = parseOptional(SyntaxKind.TypeKeyword);
9253        const namespaceExportPos = getNodePos();
9254        if (parseOptional(SyntaxKind.AsteriskToken)) {
9255            if (parseOptional(SyntaxKind.AsKeyword)) {
9256                exportClause = parseNamespaceExport(namespaceExportPos);
9257            }
9258            parseExpected(SyntaxKind.FromKeyword);
9259            moduleSpecifier = parseModuleSpecifier();
9260        }
9261        else {
9262            exportClause = parseNamedImportsOrExports(SyntaxKind.NamedExports);
9263            // It is not uncommon to accidentally omit the 'from' keyword. Additionally, in editing scenarios,
9264            // the 'from' keyword can be parsed as a named export when the export clause is unterminated (i.e. `export { from "moduleName";`)
9265            // If we don't have a 'from' keyword, see if we have a string literal such that ASI won't take effect.
9266            if (token() === SyntaxKind.FromKeyword || (token() === SyntaxKind.StringLiteral && !scanner.hasPrecedingLineBreak())) {
9267                parseExpected(SyntaxKind.FromKeyword);
9268                moduleSpecifier = parseModuleSpecifier();
9269            }
9270        }
9271        if (moduleSpecifier && token() === SyntaxKind.AssertKeyword && !scanner.hasPrecedingLineBreak()) {
9272            assertClause = parseAssertClause();
9273        }
9274        parseSemicolon();
9275        setAwaitContext(savedAwaitContext);
9276        const node = factory.createExportDeclaration(modifiers, isTypeOnly, exportClause, moduleSpecifier, assertClause);
9277        (node as Mutable<ExportDeclaration>).illegalDecorators = decorators;
9278        return withJSDoc(finishNode(node, pos), hasJSDoc);
9279    }
9280
9281    function parseExportAssignment(pos: number, hasJSDoc: boolean, decorators: NodeArray<Decorator> | undefined, modifiers: NodeArray<Modifier> | undefined): ExportAssignment {
9282        const savedAwaitContext = inAwaitContext();
9283        setAwaitContext(/*value*/ true);
9284        let isExportEquals: boolean | undefined;
9285        if (parseOptional(SyntaxKind.EqualsToken)) {
9286            isExportEquals = true;
9287        }
9288        else {
9289            parseExpected(SyntaxKind.DefaultKeyword);
9290        }
9291        const expression = parseAssignmentExpressionOrHigher(/*allowReturnTypeInArrowFunction*/ true);
9292        parseSemicolon();
9293        setAwaitContext(savedAwaitContext);
9294        const node = factory.createExportAssignment(modifiers, isExportEquals, expression);
9295        (node as Mutable<ExportAssignment>).illegalDecorators = decorators;
9296        return withJSDoc(finishNode(node, pos), hasJSDoc);
9297    }
9298
9299    const enum ParsingContext {
9300        SourceElements,            // Elements in source file
9301        BlockStatements,           // Statements in block
9302        SwitchClauses,             // Clauses in switch statement
9303        SwitchClauseStatements,    // Statements in switch clause
9304        TypeMembers,               // Members in interface or type literal
9305        ClassMembers,              // Members in class declaration
9306        AnnotationMembers,         // Members in annotation declaration
9307        EnumMembers,               // Members in enum declaration
9308        HeritageClauseElement,     // Elements in a heritage clause
9309        VariableDeclarations,      // Variable declarations in variable statement
9310        ObjectBindingElements,     // Binding elements in object binding list
9311        ArrayBindingElements,      // Binding elements in array binding list
9312        ArgumentExpressions,       // Expressions in argument list
9313        ObjectLiteralMembers,      // Members in object literal
9314        JsxAttributes,             // Attributes in jsx element
9315        JsxChildren,               // Things between opening and closing JSX tags
9316        ArrayLiteralMembers,       // Members in array literal
9317        Parameters,                // Parameters in parameter list
9318        JSDocParameters,           // JSDoc parameters in parameter list of JSDoc function type
9319        RestProperties,            // Property names in a rest type list
9320        TypeParameters,            // Type parameters in type parameter list
9321        TypeArguments,             // Type arguments in type argument list
9322        TupleElementTypes,         // Element types in tuple element type list
9323        HeritageClauses,           // Heritage clauses for a class or interface declaration.
9324        ImportOrExportSpecifiers,  // Named import clause's import specifier list,
9325        AssertEntries,             // Import entries list.
9326        Count                      // Number of parsing contexts
9327    }
9328
9329    const enum Tristate {
9330        False,
9331        True,
9332        Unknown
9333    }
9334
9335    export namespace JSDocParser {
9336        export function parseJSDocTypeExpressionForTests(content: string, start: number | undefined, length: number | undefined): { jsDocTypeExpression: JSDocTypeExpression, diagnostics: Diagnostic[] } | undefined {
9337            initializeState("file.js", content, ScriptTarget.Latest, /*_syntaxCursor:*/ undefined, ScriptKind.JS);
9338            scanner.setText(content, start, length);
9339            currentToken = scanner.scan();
9340            const jsDocTypeExpression = parseJSDocTypeExpression();
9341
9342            const sourceFile = createSourceFile("file.js", ScriptTarget.Latest, ScriptKind.JS, /*isDeclarationFile*/ false, [], factory.createToken(SyntaxKind.EndOfFileToken), NodeFlags.None, noop);
9343            const diagnostics = attachFileToDiagnostics(parseDiagnostics, sourceFile);
9344            if (jsDocDiagnostics) {
9345                sourceFile.jsDocDiagnostics = attachFileToDiagnostics(jsDocDiagnostics, sourceFile);
9346            }
9347
9348            clearState();
9349
9350            return jsDocTypeExpression ? { jsDocTypeExpression, diagnostics } : undefined;
9351        }
9352
9353        // Parses out a JSDoc type expression.
9354        export function parseJSDocTypeExpression(mayOmitBraces?: boolean): JSDocTypeExpression {
9355            const pos = getNodePos();
9356            const hasBrace = (mayOmitBraces ? parseOptional : parseExpected)(SyntaxKind.OpenBraceToken);
9357            const type = doInsideOfContext(NodeFlags.JSDoc, parseJSDocType);
9358            if (!mayOmitBraces || hasBrace) {
9359                parseExpectedJSDoc(SyntaxKind.CloseBraceToken);
9360            }
9361
9362            const result = factory.createJSDocTypeExpression(type);
9363            fixupParentReferences(result);
9364            return finishNode(result, pos);
9365        }
9366
9367        export function parseJSDocNameReference(): JSDocNameReference {
9368            const pos = getNodePos();
9369            const hasBrace = parseOptional(SyntaxKind.OpenBraceToken);
9370            const p2 = getNodePos();
9371            let entityName: EntityName | JSDocMemberName = parseEntityName(/* allowReservedWords*/ false);
9372            while (token() === SyntaxKind.PrivateIdentifier) {
9373                reScanHashToken(); // rescan #id as # id
9374                nextTokenJSDoc(); // then skip the #
9375                entityName = finishNode(factory.createJSDocMemberName(entityName, parseIdentifier()), p2);
9376            }
9377            if (hasBrace) {
9378                parseExpectedJSDoc(SyntaxKind.CloseBraceToken);
9379            }
9380
9381            const result = factory.createJSDocNameReference(entityName);
9382            fixupParentReferences(result);
9383            return finishNode(result, pos);
9384        }
9385
9386        export function parseIsolatedJSDocComment(content: string, start: number | undefined, length: number | undefined): { jsDoc: JSDoc, diagnostics: Diagnostic[] } | undefined {
9387            initializeState("", content, ScriptTarget.Latest, /*_syntaxCursor:*/ undefined, ScriptKind.JS);
9388            const jsDoc = doInsideOfContext(NodeFlags.JSDoc, () => parseJSDocCommentWorker(start, length));
9389
9390            const sourceFile = { languageVariant: LanguageVariant.Standard, text: content } as SourceFile;
9391            const diagnostics = attachFileToDiagnostics(parseDiagnostics, sourceFile);
9392            clearState();
9393
9394            return jsDoc ? { jsDoc, diagnostics } : undefined;
9395        }
9396
9397        export function parseJSDocComment(parent: HasJSDoc, start: number, length: number): JSDoc | undefined {
9398            const saveToken = currentToken;
9399            const saveParseDiagnosticsLength = parseDiagnostics.length;
9400            const saveParseErrorBeforeNextFinishedNode = parseErrorBeforeNextFinishedNode;
9401
9402            const comment = doInsideOfContext(NodeFlags.JSDoc, () => parseJSDocCommentWorker(start, length));
9403            setParent(comment, parent);
9404
9405            if (contextFlags & NodeFlags.JavaScriptFile) {
9406                if (!jsDocDiagnostics) {
9407                    jsDocDiagnostics = [];
9408                }
9409                jsDocDiagnostics.push(...parseDiagnostics);
9410            }
9411            currentToken = saveToken;
9412            parseDiagnostics.length = saveParseDiagnosticsLength;
9413            parseErrorBeforeNextFinishedNode = saveParseErrorBeforeNextFinishedNode;
9414            return comment;
9415        }
9416
9417        const enum JSDocState {
9418            BeginningOfLine,
9419            SawAsterisk,
9420            SavingComments,
9421            SavingBackticks, // NOTE: Only used when parsing tag comments
9422        }
9423
9424        const enum PropertyLikeParse {
9425            Property = 1 << 0,
9426            Parameter = 1 << 1,
9427            CallbackParameter = 1 << 2,
9428        }
9429
9430        function parseJSDocCommentWorker(start = 0, length: number | undefined): JSDoc | undefined {
9431            const content = sourceText;
9432            const end = length === undefined ? content.length : start + length;
9433            length = end - start;
9434
9435            Debug.assert(start >= 0);
9436            Debug.assert(start <= end);
9437            Debug.assert(end <= content.length);
9438
9439            // Check for /** (JSDoc opening part)
9440            if (!isJSDocLikeText(content, start)) {
9441                return undefined;
9442            }
9443
9444            let tags: JSDocTag[];
9445            let tagsPos: number;
9446            let tagsEnd: number;
9447            let linkEnd: number;
9448            let commentsPos: number | undefined;
9449            let comments: string[] = [];
9450            const parts: JSDocComment[] = [];
9451
9452            // + 3 for leading /**, - 5 in total for /** */
9453            return scanner.scanRange(start + 3, length - 5, () => {
9454                // Initially we can parse out a tag.  We also have seen a starting asterisk.
9455                // This is so that /** * @type */ doesn't parse.
9456                let state = JSDocState.SawAsterisk;
9457                let margin: number | undefined;
9458                // + 4 for leading '/** '
9459                // + 1 because the last index of \n is always one index before the first character in the line and coincidentally, if there is no \n before start, it is -1, which is also one index before the first character
9460                let indent = start - (content.lastIndexOf("\n", start) + 1) + 4;
9461                function pushComment(text: string) {
9462                    if (!margin) {
9463                        margin = indent;
9464                    }
9465                    comments.push(text);
9466                    indent += text.length;
9467                }
9468
9469                nextTokenJSDoc();
9470                while (parseOptionalJsdoc(SyntaxKind.WhitespaceTrivia));
9471                if (parseOptionalJsdoc(SyntaxKind.NewLineTrivia)) {
9472                    state = JSDocState.BeginningOfLine;
9473                    indent = 0;
9474                }
9475                loop: while (true) {
9476                    switch (token()) {
9477                        case SyntaxKind.AtToken:
9478                            if (state === JSDocState.BeginningOfLine || state === JSDocState.SawAsterisk) {
9479                                removeTrailingWhitespace(comments);
9480                                if (!commentsPos) commentsPos = getNodePos();
9481                                addTag(parseTag(indent));
9482                                // NOTE: According to usejsdoc.org, a tag goes to end of line, except the last tag.
9483                                // Real-world comments may break this rule, so "BeginningOfLine" will not be a real line beginning
9484                                // for malformed examples like `/** @param {string} x @returns {number} the length */`
9485                                state = JSDocState.BeginningOfLine;
9486                                margin = undefined;
9487                            }
9488                            else {
9489                                pushComment(scanner.getTokenText());
9490                            }
9491                            break;
9492                        case SyntaxKind.NewLineTrivia:
9493                            comments.push(scanner.getTokenText());
9494                            state = JSDocState.BeginningOfLine;
9495                            indent = 0;
9496                            break;
9497                        case SyntaxKind.AsteriskToken:
9498                            const asterisk = scanner.getTokenText();
9499                            if (state === JSDocState.SawAsterisk || state === JSDocState.SavingComments) {
9500                                // If we've already seen an asterisk, then we can no longer parse a tag on this line
9501                                state = JSDocState.SavingComments;
9502                                pushComment(asterisk);
9503                            }
9504                            else {
9505                                // Ignore the first asterisk on a line
9506                                state = JSDocState.SawAsterisk;
9507                                indent += asterisk.length;
9508                            }
9509                            break;
9510                        case SyntaxKind.WhitespaceTrivia:
9511                            // only collect whitespace if we're already saving comments or have just crossed the comment indent margin
9512                            const whitespace = scanner.getTokenText();
9513                            if (state === JSDocState.SavingComments) {
9514                                comments.push(whitespace);
9515                            }
9516                            else if (margin !== undefined && indent + whitespace.length > margin) {
9517                                comments.push(whitespace.slice(margin - indent));
9518                            }
9519                            indent += whitespace.length;
9520                            break;
9521                        case SyntaxKind.EndOfFileToken:
9522                            break loop;
9523                        case SyntaxKind.OpenBraceToken:
9524                            state = JSDocState.SavingComments;
9525                            const commentEnd = scanner.getStartPos();
9526                            const linkStart = scanner.getTextPos() - 1;
9527                            const link = parseJSDocLink(linkStart);
9528                            if (link) {
9529                                if (!linkEnd) {
9530                                    removeLeadingNewlines(comments);
9531                                }
9532                                parts.push(finishNode(factory.createJSDocText(comments.join("")), linkEnd ?? start, commentEnd));
9533                                parts.push(link);
9534                                comments = [];
9535                                linkEnd = scanner.getTextPos();
9536                                break;
9537                            }
9538                            // fallthrough if it's not a {@link sequence
9539                        default:
9540                            // Anything else is doc comment text. We just save it. Because it
9541                            // wasn't a tag, we can no longer parse a tag on this line until we hit the next
9542                            // line break.
9543                            state = JSDocState.SavingComments;
9544                            pushComment(scanner.getTokenText());
9545                            break;
9546                    }
9547                    nextTokenJSDoc();
9548                }
9549                removeTrailingWhitespace(comments);
9550                if (parts.length && comments.length) {
9551                    parts.push(finishNode(factory.createJSDocText(comments.join("")), linkEnd ?? start, commentsPos));
9552                }
9553                if (parts.length && tags) Debug.assertIsDefined(commentsPos, "having parsed tags implies that the end of the comment span should be set");
9554                const tagsArray = tags && createNodeArray(tags, tagsPos, tagsEnd);
9555                return finishNode(factory.createJSDocComment(parts.length ? createNodeArray(parts, start, commentsPos) : comments.length ? comments.join("") : undefined, tagsArray), start, end);
9556            });
9557
9558            function removeLeadingNewlines(comments: string[]) {
9559                while (comments.length && (comments[0] === "\n" || comments[0] === "\r")) {
9560                    comments.shift();
9561                }
9562            }
9563
9564            function removeTrailingWhitespace(comments: string[]) {
9565                while (comments.length && comments[comments.length - 1].trim() === "") {
9566                    comments.pop();
9567                }
9568            }
9569
9570            function isNextNonwhitespaceTokenEndOfFile(): boolean {
9571                // We must use infinite lookahead, as there could be any number of newlines :(
9572                while (true) {
9573                    nextTokenJSDoc();
9574                    if (token() === SyntaxKind.EndOfFileToken) {
9575                        return true;
9576                    }
9577                    if (!(token() === SyntaxKind.WhitespaceTrivia || token() === SyntaxKind.NewLineTrivia)) {
9578                        return false;
9579                    }
9580                }
9581            }
9582
9583            function skipWhitespace(): void {
9584                if (token() === SyntaxKind.WhitespaceTrivia || token() === SyntaxKind.NewLineTrivia) {
9585                    if (lookAhead(isNextNonwhitespaceTokenEndOfFile)) {
9586                        return; // Don't skip whitespace prior to EoF (or end of comment) - that shouldn't be included in any node's range
9587                    }
9588                }
9589                while (token() === SyntaxKind.WhitespaceTrivia || token() === SyntaxKind.NewLineTrivia) {
9590                    nextTokenJSDoc();
9591                }
9592            }
9593
9594            function skipWhitespaceOrAsterisk(): string {
9595                if (token() === SyntaxKind.WhitespaceTrivia || token() === SyntaxKind.NewLineTrivia) {
9596                    if (lookAhead(isNextNonwhitespaceTokenEndOfFile)) {
9597                        return ""; // Don't skip whitespace prior to EoF (or end of comment) - that shouldn't be included in any node's range
9598                    }
9599                }
9600
9601                let precedingLineBreak = scanner.hasPrecedingLineBreak();
9602                let seenLineBreak = false;
9603                let indentText = "";
9604                while ((precedingLineBreak && token() === SyntaxKind.AsteriskToken) || token() === SyntaxKind.WhitespaceTrivia || token() === SyntaxKind.NewLineTrivia) {
9605                    indentText += scanner.getTokenText();
9606                    if (token() === SyntaxKind.NewLineTrivia) {
9607                        precedingLineBreak = true;
9608                        seenLineBreak = true;
9609                        indentText = "";
9610                    }
9611                    else if (token() === SyntaxKind.AsteriskToken) {
9612                        precedingLineBreak = false;
9613                    }
9614                    nextTokenJSDoc();
9615                }
9616                return seenLineBreak ? indentText : "";
9617            }
9618
9619            function parseTag(margin: number) {
9620                Debug.assert(token() === SyntaxKind.AtToken);
9621                const start = scanner.getTokenPos();
9622                nextTokenJSDoc();
9623
9624                const tagName = parseJSDocIdentifierName(/*message*/ undefined);
9625                const indentText = skipWhitespaceOrAsterisk();
9626
9627                let tag: JSDocTag | undefined;
9628                switch (tagName.escapedText) {
9629                    case "author":
9630                        tag = parseAuthorTag(start, tagName, margin, indentText);
9631                        break;
9632                    case "implements":
9633                        tag = parseImplementsTag(start, tagName, margin, indentText);
9634                        break;
9635                    case "augments":
9636                    case "extends":
9637                        tag = parseAugmentsTag(start, tagName, margin, indentText);
9638                        break;
9639                    case "class":
9640                    case "constructor":
9641                        tag = parseSimpleTag(start, factory.createJSDocClassTag, tagName, margin, indentText);
9642                        break;
9643                    case "public":
9644                        tag = parseSimpleTag(start, factory.createJSDocPublicTag, tagName, margin, indentText);
9645                        break;
9646                    case "private":
9647                        tag = parseSimpleTag(start, factory.createJSDocPrivateTag, tagName, margin, indentText);
9648                        break;
9649                    case "protected":
9650                        tag = parseSimpleTag(start, factory.createJSDocProtectedTag, tagName, margin, indentText);
9651                        break;
9652                    case "readonly":
9653                        tag = parseSimpleTag(start, factory.createJSDocReadonlyTag, tagName, margin, indentText);
9654                        break;
9655                    case "override":
9656                        tag = parseSimpleTag(start, factory.createJSDocOverrideTag, tagName, margin, indentText);
9657                        break;
9658                    case "deprecated":
9659                        hasDeprecatedTag = true;
9660                        tag = parseSimpleTag(start, factory.createJSDocDeprecatedTag, tagName, margin, indentText);
9661                        break;
9662                    case "this":
9663                        tag = parseThisTag(start, tagName, margin, indentText);
9664                        break;
9665                    case "enum":
9666                        tag = parseEnumTag(start, tagName, margin, indentText);
9667                        break;
9668                    case "arg":
9669                    case "argument":
9670                    case "param":
9671                        return parseParameterOrPropertyTag(start, tagName, PropertyLikeParse.Parameter, margin);
9672                    case "return":
9673                    case "returns":
9674                        tag = parseReturnTag(start, tagName, margin, indentText);
9675                        break;
9676                    case "template":
9677                        tag = parseTemplateTag(start, tagName, margin, indentText);
9678                        break;
9679                    case "type":
9680                        tag = parseTypeTag(start, tagName, margin, indentText);
9681                        break;
9682                    case "typedef":
9683                        tag = parseTypedefTag(start, tagName, margin, indentText);
9684                        break;
9685                    case "callback":
9686                        tag = parseCallbackTag(start, tagName, margin, indentText);
9687                        break;
9688                    case "see":
9689                        tag = parseSeeTag(start, tagName, margin, indentText);
9690                        break;
9691                    default:
9692                        tag = parseUnknownTag(start, tagName, margin, indentText);
9693                        break;
9694                }
9695                return tag;
9696            }
9697
9698            function parseTrailingTagComments(pos: number, end: number, margin: number, indentText: string) {
9699                // some tags, like typedef and callback, have already parsed their comments earlier
9700                if (!indentText) {
9701                    margin += end - pos;
9702                }
9703                return parseTagComments(margin, indentText.slice(margin));
9704            }
9705
9706            function parseTagComments(indent: number, initialMargin?: string): string | NodeArray<JSDocComment> | undefined {
9707                const commentsPos = getNodePos();
9708                let comments: string[] = [];
9709                const parts: JSDocComment[] = [];
9710                let linkEnd;
9711                let state = JSDocState.BeginningOfLine;
9712                let previousWhitespace = true;
9713                let margin: number | undefined;
9714                function pushComment(text: string) {
9715                    if (!margin) {
9716                        margin = indent;
9717                    }
9718                    comments.push(text);
9719                    indent += text.length;
9720                }
9721                if (initialMargin !== undefined) {
9722                    // jump straight to saving comments if there is some initial indentation
9723                    if (initialMargin !== "") {
9724                        pushComment(initialMargin);
9725                    }
9726                    state = JSDocState.SawAsterisk;
9727                }
9728                let tok = token() as JSDocSyntaxKind;
9729                loop: while (true) {
9730                    switch (tok) {
9731                        case SyntaxKind.NewLineTrivia:
9732                            state = JSDocState.BeginningOfLine;
9733                            // don't use pushComment here because we want to keep the margin unchanged
9734                            comments.push(scanner.getTokenText());
9735                            indent = 0;
9736                            break;
9737                        case SyntaxKind.AtToken:
9738                            if (state === JSDocState.SavingBackticks
9739                                || state === JSDocState.SavingComments && (!previousWhitespace || lookAhead(isNextJSDocTokenWhitespace))) {
9740                                // @ doesn't start a new tag inside ``, and inside a comment, only after whitespace or not before whitespace
9741                                comments.push(scanner.getTokenText());
9742                                break;
9743                            }
9744                            scanner.setTextPos(scanner.getTextPos() - 1);
9745                            // falls through
9746                        case SyntaxKind.EndOfFileToken:
9747                            // Done
9748                            break loop;
9749                        case SyntaxKind.WhitespaceTrivia:
9750                            if (state === JSDocState.SavingComments || state === JSDocState.SavingBackticks) {
9751                                pushComment(scanner.getTokenText());
9752                            }
9753                            else {
9754                                const whitespace = scanner.getTokenText();
9755                                // if the whitespace crosses the margin, take only the whitespace that passes the margin
9756                                if (margin !== undefined && indent + whitespace.length > margin) {
9757                                    comments.push(whitespace.slice(margin - indent));
9758                                }
9759                                indent += whitespace.length;
9760                            }
9761                            break;
9762                        case SyntaxKind.OpenBraceToken:
9763                            state = JSDocState.SavingComments;
9764                            const commentEnd = scanner.getStartPos();
9765                            const linkStart = scanner.getTextPos() - 1;
9766                            const link = parseJSDocLink(linkStart);
9767                            if (link) {
9768                                parts.push(finishNode(factory.createJSDocText(comments.join("")), linkEnd ?? commentsPos, commentEnd));
9769                                parts.push(link);
9770                                comments = [];
9771                                linkEnd = scanner.getTextPos();
9772                            }
9773                            else {
9774                                pushComment(scanner.getTokenText());
9775                            }
9776                            break;
9777                        case SyntaxKind.BacktickToken:
9778                            if (state === JSDocState.SavingBackticks) {
9779                                state = JSDocState.SavingComments;
9780                            }
9781                            else {
9782                                state = JSDocState.SavingBackticks;
9783                            }
9784                            pushComment(scanner.getTokenText());
9785                            break;
9786                        case SyntaxKind.AsteriskToken:
9787                            if (state === JSDocState.BeginningOfLine) {
9788                                // leading asterisks start recording on the *next* (non-whitespace) token
9789                                state = JSDocState.SawAsterisk;
9790                                indent += 1;
9791                                break;
9792                            }
9793                            // record the * as a comment
9794                            // falls through
9795                        default:
9796                            if (state !== JSDocState.SavingBackticks) {
9797                                state = JSDocState.SavingComments; // leading identifiers start recording as well
9798                            }
9799                            pushComment(scanner.getTokenText());
9800                            break;
9801                    }
9802                    previousWhitespace = token() === SyntaxKind.WhitespaceTrivia;
9803                    tok = nextTokenJSDoc();
9804                }
9805
9806                removeLeadingNewlines(comments);
9807                removeTrailingWhitespace(comments);
9808                if (parts.length) {
9809                    if (comments.length) {
9810                        parts.push(finishNode(factory.createJSDocText(comments.join("")), linkEnd ?? commentsPos));
9811                    }
9812                    return createNodeArray(parts, commentsPos, scanner.getTextPos());
9813                }
9814                else if (comments.length) {
9815                    return comments.join("");
9816                }
9817            }
9818
9819            function isNextJSDocTokenWhitespace() {
9820                const next = nextTokenJSDoc();
9821                return next === SyntaxKind.WhitespaceTrivia || next === SyntaxKind.NewLineTrivia;
9822            }
9823
9824            function parseJSDocLink(start: number) {
9825                const linkType = tryParse(parseJSDocLinkPrefix);
9826                if (!linkType) {
9827                    return undefined;
9828                }
9829                nextTokenJSDoc(); // start at token after link, then skip any whitespace
9830                skipWhitespace();
9831                // parseEntityName logs an error for non-identifier, so create a MissingNode ourselves to avoid the error
9832                const p2 = getNodePos();
9833                let name: EntityName | JSDocMemberName | undefined = tokenIsIdentifierOrKeyword(token())
9834                    ? parseEntityName(/*allowReservedWords*/ true)
9835                    : undefined;
9836                if (name) {
9837                    while (token() === SyntaxKind.PrivateIdentifier) {
9838                        reScanHashToken(); // rescan #id as # id
9839                        nextTokenJSDoc(); // then skip the #
9840                        name = finishNode(factory.createJSDocMemberName(name, parseIdentifier()), p2);
9841                    }
9842                }
9843                const text = [];
9844                while (token() !== SyntaxKind.CloseBraceToken && token() !== SyntaxKind.NewLineTrivia && token() !== SyntaxKind.EndOfFileToken) {
9845                    text.push(scanner.getTokenText());
9846                    nextTokenJSDoc();
9847                }
9848                const create = linkType === "link" ? factory.createJSDocLink
9849                    : linkType === "linkcode" ? factory.createJSDocLinkCode
9850                    : factory.createJSDocLinkPlain;
9851                return finishNode(create(name, text.join("")), start, scanner.getTextPos());
9852            }
9853
9854            function parseJSDocLinkPrefix() {
9855                skipWhitespaceOrAsterisk();
9856                if (token() === SyntaxKind.OpenBraceToken
9857                    && nextTokenJSDoc() === SyntaxKind.AtToken
9858                    && tokenIsIdentifierOrKeyword(nextTokenJSDoc())) {
9859                    const kind = scanner.getTokenValue();
9860                    if (isJSDocLinkTag(kind)) return kind;
9861                }
9862            }
9863
9864            function isJSDocLinkTag(kind: string) {
9865                return kind === "link" || kind === "linkcode" || kind === "linkplain";
9866            }
9867
9868            function parseUnknownTag(start: number, tagName: Identifier, indent: number, indentText: string) {
9869                return finishNode(factory.createJSDocUnknownTag(tagName, parseTrailingTagComments(start, getNodePos(), indent, indentText)), start);
9870            }
9871
9872            function addTag(tag: JSDocTag | undefined): void {
9873                if (!tag) {
9874                    return;
9875                }
9876                if (!tags) {
9877                    tags = [tag];
9878                    tagsPos = tag.pos;
9879                }
9880                else {
9881                    tags.push(tag);
9882                }
9883                tagsEnd = tag.end;
9884            }
9885
9886            function tryParseTypeExpression(): JSDocTypeExpression | undefined {
9887                skipWhitespaceOrAsterisk();
9888                return token() === SyntaxKind.OpenBraceToken ? parseJSDocTypeExpression() : undefined;
9889            }
9890
9891            function parseBracketNameInPropertyAndParamTag(): { name: EntityName, isBracketed: boolean } {
9892                // Looking for something like '[foo]', 'foo', '[foo.bar]' or 'foo.bar'
9893                const isBracketed = parseOptionalJsdoc(SyntaxKind.OpenBracketToken);
9894                if (isBracketed) {
9895                    skipWhitespace();
9896                }
9897                // a markdown-quoted name: `arg` is not legal jsdoc, but occurs in the wild
9898                const isBackquoted = parseOptionalJsdoc(SyntaxKind.BacktickToken);
9899                const name = parseJSDocEntityName();
9900                if (isBackquoted) {
9901                    parseExpectedTokenJSDoc(SyntaxKind.BacktickToken);
9902                }
9903                if (isBracketed) {
9904                    skipWhitespace();
9905                    // May have an optional default, e.g. '[foo = 42]'
9906                    if (parseOptionalToken(SyntaxKind.EqualsToken)) {
9907                        parseExpression();
9908                    }
9909
9910                    parseExpected(SyntaxKind.CloseBracketToken);
9911                }
9912
9913                return { name, isBracketed };
9914            }
9915
9916            function isObjectOrObjectArrayTypeReference(node: TypeNode): boolean {
9917                switch (node.kind) {
9918                    case SyntaxKind.ObjectKeyword:
9919                        return true;
9920                    case SyntaxKind.ArrayType:
9921                        return isObjectOrObjectArrayTypeReference((node as ArrayTypeNode).elementType);
9922                    default:
9923                        return isTypeReferenceNode(node) && ts.isIdentifier(node.typeName) && node.typeName.escapedText === "Object" && !node.typeArguments;
9924                }
9925            }
9926
9927            function parseParameterOrPropertyTag(start: number, tagName: Identifier, target: PropertyLikeParse, indent: number): JSDocParameterTag | JSDocPropertyTag {
9928                let typeExpression = tryParseTypeExpression();
9929                let isNameFirst = !typeExpression;
9930                skipWhitespaceOrAsterisk();
9931
9932                const { name, isBracketed } = parseBracketNameInPropertyAndParamTag();
9933                const indentText = skipWhitespaceOrAsterisk();
9934
9935                if (isNameFirst && !lookAhead(parseJSDocLinkPrefix)) {
9936                    typeExpression = tryParseTypeExpression();
9937                }
9938
9939                const comment = parseTrailingTagComments(start, getNodePos(), indent, indentText);
9940
9941                const nestedTypeLiteral = target !== PropertyLikeParse.CallbackParameter && parseNestedTypeLiteral(typeExpression, name, target, indent);
9942                if (nestedTypeLiteral) {
9943                    typeExpression = nestedTypeLiteral;
9944                    isNameFirst = true;
9945                }
9946                const result = target === PropertyLikeParse.Property
9947                    ? factory.createJSDocPropertyTag(tagName, name, isBracketed, typeExpression, isNameFirst, comment)
9948                    : factory.createJSDocParameterTag(tagName, name, isBracketed, typeExpression, isNameFirst, comment);
9949                return finishNode(result, start);
9950            }
9951
9952            function parseNestedTypeLiteral(typeExpression: JSDocTypeExpression | undefined, name: EntityName, target: PropertyLikeParse, indent: number) {
9953                if (typeExpression && isObjectOrObjectArrayTypeReference(typeExpression.type)) {
9954                    const pos = getNodePos();
9955                    let child: JSDocPropertyLikeTag | JSDocTypeTag | false;
9956                    let children: JSDocPropertyLikeTag[] | undefined;
9957                    while (child = tryParse(() => parseChildParameterOrPropertyTag(target, indent, name))) {
9958                        if (child.kind === SyntaxKind.JSDocParameterTag || child.kind === SyntaxKind.JSDocPropertyTag) {
9959                            children = append(children, child);
9960                        }
9961                    }
9962                    if (children) {
9963                        const literal = finishNode(factory.createJSDocTypeLiteral(children, typeExpression.type.kind === SyntaxKind.ArrayType), pos);
9964                        return finishNode(factory.createJSDocTypeExpression(literal), pos);
9965                    }
9966                }
9967            }
9968
9969            function parseReturnTag(start: number, tagName: Identifier, indent: number, indentText: string): JSDocReturnTag {
9970                if (some(tags, isJSDocReturnTag)) {
9971                    parseErrorAt(tagName.pos, scanner.getTokenPos(), Diagnostics._0_tag_already_specified, tagName.escapedText);
9972                }
9973
9974                const typeExpression = tryParseTypeExpression();
9975                return finishNode(factory.createJSDocReturnTag(tagName, typeExpression, parseTrailingTagComments(start, getNodePos(), indent, indentText)), start);
9976            }
9977
9978            function parseTypeTag(start: number, tagName: Identifier, indent?: number, indentText?: string): JSDocTypeTag {
9979                if (some(tags, isJSDocTypeTag)) {
9980                    parseErrorAt(tagName.pos, scanner.getTokenPos(), Diagnostics._0_tag_already_specified, tagName.escapedText);
9981                }
9982
9983                const typeExpression = parseJSDocTypeExpression(/*mayOmitBraces*/ true);
9984                const comments = indent !== undefined && indentText !== undefined ? parseTrailingTagComments(start, getNodePos(), indent, indentText) : undefined;
9985                return finishNode(factory.createJSDocTypeTag(tagName, typeExpression, comments), start);
9986            }
9987
9988            function parseSeeTag(start: number, tagName: Identifier, indent?: number, indentText?: string): JSDocSeeTag {
9989                const isMarkdownOrJSDocLink = token() === SyntaxKind.OpenBracketToken
9990                    || lookAhead(() => nextTokenJSDoc() === SyntaxKind.AtToken && tokenIsIdentifierOrKeyword(nextTokenJSDoc()) && isJSDocLinkTag(scanner.getTokenValue()));
9991                const nameExpression = isMarkdownOrJSDocLink ? undefined : parseJSDocNameReference();
9992                const comments = indent !== undefined && indentText !== undefined ? parseTrailingTagComments(start, getNodePos(), indent, indentText) : undefined;
9993                return finishNode(factory.createJSDocSeeTag(tagName, nameExpression, comments), start);
9994            }
9995
9996            function parseAuthorTag(start: number, tagName: Identifier, indent: number, indentText: string): JSDocAuthorTag {
9997                const commentStart = getNodePos();
9998                const textOnly = parseAuthorNameAndEmail();
9999                let commentEnd = scanner.getStartPos();
10000                const comments = parseTrailingTagComments(start, commentEnd, indent, indentText);
10001                if (!comments) {
10002                    commentEnd = scanner.getStartPos();
10003                }
10004                const allParts = typeof comments !== "string"
10005                    ? createNodeArray(concatenate([finishNode(textOnly, commentStart, commentEnd)], comments) as JSDocComment[], commentStart) // cast away readonly
10006                    : textOnly.text + comments;
10007                return finishNode(factory.createJSDocAuthorTag(tagName, allParts), start);
10008            }
10009
10010            function parseAuthorNameAndEmail(): JSDocText {
10011                const comments: string[] = [];
10012                let inEmail = false;
10013                let token = scanner.getToken();
10014                while (token !== SyntaxKind.EndOfFileToken && token !== SyntaxKind.NewLineTrivia) {
10015                    if (token === SyntaxKind.LessThanToken) {
10016                        inEmail = true;
10017                    }
10018                    else if (token === SyntaxKind.AtToken && !inEmail) {
10019                        break;
10020                    }
10021                    else if (token === SyntaxKind.GreaterThanToken && inEmail) {
10022                        comments.push(scanner.getTokenText());
10023                        scanner.setTextPos(scanner.getTokenPos() + 1);
10024                        break;
10025                    }
10026                    comments.push(scanner.getTokenText());
10027                    token = nextTokenJSDoc();
10028                }
10029
10030                return factory.createJSDocText(comments.join(""));
10031            }
10032
10033            function parseImplementsTag(start: number, tagName: Identifier, margin: number, indentText: string): JSDocImplementsTag {
10034                const className = parseExpressionWithTypeArgumentsForAugments();
10035                return finishNode(factory.createJSDocImplementsTag(tagName, className, parseTrailingTagComments(start, getNodePos(), margin, indentText)), start);
10036            }
10037
10038            function parseAugmentsTag(start: number, tagName: Identifier, margin: number, indentText: string): JSDocAugmentsTag {
10039                const className = parseExpressionWithTypeArgumentsForAugments();
10040                return finishNode(factory.createJSDocAugmentsTag(tagName, className, parseTrailingTagComments(start, getNodePos(), margin, indentText)), start);
10041            }
10042
10043            function parseExpressionWithTypeArgumentsForAugments(): ExpressionWithTypeArguments & { expression: Identifier | PropertyAccessEntityNameExpression } {
10044                const usedBrace = parseOptional(SyntaxKind.OpenBraceToken);
10045                const pos = getNodePos();
10046                const expression = parsePropertyAccessEntityNameExpression();
10047                const typeArguments = tryParseTypeArguments();
10048                const node = factory.createExpressionWithTypeArguments(expression, typeArguments) as ExpressionWithTypeArguments & { expression: Identifier | PropertyAccessEntityNameExpression };
10049                const res = finishNode(node, pos);
10050                if (usedBrace) {
10051                    parseExpected(SyntaxKind.CloseBraceToken);
10052                }
10053                return res;
10054            }
10055
10056            function parsePropertyAccessEntityNameExpression() {
10057                const pos = getNodePos();
10058                let node: Identifier | PropertyAccessEntityNameExpression = parseJSDocIdentifierName();
10059                while (parseOptional(SyntaxKind.DotToken)) {
10060                    const name = parseJSDocIdentifierName();
10061                    node = finishNode(factory.createPropertyAccessExpression(node, name), pos) as PropertyAccessEntityNameExpression;
10062                }
10063                return node;
10064            }
10065
10066            function parseSimpleTag(start: number, createTag: (tagName: Identifier | undefined, comment?: string | NodeArray<JSDocComment>) => JSDocTag, tagName: Identifier, margin: number, indentText: string): JSDocTag {
10067                return finishNode(createTag(tagName, parseTrailingTagComments(start, getNodePos(), margin, indentText)), start);
10068            }
10069
10070            function parseThisTag(start: number, tagName: Identifier, margin: number, indentText: string): JSDocThisTag {
10071                const typeExpression = parseJSDocTypeExpression(/*mayOmitBraces*/ true);
10072                skipWhitespace();
10073                return finishNode(factory.createJSDocThisTag(tagName, typeExpression, parseTrailingTagComments(start, getNodePos(), margin, indentText)), start);
10074            }
10075
10076            function parseEnumTag(start: number, tagName: Identifier, margin: number, indentText: string): JSDocEnumTag {
10077                const typeExpression = parseJSDocTypeExpression(/*mayOmitBraces*/ true);
10078                skipWhitespace();
10079                return finishNode(factory.createJSDocEnumTag(tagName, typeExpression, parseTrailingTagComments(start, getNodePos(), margin, indentText)), start);
10080            }
10081
10082            function parseTypedefTag(start: number, tagName: Identifier, indent: number, indentText: string): JSDocTypedefTag {
10083                let typeExpression: JSDocTypeExpression | JSDocTypeLiteral | undefined = tryParseTypeExpression();
10084                skipWhitespaceOrAsterisk();
10085
10086                const fullName = parseJSDocTypeNameWithNamespace();
10087                skipWhitespace();
10088                let comment = parseTagComments(indent);
10089
10090                let end: number | undefined;
10091                if (!typeExpression || isObjectOrObjectArrayTypeReference(typeExpression.type)) {
10092                    let child: JSDocTypeTag | JSDocPropertyTag | false;
10093                    let childTypeTag: JSDocTypeTag | undefined;
10094                    let jsDocPropertyTags: JSDocPropertyTag[] | undefined;
10095                    let hasChildren = false;
10096                    while (child = tryParse(() => parseChildPropertyTag(indent))) {
10097                        hasChildren = true;
10098                        if (child.kind === SyntaxKind.JSDocTypeTag) {
10099                            if (childTypeTag) {
10100                                const lastError = parseErrorAtCurrentToken(Diagnostics.A_JSDoc_typedef_comment_may_not_contain_multiple_type_tags);
10101                                if (lastError) {
10102                                    addRelatedInfo(lastError, createDetachedDiagnostic(fileName, 0, 0, Diagnostics.The_tag_was_first_specified_here));
10103                                }
10104                                break;
10105                            }
10106                            else {
10107                                childTypeTag = child;
10108                            }
10109                        }
10110                        else {
10111                            jsDocPropertyTags = append(jsDocPropertyTags, child);
10112                        }
10113                    }
10114                    if (hasChildren) {
10115                        const isArrayType = typeExpression && typeExpression.type.kind === SyntaxKind.ArrayType;
10116                        const jsdocTypeLiteral = factory.createJSDocTypeLiteral(jsDocPropertyTags, isArrayType);
10117                        typeExpression = childTypeTag && childTypeTag.typeExpression && !isObjectOrObjectArrayTypeReference(childTypeTag.typeExpression.type) ?
10118                            childTypeTag.typeExpression :
10119                            finishNode(jsdocTypeLiteral, start);
10120                        end = typeExpression.end;
10121                    }
10122                }
10123
10124                // Only include the characters between the name end and the next token if a comment was actually parsed out - otherwise it's just whitespace
10125                end = end || comment !== undefined ?
10126                    getNodePos() :
10127                    (fullName ?? typeExpression ?? tagName).end;
10128
10129                if (!comment) {
10130                    comment = parseTrailingTagComments(start, end, indent, indentText);
10131                }
10132
10133                const typedefTag = factory.createJSDocTypedefTag(tagName, typeExpression, fullName, comment);
10134                return finishNode(typedefTag, start, end);
10135            }
10136
10137            function parseJSDocTypeNameWithNamespace(nested?: boolean) {
10138                const pos = scanner.getTokenPos();
10139                if (!tokenIsIdentifierOrKeyword(token())) {
10140                    return undefined;
10141                }
10142                const typeNameOrNamespaceName = parseJSDocIdentifierName();
10143                if (parseOptional(SyntaxKind.DotToken)) {
10144                    const body = parseJSDocTypeNameWithNamespace(/*nested*/ true);
10145                    const jsDocNamespaceNode = factory.createModuleDeclaration(
10146                        /*modifiers*/ undefined,
10147                        typeNameOrNamespaceName,
10148                        body,
10149                        nested ? NodeFlags.NestedNamespace : undefined
10150                    ) as JSDocNamespaceDeclaration;
10151                    return finishNode(jsDocNamespaceNode, pos);
10152                }
10153
10154                if (nested) {
10155                    typeNameOrNamespaceName.isInJSDocNamespace = true;
10156                }
10157                return typeNameOrNamespaceName;
10158            }
10159
10160
10161            function parseCallbackTagParameters(indent: number) {
10162                const pos = getNodePos();
10163                let child: JSDocParameterTag | false;
10164                let parameters;
10165                while (child = tryParse(() => parseChildParameterOrPropertyTag(PropertyLikeParse.CallbackParameter, indent) as JSDocParameterTag)) {
10166                    parameters = append(parameters, child);
10167                }
10168                return createNodeArray(parameters || [], pos);
10169            }
10170
10171            function parseCallbackTag(start: number, tagName: Identifier, indent: number, indentText: string): JSDocCallbackTag {
10172                const fullName = parseJSDocTypeNameWithNamespace();
10173                skipWhitespace();
10174                let comment = parseTagComments(indent);
10175                const parameters = parseCallbackTagParameters(indent);
10176                const returnTag = tryParse(() => {
10177                    if (parseOptionalJsdoc(SyntaxKind.AtToken)) {
10178                        const tag = parseTag(indent);
10179                        if (tag && tag.kind === SyntaxKind.JSDocReturnTag) {
10180                            return tag as JSDocReturnTag;
10181                        }
10182                    }
10183                });
10184                const typeExpression = finishNode(factory.createJSDocSignature(/*typeParameters*/ undefined, parameters, returnTag), start);
10185                if (!comment) {
10186                    comment = parseTrailingTagComments(start, getNodePos(), indent, indentText);
10187                }
10188                const end = comment !== undefined ? getNodePos() : typeExpression.end;
10189                return finishNode(factory.createJSDocCallbackTag(tagName, typeExpression, fullName, comment), start, end);
10190            }
10191
10192            function escapedTextsEqual(a: EntityName, b: EntityName): boolean {
10193                while (!ts.isIdentifier(a) || !ts.isIdentifier(b)) {
10194                    if (!ts.isIdentifier(a) && !ts.isIdentifier(b) && a.right.escapedText === b.right.escapedText) {
10195                        a = a.left;
10196                        b = b.left;
10197                    }
10198                    else {
10199                        return false;
10200                    }
10201                }
10202                return a.escapedText === b.escapedText;
10203            }
10204
10205            function parseChildPropertyTag(indent: number) {
10206                return parseChildParameterOrPropertyTag(PropertyLikeParse.Property, indent) as JSDocTypeTag | JSDocPropertyTag | false;
10207            }
10208
10209            function parseChildParameterOrPropertyTag(target: PropertyLikeParse, indent: number, name?: EntityName): JSDocTypeTag | JSDocPropertyTag | JSDocParameterTag | false {
10210                let canParseTag = true;
10211                let seenAsterisk = false;
10212                while (true) {
10213                    switch (nextTokenJSDoc()) {
10214                        case SyntaxKind.AtToken:
10215                            if (canParseTag) {
10216                                const child = tryParseChildTag(target, indent);
10217                                if (child && (child.kind === SyntaxKind.JSDocParameterTag || child.kind === SyntaxKind.JSDocPropertyTag) &&
10218                                    target !== PropertyLikeParse.CallbackParameter &&
10219                                    name && (ts.isIdentifier(child.name) || !escapedTextsEqual(name, child.name.left))) {
10220                                    return false;
10221                                }
10222                                return child;
10223                            }
10224                            seenAsterisk = false;
10225                            break;
10226                        case SyntaxKind.NewLineTrivia:
10227                            canParseTag = true;
10228                            seenAsterisk = false;
10229                            break;
10230                        case SyntaxKind.AsteriskToken:
10231                            if (seenAsterisk) {
10232                                canParseTag = false;
10233                            }
10234                            seenAsterisk = true;
10235                            break;
10236                        case SyntaxKind.Identifier:
10237                            canParseTag = false;
10238                            break;
10239                        case SyntaxKind.EndOfFileToken:
10240                            return false;
10241                    }
10242                }
10243            }
10244
10245            function tryParseChildTag(target: PropertyLikeParse, indent: number): JSDocTypeTag | JSDocPropertyTag | JSDocParameterTag | false {
10246                Debug.assert(token() === SyntaxKind.AtToken);
10247                const start = scanner.getStartPos();
10248                nextTokenJSDoc();
10249
10250                const tagName = parseJSDocIdentifierName();
10251                skipWhitespace();
10252                let t: PropertyLikeParse;
10253                switch (tagName.escapedText) {
10254                    case "type":
10255                        return target === PropertyLikeParse.Property && parseTypeTag(start, tagName);
10256                    case "prop":
10257                    case "property":
10258                        t = PropertyLikeParse.Property;
10259                        break;
10260                    case "arg":
10261                    case "argument":
10262                    case "param":
10263                        t = PropertyLikeParse.Parameter | PropertyLikeParse.CallbackParameter;
10264                        break;
10265                    default:
10266                        return false;
10267                }
10268                if (!(target & t)) {
10269                    return false;
10270                }
10271                return parseParameterOrPropertyTag(start, tagName, target, indent);
10272            }
10273
10274            function parseTemplateTagTypeParameter() {
10275                const typeParameterPos = getNodePos();
10276                const isBracketed = parseOptionalJsdoc(SyntaxKind.OpenBracketToken);
10277                if (isBracketed) {
10278                    skipWhitespace();
10279                }
10280                const name = parseJSDocIdentifierName(Diagnostics.Unexpected_token_A_type_parameter_name_was_expected_without_curly_braces);
10281
10282                let defaultType: TypeNode | undefined;
10283                if (isBracketed) {
10284                    skipWhitespace();
10285                    parseExpected(SyntaxKind.EqualsToken);
10286                    defaultType = doInsideOfContext(NodeFlags.JSDoc, parseJSDocType);
10287                    parseExpected(SyntaxKind.CloseBracketToken);
10288                }
10289
10290                if (nodeIsMissing(name)) {
10291                    return undefined;
10292                }
10293                return finishNode(factory.createTypeParameterDeclaration(/*modifiers*/ undefined, name, /*constraint*/ undefined, defaultType), typeParameterPos);
10294            }
10295
10296            function parseTemplateTagTypeParameters() {
10297                const pos = getNodePos();
10298                const typeParameters = [];
10299                do {
10300                    skipWhitespace();
10301                    const node = parseTemplateTagTypeParameter();
10302                    if (node !== undefined) {
10303                        typeParameters.push(node);
10304                    }
10305                    skipWhitespaceOrAsterisk();
10306                } while (parseOptionalJsdoc(SyntaxKind.CommaToken));
10307                return createNodeArray(typeParameters, pos);
10308            }
10309
10310            function parseTemplateTag(start: number, tagName: Identifier, indent: number, indentText: string): JSDocTemplateTag {
10311                // The template tag looks like one of the following:
10312                //   @template T,U,V
10313                //   @template {Constraint} T
10314                //
10315                // According to the [closure docs](https://github.com/google/closure-compiler/wiki/Generic-Types#multiple-bounded-template-types):
10316                //   > Multiple bounded generics cannot be declared on the same line. For the sake of clarity, if multiple templates share the same
10317                //   > type bound they must be declared on separate lines.
10318                //
10319                // TODO: Determine whether we should enforce this in the checker.
10320                // TODO: Consider moving the `constraint` to the first type parameter as we could then remove `getEffectiveConstraintOfTypeParameter`.
10321                // TODO: Consider only parsing a single type parameter if there is a constraint.
10322                const constraint = token() === SyntaxKind.OpenBraceToken ? parseJSDocTypeExpression() : undefined;
10323                const typeParameters = parseTemplateTagTypeParameters();
10324                return finishNode(factory.createJSDocTemplateTag(tagName, constraint, typeParameters, parseTrailingTagComments(start, getNodePos(), indent, indentText)), start);
10325            }
10326
10327            function parseOptionalJsdoc(t: JSDocSyntaxKind): boolean {
10328                if (token() === t) {
10329                    nextTokenJSDoc();
10330                    return true;
10331                }
10332                return false;
10333            }
10334
10335            function parseJSDocEntityName(): EntityName {
10336                let entity: EntityName = parseJSDocIdentifierName();
10337                if (parseOptional(SyntaxKind.OpenBracketToken)) {
10338                    parseExpected(SyntaxKind.CloseBracketToken);
10339                    // Note that y[] is accepted as an entity name, but the postfix brackets are not saved for checking.
10340                    // Technically usejsdoc.org requires them for specifying a property of a type equivalent to Array<{ x: ...}>
10341                    // but it's not worth it to enforce that restriction.
10342                }
10343                while (parseOptional(SyntaxKind.DotToken)) {
10344                    const name = parseJSDocIdentifierName();
10345                    if (parseOptional(SyntaxKind.OpenBracketToken)) {
10346                        parseExpected(SyntaxKind.CloseBracketToken);
10347                    }
10348                    entity = createQualifiedName(entity, name);
10349                }
10350                return entity;
10351            }
10352
10353            function parseJSDocIdentifierName(message?: DiagnosticMessage): Identifier {
10354                if (!tokenIsIdentifierOrKeyword(token())) {
10355                    return createMissingNode<Identifier>(SyntaxKind.Identifier, /*reportAtCurrentPosition*/ !message, message || Diagnostics.Identifier_expected);
10356                }
10357
10358                identifierCount++;
10359                const pos = scanner.getTokenPos();
10360                const end = scanner.getTextPos();
10361                const originalKeywordKind = token();
10362                const text = internIdentifier(scanner.getTokenValue());
10363                const result = finishNode(factory.createIdentifier(text, /*typeArguments*/ undefined, originalKeywordKind), pos, end);
10364                nextTokenJSDoc();
10365                return result;
10366            }
10367        }
10368    }
10369}
10370
10371namespace IncrementalParser {
10372    export function updateSourceFile(sourceFile: SourceFile, newText: string, textChangeRange: TextChangeRange, aggressiveChecks: boolean): SourceFile {
10373        aggressiveChecks = aggressiveChecks || Debug.shouldAssert(AssertionLevel.Aggressive);
10374
10375        checkChangeRange(sourceFile, newText, textChangeRange, aggressiveChecks);
10376        if (textChangeRangeIsUnchanged(textChangeRange)) {
10377            // if the text didn't change, then we can just return our current source file as-is.
10378            return sourceFile;
10379        }
10380
10381        if (sourceFile.statements.length === 0) {
10382            // If we don't have any statements in the current source file, then there's no real
10383            // way to incrementally parse.  So just do a full parse instead.
10384            return Parser.parseSourceFile(sourceFile.fileName, newText, sourceFile.languageVersion, /*syntaxCursor*/ undefined, /*setParentNodes*/ true, sourceFile.scriptKind, sourceFile.setExternalModuleIndicator);
10385        }
10386
10387        // Make sure we're not trying to incrementally update a source file more than once.  Once
10388        // we do an update the original source file is considered unusable from that point onwards.
10389        //
10390        // This is because we do incremental parsing in-place.  i.e. we take nodes from the old
10391        // tree and give them new positions and parents.  From that point on, trusting the old
10392        // tree at all is not possible as far too much of it may violate invariants.
10393        const incrementalSourceFile = sourceFile as Node as IncrementalNode;
10394        Debug.assert(!incrementalSourceFile.hasBeenIncrementallyParsed);
10395        incrementalSourceFile.hasBeenIncrementallyParsed = true;
10396        Parser.fixupParentReferences(incrementalSourceFile);
10397        const oldText = sourceFile.text;
10398        const syntaxCursor = createSyntaxCursor(sourceFile);
10399
10400        // Make the actual change larger so that we know to reparse anything whose lookahead
10401        // might have intersected the change.
10402        const changeRange = extendToAffectedRange(sourceFile, textChangeRange);
10403        checkChangeRange(sourceFile, newText, changeRange, aggressiveChecks);
10404
10405        // Ensure that extending the affected range only moved the start of the change range
10406        // earlier in the file.
10407        Debug.assert(changeRange.span.start <= textChangeRange.span.start);
10408        Debug.assert(textSpanEnd(changeRange.span) === textSpanEnd(textChangeRange.span));
10409        Debug.assert(textSpanEnd(textChangeRangeNewSpan(changeRange)) === textSpanEnd(textChangeRangeNewSpan(textChangeRange)));
10410
10411        // The is the amount the nodes after the edit range need to be adjusted.  It can be
10412        // positive (if the edit added characters), negative (if the edit deleted characters)
10413        // or zero (if this was a pure overwrite with nothing added/removed).
10414        const delta = textChangeRangeNewSpan(changeRange).length - changeRange.span.length;
10415
10416        // If we added or removed characters during the edit, then we need to go and adjust all
10417        // the nodes after the edit.  Those nodes may move forward (if we inserted chars) or they
10418        // may move backward (if we deleted chars).
10419        //
10420        // Doing this helps us out in two ways.  First, it means that any nodes/tokens we want
10421        // to reuse are already at the appropriate position in the new text.  That way when we
10422        // reuse them, we don't have to figure out if they need to be adjusted.  Second, it makes
10423        // it very easy to determine if we can reuse a node.  If the node's position is at where
10424        // we are in the text, then we can reuse it.  Otherwise we can't.  If the node's position
10425        // is ahead of us, then we'll need to rescan tokens.  If the node's position is behind
10426        // us, then we'll need to skip it or crumble it as appropriate
10427        //
10428        // We will also adjust the positions of nodes that intersect the change range as well.
10429        // By doing this, we ensure that all the positions in the old tree are consistent, not
10430        // just the positions of nodes entirely before/after the change range.  By being
10431        // consistent, we can then easily map from positions to nodes in the old tree easily.
10432        //
10433        // Also, mark any syntax elements that intersect the changed span.  We know, up front,
10434        // that we cannot reuse these elements.
10435        updateTokenPositionsAndMarkElements(incrementalSourceFile,
10436            changeRange.span.start, textSpanEnd(changeRange.span), textSpanEnd(textChangeRangeNewSpan(changeRange)), delta, oldText, newText, aggressiveChecks);
10437
10438        // Now that we've set up our internal incremental state just proceed and parse the
10439        // source file in the normal fashion.  When possible the parser will retrieve and
10440        // reuse nodes from the old tree.
10441        //
10442        // Note: passing in 'true' for setNodeParents is very important.  When incrementally
10443        // parsing, we will be reusing nodes from the old tree, and placing it into new
10444        // parents.  If we don't set the parents now, we'll end up with an observably
10445        // inconsistent tree.  Setting the parents on the new tree should be very fast.  We
10446        // will immediately bail out of walking any subtrees when we can see that their parents
10447        // are already correct.
10448        const result = Parser.parseSourceFile(sourceFile.fileName, newText, sourceFile.languageVersion, syntaxCursor, /*setParentNodes*/ true, sourceFile.scriptKind, sourceFile.setExternalModuleIndicator);
10449        result.commentDirectives = getNewCommentDirectives(
10450            sourceFile.commentDirectives,
10451            result.commentDirectives,
10452            changeRange.span.start,
10453            textSpanEnd(changeRange.span),
10454            delta,
10455            oldText,
10456            newText,
10457            aggressiveChecks
10458        );
10459        result.impliedNodeFormat = sourceFile.impliedNodeFormat;
10460        return result;
10461    }
10462
10463    function getNewCommentDirectives(
10464        oldDirectives: CommentDirective[] | undefined,
10465        newDirectives: CommentDirective[] | undefined,
10466        changeStart: number,
10467        changeRangeOldEnd: number,
10468        delta: number,
10469        oldText: string,
10470        newText: string,
10471        aggressiveChecks: boolean
10472    ): CommentDirective[] | undefined {
10473        if (!oldDirectives) return newDirectives;
10474        let commentDirectives: CommentDirective[] | undefined;
10475        let addedNewlyScannedDirectives = false;
10476        for (const directive of oldDirectives) {
10477            const { range, type } = directive;
10478            // Range before the change
10479            if (range.end < changeStart) {
10480                commentDirectives = append(commentDirectives, directive);
10481            }
10482            else if (range.pos > changeRangeOldEnd) {
10483                addNewlyScannedDirectives();
10484                // Node is entirely past the change range.  We need to move both its pos and
10485                // end, forward or backward appropriately.
10486                const updatedDirective: CommentDirective = {
10487                    range: { pos: range.pos + delta, end: range.end + delta },
10488                    type
10489                };
10490                commentDirectives = append(commentDirectives, updatedDirective);
10491                if (aggressiveChecks) {
10492                    Debug.assert(oldText.substring(range.pos, range.end) === newText.substring(updatedDirective.range.pos, updatedDirective.range.end));
10493                }
10494            }
10495            // Ignore ranges that fall in change range
10496        }
10497        addNewlyScannedDirectives();
10498        return commentDirectives;
10499
10500        function addNewlyScannedDirectives() {
10501            if (addedNewlyScannedDirectives) return;
10502            addedNewlyScannedDirectives = true;
10503            if (!commentDirectives) {
10504                commentDirectives = newDirectives;
10505            }
10506            else if (newDirectives) {
10507                commentDirectives.push(...newDirectives);
10508            }
10509        }
10510    }
10511
10512    function moveElementEntirelyPastChangeRange(element: IncrementalElement, isArray: boolean, delta: number, oldText: string, newText: string, aggressiveChecks: boolean) {
10513        if (isArray) {
10514            visitArray(element as IncrementalNodeArray);
10515        }
10516        else {
10517            visitNode(element as IncrementalNode);
10518        }
10519        return;
10520
10521        function visitNode(node: IncrementalNode) {
10522            let text = "";
10523            if (aggressiveChecks && shouldCheckNode(node)) {
10524                text = oldText.substring(node.pos, node.end);
10525            }
10526
10527            // Ditch any existing LS children we may have created.  This way we can avoid
10528            // moving them forward.
10529            if (node._children) {
10530                node._children = undefined;
10531            }
10532
10533            setTextRangePosEnd(node, node.pos + delta, node.end + delta);
10534
10535            if (aggressiveChecks && shouldCheckNode(node)) {
10536                Debug.assert(text === newText.substring(node.pos, node.end));
10537            }
10538
10539            forEachChild(node, visitNode, visitArray);
10540            if (hasJSDocNodes(node)) {
10541                for (const jsDocComment of node.jsDoc!) {
10542                    visitNode(jsDocComment as Node as IncrementalNode);
10543                }
10544            }
10545            checkNodePositions(node, aggressiveChecks);
10546        }
10547
10548        function visitArray(array: IncrementalNodeArray) {
10549            array._children = undefined;
10550            setTextRangePosEnd(array, array.pos + delta, array.end + delta);
10551
10552            for (const node of array) {
10553                visitNode(node);
10554            }
10555        }
10556    }
10557
10558    function shouldCheckNode(node: Node) {
10559        switch (node.kind) {
10560            case SyntaxKind.StringLiteral:
10561            case SyntaxKind.NumericLiteral:
10562            case SyntaxKind.Identifier:
10563                return true;
10564        }
10565
10566        return false;
10567    }
10568
10569    function adjustIntersectingElement(element: IncrementalElement, changeStart: number, changeRangeOldEnd: number, changeRangeNewEnd: number, delta: number) {
10570        Debug.assert(element.end >= changeStart, "Adjusting an element that was entirely before the change range");
10571        Debug.assert(element.pos <= changeRangeOldEnd, "Adjusting an element that was entirely after the change range");
10572        Debug.assert(element.pos <= element.end);
10573
10574        // We have an element that intersects the change range in some way.  It may have its
10575        // start, or its end (or both) in the changed range.  We want to adjust any part
10576        // that intersects such that the final tree is in a consistent state.  i.e. all
10577        // children have spans within the span of their parent, and all siblings are ordered
10578        // properly.
10579
10580        // We may need to update both the 'pos' and the 'end' of the element.
10581
10582        // If the 'pos' is before the start of the change, then we don't need to touch it.
10583        // If it isn't, then the 'pos' must be inside the change.  How we update it will
10584        // depend if delta is positive or negative. If delta is positive then we have
10585        // something like:
10586        //
10587        //  -------------------AAA-----------------
10588        //  -------------------BBBCCCCCCC-----------------
10589        //
10590        // In this case, we consider any node that started in the change range to still be
10591        // starting at the same position.
10592        //
10593        // however, if the delta is negative, then we instead have something like this:
10594        //
10595        //  -------------------XXXYYYYYYY-----------------
10596        //  -------------------ZZZ-----------------
10597        //
10598        // In this case, any element that started in the 'X' range will keep its position.
10599        // However any element that started after that will have their pos adjusted to be
10600        // at the end of the new range.  i.e. any node that started in the 'Y' range will
10601        // be adjusted to have their start at the end of the 'Z' range.
10602        //
10603        // The element will keep its position if possible.  Or Move backward to the new-end
10604        // if it's in the 'Y' range.
10605        const pos = Math.min(element.pos, changeRangeNewEnd);
10606
10607        // If the 'end' is after the change range, then we always adjust it by the delta
10608        // amount.  However, if the end is in the change range, then how we adjust it
10609        // will depend on if delta is positive or negative.  If delta is positive then we
10610        // have something like:
10611        //
10612        //  -------------------AAA-----------------
10613        //  -------------------BBBCCCCCCC-----------------
10614        //
10615        // In this case, we consider any node that ended inside the change range to keep its
10616        // end position.
10617        //
10618        // however, if the delta is negative, then we instead have something like this:
10619        //
10620        //  -------------------XXXYYYYYYY-----------------
10621        //  -------------------ZZZ-----------------
10622        //
10623        // In this case, any element that ended in the 'X' range will keep its position.
10624        // However any element that ended after that will have their pos adjusted to be
10625        // at the end of the new range.  i.e. any node that ended in the 'Y' range will
10626        // be adjusted to have their end at the end of the 'Z' range.
10627        const end = element.end >= changeRangeOldEnd ?
10628            // Element ends after the change range.  Always adjust the end pos.
10629            element.end + delta :
10630            // Element ends in the change range.  The element will keep its position if
10631            // possible. Or Move backward to the new-end if it's in the 'Y' range.
10632            Math.min(element.end, changeRangeNewEnd);
10633
10634        Debug.assert(pos <= end);
10635        if (element.parent) {
10636            Debug.assertGreaterThanOrEqual(pos, element.parent.pos);
10637            Debug.assertLessThanOrEqual(end, element.parent.end);
10638        }
10639
10640        setTextRangePosEnd(element, pos, end);
10641    }
10642
10643    function checkNodePositions(node: Node, aggressiveChecks: boolean) {
10644        if (aggressiveChecks) {
10645            let pos = node.pos;
10646            const visitNode = (child: Node) => {
10647                Debug.assert(child.pos >= pos);
10648                pos = child.end;
10649            };
10650            if (hasJSDocNodes(node)) {
10651                for (const jsDocComment of node.jsDoc!) {
10652                    visitNode(jsDocComment);
10653                }
10654            }
10655            forEachChild(node, visitNode);
10656            Debug.assert(pos <= node.end);
10657        }
10658    }
10659
10660    function updateTokenPositionsAndMarkElements(
10661        sourceFile: IncrementalNode,
10662        changeStart: number,
10663        changeRangeOldEnd: number,
10664        changeRangeNewEnd: number,
10665        delta: number,
10666        oldText: string,
10667        newText: string,
10668        aggressiveChecks: boolean): void {
10669
10670        visitNode(sourceFile);
10671        return;
10672
10673        function visitNode(child: IncrementalNode) {
10674            Debug.assert(child.pos <= child.end);
10675            if (child.pos > changeRangeOldEnd) {
10676                // Node is entirely past the change range.  We need to move both its pos and
10677                // end, forward or backward appropriately.
10678                moveElementEntirelyPastChangeRange(child, /*isArray*/ false, delta, oldText, newText, aggressiveChecks);
10679                return;
10680            }
10681
10682            // Check if the element intersects the change range.  If it does, then it is not
10683            // reusable.  Also, we'll need to recurse to see what constituent portions we may
10684            // be able to use.
10685            const fullEnd = child.end;
10686            if (fullEnd >= changeStart) {
10687                child.intersectsChange = true;
10688                child._children = undefined;
10689
10690                // Adjust the pos or end (or both) of the intersecting element accordingly.
10691                adjustIntersectingElement(child, changeStart, changeRangeOldEnd, changeRangeNewEnd, delta);
10692                forEachChild(child, visitNode, visitArray);
10693                if (hasJSDocNodes(child)) {
10694                    for (const jsDocComment of child.jsDoc!) {
10695                        visitNode(jsDocComment as Node as IncrementalNode);
10696                    }
10697                }
10698                checkNodePositions(child, aggressiveChecks);
10699                return;
10700            }
10701
10702            // Otherwise, the node is entirely before the change range.  No need to do anything with it.
10703            Debug.assert(fullEnd < changeStart);
10704        }
10705
10706        function visitArray(array: IncrementalNodeArray) {
10707            Debug.assert(array.pos <= array.end);
10708            if (array.pos > changeRangeOldEnd) {
10709                // Array is entirely after the change range.  We need to move it, and move any of
10710                // its children.
10711                moveElementEntirelyPastChangeRange(array, /*isArray*/ true, delta, oldText, newText, aggressiveChecks);
10712                return;
10713            }
10714
10715            // Check if the element intersects the change range.  If it does, then it is not
10716            // reusable.  Also, we'll need to recurse to see what constituent portions we may
10717            // be able to use.
10718            const fullEnd = array.end;
10719            if (fullEnd >= changeStart) {
10720                array.intersectsChange = true;
10721                array._children = undefined;
10722
10723                // Adjust the pos or end (or both) of the intersecting array accordingly.
10724                adjustIntersectingElement(array, changeStart, changeRangeOldEnd, changeRangeNewEnd, delta);
10725                for (const node of array) {
10726                    if (!node.virtual) {
10727                        visitNode(node);
10728                    }
10729                }
10730                return;
10731            }
10732
10733            // Otherwise, the array is entirely before the change range.  No need to do anything with it.
10734            Debug.assert(fullEnd < changeStart);
10735        }
10736    }
10737
10738    function extendToAffectedRange(sourceFile: SourceFile, changeRange: TextChangeRange): TextChangeRange {
10739        // Consider the following code:
10740        //      void foo() { /; }
10741        //
10742        // If the text changes with an insertion of / just before the semicolon then we end up with:
10743        //      void foo() { //; }
10744        //
10745        // If we were to just use the changeRange a is, then we would not rescan the { token
10746        // (as it does not intersect the actual original change range).  Because an edit may
10747        // change the token touching it, we actually need to look back *at least* one token so
10748        // that the prior token sees that change.
10749        const maxLookahead = 1;
10750
10751        let start = changeRange.span.start;
10752
10753        // the first iteration aligns us with the change start. subsequent iteration move us to
10754        // the left by maxLookahead tokens.  We only need to do this as long as we're not at the
10755        // start of the tree.
10756        for (let i = 0; start > 0 && i <= maxLookahead; i++) {
10757            const nearestNode = findNearestNodeStartingBeforeOrAtPosition(sourceFile, start);
10758            Debug.assert(nearestNode.pos <= start);
10759            const position = nearestNode.pos;
10760
10761            start = Math.max(0, position - 1);
10762        }
10763
10764        const finalSpan = createTextSpanFromBounds(start, textSpanEnd(changeRange.span));
10765        const finalLength = changeRange.newLength + (changeRange.span.start - start);
10766
10767        return createTextChangeRange(finalSpan, finalLength);
10768    }
10769
10770    function findNearestNodeStartingBeforeOrAtPosition(sourceFile: SourceFile, position: number): Node {
10771        let bestResult: Node = sourceFile;
10772        let lastNodeEntirelyBeforePosition: Node | undefined;
10773
10774        forEachChild(sourceFile, visit);
10775
10776        if (lastNodeEntirelyBeforePosition) {
10777            const lastChildOfLastEntireNodeBeforePosition = getLastDescendant(lastNodeEntirelyBeforePosition);
10778            if (lastChildOfLastEntireNodeBeforePosition.pos > bestResult.pos) {
10779                bestResult = lastChildOfLastEntireNodeBeforePosition;
10780            }
10781        }
10782
10783        return bestResult;
10784
10785        function getLastDescendant(node: Node): Node {
10786            while (true) {
10787                const lastChild = getLastChild(node);
10788                if (lastChild) {
10789                    node = lastChild;
10790                }
10791                else {
10792                    return node;
10793                }
10794            }
10795        }
10796
10797        function visit(child: Node) {
10798            if (nodeIsMissing(child)) {
10799                // Missing nodes are effectively invisible to us.  We never even consider them
10800                // When trying to find the nearest node before us.
10801                return;
10802            }
10803
10804            // If the child intersects this position, then this node is currently the nearest
10805            // node that starts before the position.
10806            if (child.pos <= position) {
10807                if (child.pos >= bestResult.pos) {
10808                    // This node starts before the position, and is closer to the position than
10809                    // the previous best node we found.  It is now the new best node.
10810                    bestResult = child;
10811                }
10812
10813                // Now, the node may overlap the position, or it may end entirely before the
10814                // position.  If it overlaps with the position, then either it, or one of its
10815                // children must be the nearest node before the position.  So we can just
10816                // recurse into this child to see if we can find something better.
10817                if (position < child.end) {
10818                    // The nearest node is either this child, or one of the children inside
10819                    // of it.  We've already marked this child as the best so far.  Recurse
10820                    // in case one of the children is better.
10821                    forEachChild(child, visit);
10822
10823                    // Once we look at the children of this node, then there's no need to
10824                    // continue any further.
10825                    return true;
10826                }
10827                else {
10828                    Debug.assert(child.end <= position);
10829                    // The child ends entirely before this position.  Say you have the following
10830                    // (where $ is the position)
10831                    //
10832                    //      <complex expr 1> ? <complex expr 2> $ : <...> <...>
10833                    //
10834                    // We would want to find the nearest preceding node in "complex expr 2".
10835                    // To support that, we keep track of this node, and once we're done searching
10836                    // for a best node, we recurse down this node to see if we can find a good
10837                    // result in it.
10838                    //
10839                    // This approach allows us to quickly skip over nodes that are entirely
10840                    // before the position, while still allowing us to find any nodes in the
10841                    // last one that might be what we want.
10842                    lastNodeEntirelyBeforePosition = child;
10843                }
10844            }
10845            else {
10846                Debug.assert(child.pos > position);
10847                // We're now at a node that is entirely past the position we're searching for.
10848                // This node (and all following nodes) could never contribute to the result,
10849                // so just skip them by returning 'true' here.
10850                return true;
10851            }
10852        }
10853    }
10854
10855    function checkChangeRange(sourceFile: SourceFile, newText: string, textChangeRange: TextChangeRange, aggressiveChecks: boolean) {
10856        const oldText = sourceFile.text;
10857        if (textChangeRange) {
10858            Debug.assert((oldText.length - textChangeRange.span.length + textChangeRange.newLength) === newText.length);
10859
10860            if (aggressiveChecks || Debug.shouldAssert(AssertionLevel.VeryAggressive)) {
10861                const oldTextPrefix = oldText.substr(0, textChangeRange.span.start);
10862                const newTextPrefix = newText.substr(0, textChangeRange.span.start);
10863                Debug.assert(oldTextPrefix === newTextPrefix);
10864
10865                const oldTextSuffix = oldText.substring(textSpanEnd(textChangeRange.span), oldText.length);
10866                const newTextSuffix = newText.substring(textSpanEnd(textChangeRangeNewSpan(textChangeRange)), newText.length);
10867                Debug.assert(oldTextSuffix === newTextSuffix);
10868            }
10869        }
10870    }
10871
10872    interface IncrementalElement extends ReadonlyTextRange {
10873        readonly parent: Node;
10874        intersectsChange: boolean;
10875        length?: number;
10876        _children: Node[] | undefined;
10877    }
10878
10879    export interface IncrementalNode extends Node, IncrementalElement {
10880        hasBeenIncrementallyParsed: boolean;
10881    }
10882
10883    interface IncrementalNodeArray extends NodeArray<IncrementalNode>, IncrementalElement {
10884        length: number;
10885    }
10886
10887    // Allows finding nodes in the source file at a certain position in an efficient manner.
10888    // The implementation takes advantage of the calling pattern it knows the parser will
10889    // make in order to optimize finding nodes as quickly as possible.
10890    export interface SyntaxCursor {
10891        currentNode(position: number): IncrementalNode;
10892    }
10893
10894    export function createSyntaxCursor(sourceFile: SourceFile): SyntaxCursor {
10895        let currentArray: NodeArray<Node> = sourceFile.statements;
10896        let currentArrayIndex = 0;
10897
10898        Debug.assert(currentArrayIndex < currentArray.length);
10899        let current = currentArray[currentArrayIndex];
10900        let lastQueriedPosition = InvalidPosition.Value;
10901
10902        return {
10903            currentNode(position: number) {
10904                // Only compute the current node if the position is different than the last time
10905                // we were asked.  The parser commonly asks for the node at the same position
10906                // twice.  Once to know if can read an appropriate list element at a certain point,
10907                // and then to actually read and consume the node.
10908                if (position !== lastQueriedPosition) {
10909                    // Much of the time the parser will need the very next node in the array that
10910                    // we just returned a node from.So just simply check for that case and move
10911                    // forward in the array instead of searching for the node again.
10912                    if (current && current.end === position && currentArrayIndex < (currentArray.length - 1)) {
10913                        currentArrayIndex++;
10914                        current = currentArray[currentArrayIndex];
10915                    }
10916
10917                    // If we don't have a node, or the node we have isn't in the right position,
10918                    // then try to find a viable node at the position requested.
10919                    if (!current || current.pos !== position) {
10920                        findHighestListElementThatStartsAtPosition(position);
10921                    }
10922                }
10923
10924                // Cache this query so that we don't do any extra work if the parser calls back
10925                // into us.  Note: this is very common as the parser will make pairs of calls like
10926                // 'isListElement -> parseListElement'.  If we were unable to find a node when
10927                // called with 'isListElement', we don't want to redo the work when parseListElement
10928                // is called immediately after.
10929                lastQueriedPosition = position;
10930
10931                // Either we don'd have a node, or we have a node at the position being asked for.
10932                Debug.assert(!current || current.pos === position);
10933                return current as IncrementalNode;
10934            }
10935        };
10936
10937        // Finds the highest element in the tree we can find that starts at the provided position.
10938        // The element must be a direct child of some node list in the tree.  This way after we
10939        // return it, we can easily return its next sibling in the list.
10940        function findHighestListElementThatStartsAtPosition(position: number) {
10941            // Clear out any cached state about the last node we found.
10942            currentArray = undefined!;
10943            currentArrayIndex = InvalidPosition.Value;
10944            current = undefined!;
10945
10946            // Recurse into the source file to find the highest node at this position.
10947            forEachChild(sourceFile, visitNode, visitArray);
10948            return;
10949
10950            function visitNode(node: Node) {
10951                if (position >= node.pos && position < node.end) {
10952                    // Position was within this node.  Keep searching deeper to find the node.
10953                    forEachChild(node, visitNode, visitArray);
10954
10955                    // don't proceed any further in the search.
10956                    return true;
10957                }
10958
10959                // position wasn't in this node, have to keep searching.
10960                return false;
10961            }
10962
10963            function visitArray(array: NodeArray<Node>) {
10964                if (position >= array.pos && position < array.end) {
10965                    // position was in this array.  Search through this array to see if we find a
10966                    // viable element.
10967                    for (let i = 0; i < array.length; i++) {
10968                        const child = array[i];
10969                        if (child) {
10970                            if (child.pos === position) {
10971                                // Found the right node.  We're done.
10972                                currentArray = array;
10973                                currentArrayIndex = i;
10974                                current = child;
10975                                return true;
10976                            }
10977                            else {
10978                                if (child.pos < position && position < child.end) {
10979                                    // Position in somewhere within this child.  Search in it and
10980                                    // stop searching in this array.
10981                                    forEachChild(child, visitNode, visitArray);
10982                                    return true;
10983                                }
10984                            }
10985                        }
10986                    }
10987                }
10988
10989                // position wasn't in this array, have to keep searching.
10990                return false;
10991            }
10992        }
10993    }
10994
10995    const enum InvalidPosition {
10996        Value = -1
10997    }
10998}
10999
11000/** @internal */
11001export function isDeclarationFileName(fileName: string): boolean {
11002    return fileExtensionIsOneOf(fileName, supportedDeclarationExtensions);
11003}
11004
11005/** @internal */
11006export interface PragmaContext {
11007    languageVersion: ScriptTarget;
11008    pragmas?: PragmaMap;
11009    checkJsDirective?: CheckJsDirective;
11010    referencedFiles: FileReference[];
11011    typeReferenceDirectives: FileReference[];
11012    libReferenceDirectives: FileReference[];
11013    amdDependencies: AmdDependency[];
11014    hasNoDefaultLib?: boolean;
11015    moduleName?: string;
11016}
11017
11018function parseResolutionMode(mode: string | undefined, pos: number, end: number, reportDiagnostic: PragmaDiagnosticReporter): ModuleKind.ESNext | ModuleKind.CommonJS | undefined {
11019    if (!mode) {
11020        return undefined;
11021    }
11022    if (mode === "import") {
11023        return ModuleKind.ESNext;
11024    }
11025    if (mode === "require") {
11026        return ModuleKind.CommonJS;
11027    }
11028    reportDiagnostic(pos, end - pos, Diagnostics.resolution_mode_should_be_either_require_or_import);
11029    return undefined;
11030}
11031
11032/** @internal */
11033export function processCommentPragmas(context: PragmaContext, sourceText: string): void {
11034    const pragmas: PragmaPseudoMapEntry[] = [];
11035
11036    for (const range of getLeadingCommentRanges(sourceText, 0) || emptyArray) {
11037        const comment = sourceText.substring(range.pos, range.end);
11038        extractPragmas(pragmas, range, comment);
11039    }
11040
11041    context.pragmas = new Map() as PragmaMap;
11042    for (const pragma of pragmas) {
11043        if (context.pragmas.has(pragma.name)) {
11044            const currentValue = context.pragmas.get(pragma.name);
11045            if (currentValue instanceof Array) {
11046                currentValue.push(pragma.args);
11047            }
11048            else {
11049                context.pragmas.set(pragma.name, [currentValue, pragma.args]);
11050            }
11051            continue;
11052        }
11053        context.pragmas.set(pragma.name, pragma.args);
11054    }
11055}
11056
11057/** @internal */
11058export type PragmaDiagnosticReporter = (pos: number, length: number, message: DiagnosticMessage) => void;
11059
11060/** @internal */
11061export function processPragmasIntoFields(context: PragmaContext, reportDiagnostic: PragmaDiagnosticReporter): void {
11062    context.checkJsDirective = undefined;
11063    context.referencedFiles = [];
11064    context.typeReferenceDirectives = [];
11065    context.libReferenceDirectives = [];
11066    context.amdDependencies = [];
11067    context.hasNoDefaultLib = false;
11068    context.pragmas!.forEach((entryOrList, key) => { // TODO: GH#18217
11069        // TODO: The below should be strongly type-guarded and not need casts/explicit annotations, since entryOrList is related to
11070        // key and key is constrained to a union; but it's not (see GH#21483 for at least partial fix) :(
11071        switch (key) {
11072            case "reference": {
11073                const referencedFiles = context.referencedFiles;
11074                const typeReferenceDirectives = context.typeReferenceDirectives;
11075                const libReferenceDirectives = context.libReferenceDirectives;
11076                forEach(toArray(entryOrList) as PragmaPseudoMap["reference"][], arg => {
11077                    const { types, lib, path, ["resolution-mode"]: res } = arg.arguments;
11078                    if (arg.arguments["no-default-lib"]) {
11079                        context.hasNoDefaultLib = true;
11080                    }
11081                    else if (types) {
11082                        const parsed = parseResolutionMode(res, types.pos, types.end, reportDiagnostic);
11083                        typeReferenceDirectives.push({ pos: types.pos, end: types.end, fileName: types.value, ...(parsed ? { resolutionMode: parsed } : {}) });
11084                    }
11085                    else if (lib) {
11086                        libReferenceDirectives.push({ pos: lib.pos, end: lib.end, fileName: lib.value });
11087                    }
11088                    else if (path) {
11089                        referencedFiles.push({ pos: path.pos, end: path.end, fileName: path.value });
11090                    }
11091                    else {
11092                        reportDiagnostic(arg.range.pos, arg.range.end - arg.range.pos, Diagnostics.Invalid_reference_directive_syntax);
11093                    }
11094                });
11095                break;
11096            }
11097            case "amd-dependency": {
11098                context.amdDependencies = map(
11099                    toArray(entryOrList) as PragmaPseudoMap["amd-dependency"][],
11100                    x => ({ name: x.arguments.name, path: x.arguments.path }));
11101                break;
11102            }
11103            case "amd-module": {
11104                if (entryOrList instanceof Array) {
11105                    for (const entry of entryOrList) {
11106                        if (context.moduleName) {
11107                            // TODO: It's probably fine to issue this diagnostic on all instances of the pragma
11108                            reportDiagnostic(entry.range.pos, entry.range.end - entry.range.pos, Diagnostics.An_AMD_module_cannot_have_multiple_name_assignments);
11109                        }
11110                        context.moduleName = (entry as PragmaPseudoMap["amd-module"]).arguments.name;
11111                    }
11112                }
11113                else {
11114                    context.moduleName = (entryOrList as PragmaPseudoMap["amd-module"]).arguments.name;
11115                }
11116                break;
11117            }
11118            case "ts-nocheck":
11119            case "ts-check": {
11120                // _last_ of either nocheck or check in a file is the "winner"
11121                forEach(toArray(entryOrList), entry => {
11122                    if (!context.checkJsDirective || entry.range.pos > context.checkJsDirective.pos) {
11123                        context.checkJsDirective = {
11124                            enabled: key === "ts-check",
11125                            end: entry.range.end,
11126                            pos: entry.range.pos
11127                        };
11128                    }
11129                });
11130                break;
11131            }
11132            case "jsx":
11133            case "jsxfrag":
11134            case "jsximportsource":
11135            case "jsxruntime":
11136                return; // Accessed directly
11137            default: Debug.fail("Unhandled pragma kind"); // Can this be made into an assertNever in the future?
11138        }
11139    });
11140}
11141
11142const namedArgRegExCache = new Map<string, RegExp>();
11143function getNamedArgRegEx(name: string): RegExp {
11144    if (namedArgRegExCache.has(name)) {
11145        return namedArgRegExCache.get(name)!;
11146    }
11147    const result = new RegExp(`(\\s${name}\\s*=\\s*)(?:(?:'([^']*)')|(?:"([^"]*)"))`, "im");
11148    namedArgRegExCache.set(name, result);
11149    return result;
11150}
11151
11152const tripleSlashXMLCommentStartRegEx = /^\/\/\/\s*<(\S+)\s.*?\/>/im;
11153const singleLinePragmaRegEx = /^\/\/\/?\s*@(\S+)\s*(.*)\s*$/im;
11154function extractPragmas(pragmas: PragmaPseudoMapEntry[], range: CommentRange, text: string) {
11155    const tripleSlash = range.kind === SyntaxKind.SingleLineCommentTrivia && tripleSlashXMLCommentStartRegEx.exec(text);
11156    if (tripleSlash) {
11157        const name = tripleSlash[1].toLowerCase() as keyof PragmaPseudoMap; // Technically unsafe cast, but we do it so the below check to make it safe typechecks
11158        const pragma = commentPragmas[name] as PragmaDefinition;
11159        if (!pragma || !(pragma.kind! & PragmaKindFlags.TripleSlashXML)) {
11160            return;
11161        }
11162        if (pragma.args) {
11163            const argument: {[index: string]: string | {value: string, pos: number, end: number}} = {};
11164            for (const arg of pragma.args) {
11165                const matcher = getNamedArgRegEx(arg.name);
11166                const matchResult = matcher.exec(text);
11167                if (!matchResult && !arg.optional) {
11168                    return; // Missing required argument, don't parse
11169                }
11170                else if (matchResult) {
11171                    const value = matchResult[2] || matchResult[3];
11172                    if (arg.captureSpan) {
11173                        const startPos = range.pos + matchResult.index + matchResult[1].length + 1;
11174                        argument[arg.name] = {
11175                            value,
11176                            pos: startPos,
11177                            end: startPos + value.length
11178                        };
11179                    }
11180                    else {
11181                        argument[arg.name] = value;
11182                    }
11183                }
11184            }
11185            pragmas.push({ name, args: { arguments: argument, range } } as PragmaPseudoMapEntry);
11186        }
11187        else {
11188            pragmas.push({ name, args: { arguments: {}, range } } as PragmaPseudoMapEntry);
11189        }
11190        return;
11191    }
11192
11193    const singleLine = range.kind === SyntaxKind.SingleLineCommentTrivia && singleLinePragmaRegEx.exec(text);
11194    if (singleLine) {
11195        return addPragmaForMatch(pragmas, range, PragmaKindFlags.SingleLine, singleLine);
11196    }
11197
11198    if (range.kind === SyntaxKind.MultiLineCommentTrivia) {
11199        const multiLinePragmaRegEx = /@(\S+)(\s+.*)?$/gim; // Defined inline since it uses the "g" flag, which keeps a persistent index (for iterating)
11200        let multiLineMatch: RegExpExecArray | null;
11201        while (multiLineMatch = multiLinePragmaRegEx.exec(text)) {
11202            addPragmaForMatch(pragmas, range, PragmaKindFlags.MultiLine, multiLineMatch);
11203        }
11204    }
11205}
11206
11207function addPragmaForMatch(pragmas: PragmaPseudoMapEntry[], range: CommentRange, kind: PragmaKindFlags, match: RegExpExecArray) {
11208    if (!match) return;
11209    const name = match[1].toLowerCase() as keyof PragmaPseudoMap; // Technically unsafe cast, but we do it so they below check to make it safe typechecks
11210    const pragma = commentPragmas[name] as PragmaDefinition;
11211    if (!pragma || !(pragma.kind! & kind)) {
11212        return;
11213    }
11214    const args = match[2]; // Split on spaces and match up positionally with definition
11215    const argument = getNamedPragmaArguments(pragma, args);
11216    if (argument === "fail") return; // Missing required argument, fail to parse it
11217    pragmas.push({ name, args: { arguments: argument, range } } as PragmaPseudoMapEntry);
11218    return;
11219}
11220
11221function getNamedPragmaArguments(pragma: PragmaDefinition, text: string | undefined): {[index: string]: string} | "fail" {
11222    if (!text) return {};
11223    if (!pragma.args) return {};
11224    const args = trimString(text).split(/\s+/);
11225    const argMap: {[index: string]: string} = {};
11226    for (let i = 0; i < pragma.args.length; i++) {
11227        const argument = pragma.args[i];
11228        if (!args[i] && !argument.optional) {
11229            return "fail";
11230        }
11231        if (argument.captureSpan) {
11232            return Debug.fail("Capture spans not yet implemented for non-xml pragmas");
11233        }
11234        argMap[argument.name] = args[i];
11235    }
11236    return argMap;
11237}
11238
11239/** @internal */
11240export function tagNamesAreEquivalent(lhs: JsxTagNameExpression, rhs: JsxTagNameExpression): boolean {
11241    if (lhs.kind !== rhs.kind) {
11242        return false;
11243    }
11244
11245    if (lhs.kind === SyntaxKind.Identifier) {
11246        return lhs.escapedText === (rhs as Identifier).escapedText;
11247    }
11248
11249    if (lhs.kind === SyntaxKind.ThisKeyword) {
11250        return true;
11251    }
11252
11253    // If we are at this statement then we must have PropertyAccessExpression and because tag name in Jsx element can only
11254    // take forms of JsxTagNameExpression which includes an identifier, "this" expression, or another propertyAccessExpression
11255    // it is safe to case the expression property as such. See parseJsxElementName for how we parse tag name in Jsx element
11256    return (lhs as PropertyAccessExpression).name.escapedText === (rhs as PropertyAccessExpression).name.escapedText &&
11257        tagNamesAreEquivalent((lhs as PropertyAccessExpression).expression as JsxTagNameExpression, (rhs as PropertyAccessExpression).expression as JsxTagNameExpression);
11258}
11259